2012-02-12 9 views
2

USB GPSデバイスに接続しようとしています。 CreateFile WinApi(デバイスマネージャで指定されたパスを使用)経由で手動でファイルを作成すると、デバイスに正常に接続できます。Win32Api USB SetupDiGetDeviceInterfaceDetailが失敗する

ただし、列挙を使用してデバイスを選択しようとすると、SetupDiGetDeviceInterfaceDetailコールに失敗します。

私は正しく動作するCコードを持っていますが、C#変換は正しく動作するようには見えません。私は本質的に同じ結果で多くのバリエーションを試しました。


// Get enumerator handle for the specified ClassGuid 
HDEVINFO theDevInfo = SetupDiGetClassDevs((GUID*)&GUID_DEVINTERFACE_GRMNUSB, NULL, NULL, 
    DIGCF_PRESENT | DIGCF_INTERFACEDEVICE); 

SP_DEVICE_INTERFACE_DATA theInterfaceData; 
theInterfaceData.cbSize = sizeof(theInterfaceData); 

// populate theInterfaceData which contains device class information 
if (!SetupDiEnumDeviceInterfaces(theDevInfo, NULL, (GUID*)&GUID_DEVINTERFACE_GRMNUSB, 0, &theInterfaceData) && 
    GetLastError() == ERROR_NO_MORE_ITEMS) 
{ 
    gHandle = 0; 
    return; 
} 
// This is normally used to obtain the device path information using theInterfaceData obtained above 
bool initialized = SetupDiGetDeviceInterfaceDetail(theDevInfo, &theInterfaceData, NULL, 0, &theBytesReturned, NULL); 
// theBytesReturned = 83 
theDevDetailData = 
(PSP_INTERFACE_DEVICE_DETAIL_DATA)malloc(theBytesReturned); 
theDevDetailData->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA); 

bool initialized = SetupDiGetDeviceInterfaceDetail(theDevInfo, &theInterfaceData, theDevDetailData, theBytesReturned, NULL, &theDevInfoData); 
を作品

CコードはC#

[DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] 
public static extern Boolean SetupDiGetDeviceInterfaceDetail(
    IntPtr hDevInfo, 
    ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, 
    IntPtr deviceInterfaceDetailData, 
    UInt32 deviceInterfaceDetailDataSize, 
    out UInt32 requiredSize, 
    IntPtr deviceInfoData 
    ); 

[StructLayout(LayoutKind.Sequential)] 
public struct SP_DEVICE_INTERFACE_DATA 
{ 
    public Int32 cbSize; 
    public Guid interfaceClassGuid; 
    public Int32 flags; 
    private UIntPtr reserved; 
} 


// Get enumerator handle for the specified ClassGuid 
IntPtr theDevInfo = SetupDiGetClassDevs(ref ClassGuid, (DiGetClassFlags.DIGCF_PRESENT | DiGetClassFlags.DIGCF_DEVICEINTERFACE)); 

SP_DEVICE_INTERFACE_DATA DevInterfaceData = new SP_DEVICE_INTERFACE_DATA(); 
DevInterfaceData.cbSize = Marshal.SizeOf(DevInterfaceData); 

initialized = SetupDiEnumDeviceInterfaces(theDevInfo, IntPtr.Zero, ref ClassGuid, 0, 
     ref DevInterfaceData); 
// I assume The DevInterfaceData is populated correctly as it matches the C Code 
// And I've compared the values in memory and they match 

uint bytesReturned = 0; 
initialized = SetupDiGetDeviceInterfaceDetail(theDevInfo, ref DevInterfaceData, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero); 
// I expect bytesReturned = 83 and initialized = true which is the value that is returned in the C Code 
// Instead the value 162 is returned 

答えて

2

私は問題を発見したと信じています。

pinvoke.netチャンスをうかがった後、私は私のコードでこれを変更し、次の

// build a Device Interface Detail Data structure 
SP_DEVICE_INTERFACE_DETAIL_DATA didd = new SP_DEVICE_INTERFACE_DETAIL_DATA(); 
if (IntPtr.Size == 8) // for 64 bit operating systems 
    didd.cbSize = 8; 
else didd.cbSize = 4 + Marshal.SystemDefaultCharSize; // for 32 bit systems 

を見つけた私は適切にDevicePathのを得ることができます。

参考になりました。

http://pinvoke.net/default.aspx/setupapi.SetupDiGetDeviceInterfaceDetail

+1

いいえ、スタックを破壊します。 Marshal.AllocHGlobal()を使用して、必要なサイズのバッファを割り当てます。あなたが最初の呼び出しから得たサイズ。 –

+0

なぜスタックは壊れていますか? Win32api呼び出しを行うと適切なメモリがマーシャリングされないでしょうか? – galford13x

+0

@ HansPassant 'IntPtr.Size'のテストがなぜ必要なのか説明できます.Marshalerを使って' SizeOf(SP_DEVICE_INTERFACE_DETAIL_DATA) 'を得ることはできません。私はそれが何とかパッディングと関係があると思いますか? –

4

おめでとうございます。あなたはUnicode文字列を取得します。これは2倍の長さです。そして、偽の戻り値は正しいです。 Marshal.GetLastWin32Error()を呼び出し、ERROR_INSUFFICIENT_BUFFERを取得していることを確認するだけです。あなたのCコードが壊れているのはおそらく、あなたがBytesReturnedを0に初期化するのを忘れたからです。

+0

Cコードは正しく動作します。 C#コードは正しく動作しませんでした。 theBytesReturnedは0に初期化されています。スペースを節約するために関数全体を入れなかったので、上記のコードには表示されません。私は、CコードがASCIIであるために83バイトを返したと思いますが、C#コードがUNICODE文字列を期待していた場合、それはなぜ162であり、83x2 = 166ではありませんか? – galford13x

+0

私は知らない、文字列を投稿して、理由を教えてあげます。実際にはCコードに問題があり、関数はFALSEを返し、GetLastError()はERROR_INSUFFICIENT_BUFFERを返さなければなりません。次に、必要なバッファー・サイズを知り、それを割り振り、関数を再度呼び出します。 –

+0

ああ、私は同意する、最初の呼び出しがfalseを返す、私は明らかに実際にdeviceDetailDataを読み込んでいない2番目の呼び出しがあります。私は正しいように投稿を編集します。 @ "\\?\ usb#vid_091e&pid_0003#5&4a03a84&0&5#{2c9c45c2-8e7d-4c08-a12d-816bbae722c0}"という文字列があります – galford13x

関連する問題