2012-03-09 7 views
1

SetupDiGetDeviceInterfaceDetail()hereを呼び出していて、SP_DEVICE_INTERFACE_DETAIL_DATA構造体が正しくマーシャリングしていません。構造体の定義はhereです。私はPInvoke.net、hereからこの構造の定義を使用しようとしましたが、役に立たないです。32ビットおよび64ビットランタイムの動的構造を整理する

これまでは、関数の呼び出しが成功したとき(つまり、マーシャラがエラーをスローしない)、戻り値は1784(INVALID_USER_BUFFER)です。キッカーは、このコードが私のボックス上の32ビットプロセスから実行されるときに、このすべてがうまくいきます。 64ビットプロセスで実行すると、この問題が発生します。

私の現在のSetupDiGetInterfaceDetailData()署名は次のようになります。

[DllImport(@"c:\Windows\System32\SetupApi.dll", SetLastError = true, CharSet = CharSet.Auto)] 
[return : MarshalAs(UnmanagedType.Bool)] 
public static extern bool SetupDiGetDeviceInterfaceDetail(
    SafeHandleZeroOrMinusOneIsInvalid deviceInfoSet, 
    ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, 
    IntPtr deviceInterfaceDetailData, 
    uint deviceInterfaceDetailDataSize, 
    IntPtr requiredSize, 
    IntPtr deviceInfoData); 

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
public struct SP_DEVICE_INTERFACE_DETAIL_DATA 
{ 
    public UInt32 cbSize; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] 
    public string DevicePath; 
} 

現在、私は(Marshal.AllocHGlobalでメモリを割り当てる)と元帥を使用して、そのバッファからの書き込み/読み出しデータ午前関数の*家族。

public string GetPathToDevice(SafeHandleZeroOrMinusOneIsInvalid hDevList, 
           SP_DEVICE_INTERFACE_DATA devIntfData) 
{ 
    uint sizeNeeded = 0; 
    // get's the size needed 
    SetupApi.SetupDiGetDeviceInterfaceDetailData(hDevList, 
               ref devIntfData, 
               IntPtr.Zero, 
               0, 
               ref sizeNeeded, 
               IntPtr.Zero); 

    IntPtr pBuffer = Marshal.AllocHGlobal((int)(sizeNeeded + 4)); // +4 for cbSize 
    SetupApi.SetupDiGetDeviceInterfaceDetailData(hDevList, 
               ref devIntfData, 
               pBuffer, 
               sizeNeeded, 
               IntPtr.Zero, 
               IntPtr.Zero); 

    // copy bytes from unmanaged space in pBuffer to a manged byte array 
    // free unmanaged memory 

    return theStringParsedFromByteArray; 
} 

を私が述べたように、私はSP_DEVICE_INTERFACE_DETAIL_DATAためPInvoke.netによって概説されているような構造を定義しようとした(リンク上記参照)と新しいを作りました:参考までに、これは私がやっている

ですそれを処理するPInvokeメソッドのシグネチャ。 64ビットシステムから実行すると、同じ問題が発生します。つまり、関数は1784を返します。その理由は、C#での参照が64ビットのランタイムで実行されている場合、8バイトで整列されているStackOverflow記事)。私はその構造体にレイアウトを(明示的とフィールドオフセットを使用して)強制的に4バイト整列構造体にしようと試みましたが、それも私のためには機能しませんでした。コンパイル時に問題がありました。

私はPInvokeメソッドのシグネチャパラメータにさまざまなデコレーションを使用しようとしました。 MarshalAs(UnmanagedType.LPStruct)のように、私は不当に続けてペアリングを続けています。私は今、私がこの点で助けが必要であるという点までいます。

私が実際に理解していないことは、なぜそれが全く起こっているのかということです。 32ビットのランタイムで動作するときに私のボックスで動作しても、64ビットのランタイムはセットアップAPIの正しい64ビットバージョンに接続するだけではありませんか?どうしたの?任意の助け

おかげで、

問題は、良いことは、それが今解かれますされ、刺激性のものは、私は1時間か2時間の範囲内のものを固定好きではないです

を解決している アンディここに投稿してください。だから問題は確かに64ビット問題だった。 Marshal.GetLastWin32Error()のエラーコードが問題を伝えていました。 cbSize値が正しくありませんでした。私はそれを8に変更しました。

64ビットのサイズが8になった理由を教えてください。構造は今以上です(投稿者は私にそれを含めるように頼んだ)。構造体は、1つのDWORDとTCHAR [ANYSIZE_ARRAY]という2つのメンバで構成されています。 ANYSIZE_ARRAYは1と評価され、TCHARはUnicodeの場合は常にWCHAR、それ以外の場合はcharです。 DWORDは常に32ビット(4バイト)で、ユニコード用のTCHARは2バイトです。したがって、4 + 2 = 6.なぜ8ですか?これは、64ビットでその構造のバイトアライメントのためですか?私は本当にこれを理解したいと思います。

いずれにしても、cbSizeメンバーを64ビットで8、そして32ビットで6に設定すると、私は割り当てられていないメモリの割り当て/割り当て解除とマーシャリングの代わりに上記で定義した構造体を使用できます。

+0

C#で定義した構造体を投稿する構造体のサイズを明確に定義する必要があります。 –

+0

@Ramhound現在のところ、この構造は、私が個別に書いている生のメモリです。私がPInvokeから定義した構造は、私が投稿したリンクです。私はそこにそれを示すために編集する。 –

+0

'c:\ Windows \ System32 \ SetupApi.dll'をあなたのDLL名にするのは悪い考えです。そのパスをハードコーディングするのは危険です。ちょうど 'setupapi.dll'を使用してください。 –

答えて

0

この回答のコードをコピーしたので、私もこの問題を解決しました。https://stackoverflow.com/a/2937588/1070906 これは構造体定義にエラーがあります。 多分あなたは同じ間違いをしました。

http://msdn.microsoft.com/en-us/library/windows/hardware/ff552344(v=vs.85).aspxのSP_DEVINFO_DATAの定義を見ると、最後のパラメータはポインタであり、他のポストと同じではありません。

[StructLayout(LayoutKind.Sequential)] 
private struct SP_DEVINFO_DATA 
{ 
    /// <summary>Size of the structure, in bytes.</summary> 
    public uint cbSize; 
    /// <summary>GUID of the device interface class.</summary> 
    public Guid ClassGuid; 
    /// <summary>Handle to this device instance.</summary> 
    public uint DevInst; 
    /// <summary>Reserved; do not use.</summary> 
    public IntPtr Reserved; 
} 
それが動作

:私は構造体の定義を変更したので

Marshall.SizeOf(new SP_DEVINFO_DATA())は、28ではなく32を返し、シリアルポートが表示されます。

+0

私の問題は、SP_DEVINFO_DATAの定義ではなく、SP_DEVICE_INTERFACE_DETAIL_DATAです。ソリューションはDavid Heffernanの提案を使用し、AllocHGlobalを使用して必要なメモリを割り当てるだけで、手間をかけずに済むと思います。 –

関連する問題