對於我的問題,我非常接近解決方案,但我需要一些關於最終結果的指導以使所有工作都成功。在過去的一週中,我學到了很多關於數組結構和IntPtr數組元素
作爲一個參考,上週我提了一個類似的問題關於同一個話題,但由於我身邊的巨大監督,我提出了錯誤的問題。
我想使用一個非託管的C++ dll,這是與連接的設備通信的API。我已經成功創建了包裝器,以及其他大部分函數調用,但是最後一個讓我瘋狂。
對於一些背景信息(可能不需要回答這個問題 - 並牢記我的基本思維過程當時有缺陷)是在這裏:Calling un-managed code with pointer (Updated)
在我原來的問題,我是問有關創建IntPtr到包含struct(2)的數組的結構(1)....實際上,struct(1)根本不包含數組,它包含指向數組的指針。
這裏是我想實現作爲參考API文檔:
extern 「C」 long WINAPI PassThruIoctl
(
unsigned long ChannelID,
unsigned long IoctlID,
void *pInput,
void *pOutput
)
// *pInput Points to the structure SCONFIG_LIST, which is defined as follows:
// *pOutput is not used in this function and is a null pointer
typedef struct
{
unsigned long NumOfParams; /* number of SCONFIG elements */
SCONFIG *ConfigPtr; /* array of SCONFIG */
} SCONFIG_LIST
// Where:
// NumOfParms is an INPUT, which contains the number of SCONFIG elements in the array pointed to by ConfigPtr.
// ConfigPtr is a pointer to an array of SCONFIG structures.
// The structure SCONFIG is defined as follows:
typedef struct
{
unsigned long Parameter; /* name of parameter */
unsigned long Value; /* value of the parameter */
} SCONFIG
這裏是我的結構定義,因爲我現在有他們定義
[StructLayout(LayoutKind.Sequential)] // Also tried with Pack=1
public struct SConfig
{
public UInt32 Parameter;
public UInt32 Value;
}
[StructLayout(LayoutKind.Sequential)] // Also tried with Pack=1
public struct SConfig_List
{
public UInt32 NumOfParams;
public IntPtr configPtr;
public SConfig_List(UInt32 nParams, SConfig[] config)
{
this.NumOfParams = nParams;
// I have tried these 2 lines together
IntPtr temp = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MyNameSpace.SConfig)) * (int)nParams);
this.configPtr = new IntPtr(temp.ToInt32());
// I have tried this by itself
// this.configPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MyNameSpace.SConfig)) * (int)nParams);
// and this line
// this.configPtr = Marshal.AllocHGlobal(sizeof(SConfig)*(int)nParams); // this only complies with unsafe struct
}
}
這裏的片段將其設置爲變量並調用與API接口的函數的代碼
SConfig[] arr_sconfig;
arr_sconfig = new SConfig[1];
arr_sconfig[0].Parameter = 0x04;
arr_sconfig[0].Value = 0xF1;
SConfig_List myConfig = new SConfig_List(1, arr_sconfig);
m_status = m_APIBox.SetConfig(m_channelId, ref myConfig);
最後,這裏是傳遞到DLL此信息的功能:
public APIErr SetConfig(int channelId, ref SConfig_List config)
{
unsafe
{
IntPtr output = IntPtr.Zero; // Output not used, just a null pointer for this function
// These 2 lines of code cause API dll to yell about invalid pointer (C# is happy but it doesnt work with dll)
// IntPtr temp = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(J_2534_API.SConfig_List)));
// IntPtr input = new IntPtr(temp.ToInt32());
// The following 2 lines only compile with unsafe - but API dll "likes" the pointer - but I am not getting desired results
// The dll is properly getting the Number of Parameters (NumOfParams), but the data within the array is not being
// referenced correctly
IntPtr input = Marshal.AllocHGlobal(sizeof(SConfig_List)); // Only works with unsafe
Marshal.StructureToPtr(config, input, true);
APIErr returnVal = (APIErr)m_wrapper.Ioctl(channelId, (int)Ioctl.SET_CONFIG, input, output);
return returnVal;
}
}
我才意識到我的基本想法巨大的監督,我從來沒有甚至可以讓C#快樂,無論我有語法錯誤和代碼不會編譯,或者它會編譯,但給出了運行時錯誤(甚至從來沒有調用外部DLL)
這些問題是在我身後。代碼現在編譯好了,並且執行時沒有任何運行時錯誤。另外,我使用的dll具有日誌記錄功能,所以我可以看到我實際上正在調用正確的函數。我甚至將一些數據正確傳遞給它。函數正在正確讀取NumOfParams變量,但是結構數組似乎是垃圾數據。
我一直在讀一個非常有用的文章在這裏:http://limbioliong.wordpress.com/2012/02/28/marshaling-a-safearray-of-managed-structures-by-pinvoke-part-1/
而且我一直在閱讀MSDN,但到目前爲止,我還沒有能夠碰到的代碼的神奇組合,使這件事情的工作,所以我我再次伸出援助之手。
我很確定我的問題是我沒有正確設置IntPtr變量,並且它們沒有指向內存中的正確區域。
我已經嘗試過不安全和安全代碼的各種組合。另外,我知道在這一點上我沒有明確地釋放內存,所以對此的指點也會有幫助。在我的研究,這裏有一些想法可能的工作,我只是不能似乎得到他們恰到好處
[MarshalAs(UnmanagedType.LPWStr)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst=...)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst=100)]
最後一個問題:我認爲,由於C++的聲明是無符號長,那麼UInt32的是正確的類型在C#中?
非常感謝,這非常有幫助,我可以在你的幫助下完成並運行。由於輸入和輸出指針與正在傳遞的實際Ioctl值的關係不同,我還沒有實現您的想法來爲C函數提供更好的聲明。在某些情況下,它們都是無效的(例如只發送一個明確的緩衝區命令,因此兩個指針都是空的。在另一個Ioctl場景中,一個指針指向一個Bytes數組。因此,我仍然在Set_Config方法中使用Marshaling - 但它工作100%。 – mleega