1

kernel32.dllからこの関数(GetPackageId)をPInvokeしようとしています:http://msdn.microsoft.com/en-us/library/windows/desktop/hh446607(v = vs.85) .aspx

構造体とインポートを次のように定義しました。

    [StructLayout(LayoutKind.Sequential)]
    public struct PACKAGE_ID
    {
        uint reserved;
        uint processorArchitecture;
        PACKAGE_VERSION version;
        String name;
        String publisher;
        String resourceId;
        String publisherId;
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct PACKAGE_VERSION
    {
        [FieldOffset(0)] public UInt64 Version;
        [FieldOffset(0)] public ushort Revision;
        [FieldOffset(2)] public ushort Build;
        [FieldOffset(4)] public ushort Minor;
        [FieldOffset(6)] public ushort Major;
    }  

    [DllImport("kernel32.dll", EntryPoint = "GetPackageId", SetLastError = true)]
    static extern int GetPackageId(IntPtr hProcess,out uint bufferLength,out PACKAGE_ID pBuffer);

そしてそれをこのように呼びます:

    PACKAGE_ID buffer = new PACKAGE_ID();
    result = GetPackageId(hProcess, out bufferLength, out buffer); 

ただし、戻り値は122(ERROR_INSUFFICIENT_BUFFER)になります。私はPInvokeにかなり慣れていないので、ここから先に進む方法がよくわかりません。関数を呼び出す前に文字列を初期化する必要がありますか?

4

2 に答える 2

3

p/invokeを変更する必要があります。

[DllImport("kernel32.dll", SetLastError=true)]
static extern int GetPackageId(
    IntPtr hProcess,
    ref int bufferLength,
    IntPtr pBuffer
);

あなたはそれを一度長さを渡すと呼びます0

int len = 0;
int retval = GetPackageId(hProcess, ref len, IntPtr.Zero);

retval次に、に等しいことを確認する必要がありますERROR_INSUFFICIENT_BUFFER。そうでない場合は、エラーが発生します。

if (retval != ERROR_INSUFFICIENT_BUFFER)
    throw new Win32Exception();

それ以外の場合は続行できます。

IntPtr buffer = Marshal.AllocHGlobal(len);
retval = GetPackageId(hProcess, ref len, buffer);

retvalこれで、に対してチェックできますERROR_SUCCESS

if (retval != ERROR_SUCCESS)
    throw new Win32Exception();

そして最後に、バッファをに変換できPACKAGE_IDます。

PACKAGE_ID packageID = (PACKAGE_ID)Marshal.PtrToStructure(buffer, 
    typeof(PACKAGE_ID));

すべてをまとめると、次のようになります。

int len = 0;
int retval = GetPackageId(hProcess, ref len, IntPtr.Zero);
if (retval != ERROR_INSUFFICIENT_BUFFER)
    throw new Win32Exception();
IntPtr buffer = Marshal.AllocHGlobal((int)len);
try
{
    retval = GetPackageId(hProcess, ref len, buffer);
    if (retval != ERROR_SUCCESS)
        throw new Win32Exception();
    PACKAGE_ID packageID = (PACKAGE_ID)Marshal.PtrToStructure(buffer,
        typeof(PACKAGE_ID));
}
finally
{
    Marshal.FreeHGlobal(buffer);
}

PACKAGE_IDコメントから、構造体のマーシャリング方法も変更する必要があるようです。

私は次のことを提案します:

[StructLayout(LayoutKind.Sequential)]
public struct PACKAGE_ID
{
    uint reserved;
    uint processorArchitecture;
    PACKAGE_VERSION version;
    IntPtr name;
    IntPtr publisher;
    IntPtr resourceId;
    IntPtr publisherId;
}

続いて、を呼び出して文字列フィールドをC#文字列Marshal.PtrToStringUniに変換します。IntPtr当然、この変換は、を呼び出す前に行う必要がありますFreeHGlobal

私の推測では、APIは実際にはの終わりを超えたスペースに文字列バッファを割り当てますPACKAGE_ID。そのため、割り当てるメモリの量を尋ねる必要があります。この仮説をテストするためのWindows8は手元にありません。

于 2013-01-15T12:48:06.917 に答える
0

GetPackageIdのドキュメントから、呼び出すときに引数としてバッファのサイズを送信する必要があるようです。つまり、bufferLengthは渡されたバッファのサイズで初期化する必要があります。

返されると、bufferLengthは返されたバッファのサイズを教えてくれます。

または、ドキュメントを読み間違えましたか?

于 2013-01-15T09:05:19.513 に答える