2011-02-25 87 views
2

我想從C#應用程序調用SetupDiGetDriverInfoDetail。調用失敗,我得到的win32錯誤是0x6F8(「提供的用戶緩衝區對於請求的操作無效」)。到目前爲止,我已經能夠成功地調用其他setupdi函數,所以我認爲問題在於我編組函數或SP_DRVINFO_DETAIL_DATA結構的方式。PInvoke與SetupDiGetDriverInfoDetail

我不確定,但我認爲問題可能與SP_DRVINFO_DETAIL_DATA結構的HardwareID成員有關。我試過將HardwareID指定爲不同的類型(例如一個字節數組,並在設置大小和調用函數之前分配緩衝區),但總是出現相同的錯誤。如果任何人有任何這個電話的經驗或任何指針,我將不勝感激的幫助。

下面是我的結構定義,函數導入和代碼片斷。在這個版本中,我使用了一個固定大小的HardwareID緩衝區。我也試過指定緩衝區大小爲1,期望「緩衝區太小」的錯誤,但我總是得到「無效緩衝區」錯誤。

[DllImport("setupapi.dll", SetLastError = true)] 
    internal static extern Int32 SetupDiGetDriverInfoDetail(
     IntPtr DeviceInfoSet, 
     SP_DEVINFO_DATA DeviceInfoData, 
     SP_DRVINFO_DATA DriverInfoData, 
     ref SP_DRVINFO_DETAIL_DATA DriverInfoDetailData, 
     Int32 DriverInfoDetailDataSize, 
     ref Int32 RequiredSize); 


    [StructLayout(LayoutKind.Sequential, Pack = 1)] 
    internal struct SP_DRVINFO_DETAIL_DATA 
    { 
     public Int32 cbSize; 
     public System.Runtime.InteropServices.ComTypes.FILETIME InfDate; 
     public Int32 CompatIDsOffset; 
     public Int32 CompatIDsLength; 
     public IntPtr Reserved; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] 
     public String SectionName; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] 
     public String InfFileName; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] 
     public String DrvDescription; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] 
     public String HardwareID; 
    }; 

SetupApiWrapper.SP_DRVINFO_DETAIL_DATA DriverInfoDetailData = new SetupApiWrapper.SP_DRVINFO_DETAIL_DATA(); 
DriverInfoDetailData.cbSize = Marshal.SizeOf(DriverInfoDetailData); 

result = SetupApiWrapper.SetupDiGetDriverInfoDetail(
          DevInfo, 
          DeviceInfoData, 
          DriverInfoData, 
          ref DriverInfoDetailData, 
          DriverInfoDetailData.cbSize, 
          ref reqSize); 

回答

1

oAlthough我同意錯誤代碼看起來出乎意料,我認爲這個問題是CBSIZE應設置爲sizeof(SP_DRVINFO_DETAIL_DATA)(這是恰當的C的sizeof,而不是Marshal.SizeOf您的P/Invoke結構。 )

快速測試用兩行的C程序給出了:

ANSI 797 
UNICODE 1570 

對於兩個合適的sizeof值(你需要找出你需要自己哪一個......)

與此相反,Marshal.SizeOf(typeof(SP_DRVINFO_DETAIL_DATA))爲您的結構提供了1048作爲長度。

我認爲你需要在你進一步探討之前排隊。

我懷疑,如果DriverInfoDetailDataSize太小,可能會返回buffer-too-small錯誤,但如果cbSize錯誤,則返回invalid-buffer錯誤。

SetupDiGetDriverInfoDetail的幫助也是顯式的,cbSize和DriverInfoDetailDataSize不應該是相同的值(因爲ANYSIZE_ARRAY只是定義爲1作爲佔位符),所以您不應該期望獲得Marshal.SizeOf以正常工作你故意超大的結構。

附加校正:

你InfFilename構件也是錯誤的長度 - 一個其完全從結構匹配SETUPAPI.H結構是:

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet=CharSet.Unicode)] 
    internal struct SP_DRVINFO_DETAIL_DATA 
    { 
     public Int32 cbSize; 
     public System.Runtime.InteropServices.ComTypes.FILETIME InfDate; 
     public Int32 CompatIDsOffset; 
     public Int32 CompatIDsLength; 
     public IntPtr Reserved; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] 
     public String SectionName; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 
     public String InfFileName; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] 
     public String DrvDescription; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)] 
     public String HardwareID; 
    }; 

這給出了正確的長度,無論是在ANSI和UNICODE版本。但是,您不想這樣使用,因爲您需要HardwareID的時間更長,所以您必須調整其長度,然後使用Marshal.SizeOf提供的錯誤值直接插入cbSize。

1

函數聲明錯誤,第二個和第三個參數通過ref傳遞。解釋「無效緩衝區」,API需要一個指針。小心Pack,它在32位操作系統上只有1個。確保將平臺目標設置爲x86。你應該首先測量所需的結構尺寸。狡猾的做,使HardwareID好大,不要節儉,並把它扔在16K。

+0

SetupAPI的結構在32位構建中是1個字節打包,而在64位構建中是8個字節打包。這種結構的ANSI版本的標準尺寸是奇數個字節,這對於「默認打包」的進行情況是一個很好的想法。但你是對的,其他兩個參數應該是ref。 – 2011-02-25 19:25:23

+0

你是對的,修好了。 – 2011-02-25 19:36:48

+0

Win32的32/64位版本的此對齊變體是否適用於整個API的整個表面區域? – 2011-02-25 20:31:52