对于我的问题,我非常接近解决方案,但我需要一些关于最终结果的指导以使所有工作都成功。在过去的一周中,我学到了很多关于数组结构和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