编组结构,嵌入指针从C#到非托管驱动程序(Marshalling struct with embedded pointer from C# to unmanaged driver)
我正在尝试使用P / Invoked DeviceIoControl()调用将C#(.NET Compact Framework 3.5)与Windows CE 6 R2流驱动程序连接。 对于其中一个IOCTL代码,驱动程序需要一个DeviceIoControl输入缓冲区,该缓冲区是包含嵌入指针的以下非托管结构:
typedef struct { DWORD address; const void* pBuffer; DWORD size; // buffer size } IOCTL_TWL_WRITEREGS_IN;
我在C#中定义了结构:
[StructLayout(LayoutKind.Sequential)] public struct IoctlWriteRegsIn { public uint Address; public byte[] Buffer; public uint Size; }
和我的P / Invoke签名为:
[DllImport("coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)] static extern bool DeviceIoControl(IntPtr hDevice, UInt32 dwIoControlCode, ref IoctlWriteRegsIn lpInBuffer, UInt32 nInBufferSize, UInt32[] lpOutBuffer, UInt32 nOutBufferSize, ref UInt32 lpBytesReturned, IntPtr lpOverlapped);
但是,每当我在C#中调用DeviceIoControl()时,它总是返回false,最后一次Win32错误为
ERROR_INVALID_PARAMETER
。 这是驱动程序中IOCTL switch语句的源代码片段,它处理IOCTL代码并对输入缓冲区进行错误检查,其中inSize是nInBufferSize参数:case IOCTL_TWL_WRITEREGS: if ((pInBuffer == NULL) || (inSize < sizeof(IOCTL_TWL_WRITEREGS_IN))) { SetLastError(ERROR_INVALID_PARAMETER); break; } address = ((IOCTL_TWL_WRITEREGS_IN*)pInBuffer)->address; pBuffer = ((IOCTL_TWL_WRITEREGS_IN*)pInBuffer)->pBuffer; size = ((IOCTL_TWL_WRITEREGS_IN*)pInBuffer)->size; if (inSize < (sizeof(IOCTL_TWL_WRITEREGS_IN) + size)) { SetLastError(ERROR_INVALID_PARAMETER); break; } rc = TWL_WriteRegs(context, address, pBuffer, size);
我试过硬编码大小应该通过驱动程序的错误检查没有成功,这表明它是一个编组问题。 我可能没有正确定义C#struct中的嵌入指针或者我的P / Invoke签名错误。 有任何想法吗?
提前谢谢,本
作为参考,我可以用C ++与驱动程序通信,没有这样的问题:
IOCTL_TWL_WRITEREGS_IN reg; reg.address = 0x004B0014; unsigned char data = 0xBE; reg.pBuffer = &data; reg.size = sizeof(char); BOOL writeSuccess = DeviceIoControl(driver, IOCTL_TWL_WRITEREGS, ®, sizeof(IOCTL_TWL_WRITEREGS_IN) + 1, NULL, 0, NULL, NULL);
更新:这是有效的! 使用JaredPar的IntPtr建议并通过SwDevMan81的建议清理我的P / Invoke签名:
[StructLayout(LayoutKind.Sequential)] public struct IoctlWriteRegsIn { public uint Address; public IntPtr Buffer; public uint Size; } // elided byte regData = 0xFF; GCHandle pin = GCHandle.Alloc(regData, GCHandleType.Pinned); IoctlWriteRegsIn writeInBuffer = new IoctlWriteRegsIn{Address = twlBackupRegA, Buffer = pin.AddrOfPinnedObject(), Size = 1}; bool writeSuccess = DeviceIoControl(driverHandle, IoctlTwlWriteRegs, ref writeInBuffer, (uint) Marshal.SizeOf(writeInBuffer) + 1, IntPtr.Zero, 0, ref numBytesReturned, IntPtr.Zero); // P/Invoke signature [DllImport("coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)] static extern bool DeviceIoControl(IntPtr hDevice, UInt32 dwIoControlCode, ref IoctlWriteRegsIn lpInBuffer, UInt32 nInBufferSize, IntPtr lpOutBuffer, UInt32 nOutBufferSize, ref UInt32 lpBytesReturned, IntPtr lpOverlapped);
I'm trying to interface C# (.NET Compact Framework 3.5) with a Windows CE 6 R2 stream driver using P/Invoked DeviceIoControl() calls . For one of the IOCTL codes, the driver requires a DeviceIoControl input buffer that is the following unmanaged struct that contains an embedded pointer:
typedef struct { DWORD address; const void* pBuffer; DWORD size; // buffer size } IOCTL_TWL_WRITEREGS_IN;
I defined the struct in C# as:
[StructLayout(LayoutKind.Sequential)] public struct IoctlWriteRegsIn { public uint Address; public byte[] Buffer; public uint Size; }
and my P/Invoke signature as:
[DllImport("coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)] static extern bool DeviceIoControl(IntPtr hDevice, UInt32 dwIoControlCode, ref IoctlWriteRegsIn lpInBuffer, UInt32 nInBufferSize, UInt32[] lpOutBuffer, UInt32 nOutBufferSize, ref UInt32 lpBytesReturned, IntPtr lpOverlapped);
However, whenever I call DeviceIoControl() in C#, it always returns false, with a last Win32 error of
ERROR_INVALID_PARAMETER
. Here's a source code snippet from the IOCTL switch statement in the driver that handles the IOCTL code and does error checking on the input buffer, where inSize is the nInBufferSize parameter:case IOCTL_TWL_WRITEREGS: if ((pInBuffer == NULL) || (inSize < sizeof(IOCTL_TWL_WRITEREGS_IN))) { SetLastError(ERROR_INVALID_PARAMETER); break; } address = ((IOCTL_TWL_WRITEREGS_IN*)pInBuffer)->address; pBuffer = ((IOCTL_TWL_WRITEREGS_IN*)pInBuffer)->pBuffer; size = ((IOCTL_TWL_WRITEREGS_IN*)pInBuffer)->size; if (inSize < (sizeof(IOCTL_TWL_WRITEREGS_IN) + size)) { SetLastError(ERROR_INVALID_PARAMETER); break; } rc = TWL_WriteRegs(context, address, pBuffer, size);
I tried hard coding sizes that should pass the driver's error checking with no success, suggesting that it's a marshalling problem. I probably did not define the embedded pointer in the C# struct correctly or have my P/Invoke signature wrong. Any ideas?
Thanks in advance, Ben
For reference, I can talk to the driver from C++ with no problems like this:
IOCTL_TWL_WRITEREGS_IN reg; reg.address = 0x004B0014; unsigned char data = 0xBE; reg.pBuffer = &data; reg.size = sizeof(char); BOOL writeSuccess = DeviceIoControl(driver, IOCTL_TWL_WRITEREGS, ®, sizeof(IOCTL_TWL_WRITEREGS_IN) + 1, NULL, 0, NULL, NULL);
Update: here's what worked! Used JaredPar's IntPtr suggestion and cleaned up my P/Invoke signature by SwDevMan81's suggestion:
[StructLayout(LayoutKind.Sequential)] public struct IoctlWriteRegsIn { public uint Address; public IntPtr Buffer; public uint Size; } // elided byte regData = 0xFF; GCHandle pin = GCHandle.Alloc(regData, GCHandleType.Pinned); IoctlWriteRegsIn writeInBuffer = new IoctlWriteRegsIn{Address = twlBackupRegA, Buffer = pin.AddrOfPinnedObject(), Size = 1}; bool writeSuccess = DeviceIoControl(driverHandle, IoctlTwlWriteRegs, ref writeInBuffer, (uint) Marshal.SizeOf(writeInBuffer) + 1, IntPtr.Zero, 0, ref numBytesReturned, IntPtr.Zero); // P/Invoke signature [DllImport("coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)] static extern bool DeviceIoControl(IntPtr hDevice, UInt32 dwIoControlCode, ref IoctlWriteRegsIn lpInBuffer, UInt32 nInBufferSize, IntPtr lpOutBuffer, UInt32 nOutBufferSize, ref UInt32 lpBytesReturned, IntPtr lpOverlapped);
原文:https://stackoverflow.com/questions/1681517
最满意答案
您永远不会连接到数据库。 数据库(aka schema)只是数据库服务器(又名RDBMS)中的组织结构。 因此,首先连接到该服务器,以建立通信。 然后选择要使用的模式。 要么运行USE命令,要么在MySQL Workbench中双击左侧架构树中的架构节点,使其成为当前默认值。 您还可以在连接设置中设置初始默认架构。 当前(默认)架构在树中以粗体显示:
You never connect to a database. A database (aka schema) is just an organizational construct within a database server (aka RDBMS). So, first you connect to that server, to establish the communication. Then you select a schema to work with. Either run a USE command or, in MySQL Workbench, double click on a schema node in the schema tree on the left hand side to make this the current default. You can also set an initial default schema in the connection settings. The current (default) schema is shown in bold in the tree:
相关问答
更多-
有什么数据库专业书籍介绍?[2022-05-19]
mysql -
如何使用MySQL Workbench进行MySQL数据库备份?(How to take MySQL database backup using MySQL Workbench?)[2022-02-26]
对于Workbench 6.0 打开MySql工作台。 要进行数据库备份,您需要在Server Administration创建New Server Instance (如果不可用)。 创建New Server Instance步骤: 在Server Administrator选择New Server Instance选项。 提供连接细节。 创建新的服务器实例后,它将在“ Server Administration列表中可用。 双击您创建的服务器实例或单击Manage Import/Export选项和选择服 ... -
我不是MySQL Workbench的用户,但要确保首先使用支持外键的存储引擎。 (例如,InnoDB) 请参阅MySQL文档以获取外键关系所需的要求 。 I'm not a user of MySQL Workbench, but make sure you're using a storage engine that supports foreign keys in the first place. (for example, InnoDB) See the MySQL documentation fo ...
-
如果您只想添加加号字段(列?),则无需使用MySQL Workbench或SQL查询进行任何导出或导入即可。 MySQL更改表: ALTER TABLE语法 或者在MySQL Workbench中右键单击表而不是单击Alter table ...添加新列而不是单击Apply,这将添加新列而不会损害任何已添加的数据。 您还可以指定默认值。 If you only want to add plus fields (columns?) you can do them without any export or i ...
-
不。您必须首先删除数据库然后恢复。 No. You have to drop the DB first then restore.
-
您永远不会连接到数据库。 数据库(aka schema)只是数据库服务器(又名RDBMS)中的组织结构。 因此,首先连接到该服务器,以建立通信。 然后选择要使用的模式。 要么运行USE命令,要么在MySQL Workbench中双击左侧架构树中的架构节点,使其成为当前默认值。 您还可以在连接设置中设置初始默认架构。 当前(默认)架构在树中以粗体显示: You never connect to a database. A database (aka schema) is just an organizatio ...
-
为什么我不能使用MySQL Workbench连接到我的MySQL数据库?(Why can't I connect to my MySQL database using MySQL Workbench?)[2021-06-06]
看起来MySQL Workbench无法在您的计算机上正确启动。 我从官方网站上发现了这一点 ,看看它是否有效,如果没有尝试向开发团队报告错误并等待响应。 或者,您可以尝试使用其他工具连接到数据库。 I executed MySQL Workbench using -log-level=debug3 command: MySQLWorkbench.exe -log-level=debug3. After reading the log generated by the program I found fol ... -
您可以尝试文件 - >导出 - >转发工程师SQL创建脚本 。 在这里,您可以生成与EER图对应的SQL脚本,并在数据库引擎中执行此脚本。 You can try File -> Export -> Forward Engineer SQL Create Script. Here you can generate the SQL Script corresponding to your EER diagram, and execute this script in your database engine. ...
-
没有表格自己填充,您需要确保它已填充。 为多对多关系创建的第三个表称为关联表或联结表,并且至少包含它们连接的2个表的主键。 如果您有一个recipe_id标识收件人和一个fish_id识别鱼类,那么Cooking_Has_Fish表将至少有一个recipe_id和一个fish_id字段。 如果你想将fish and chips (with recipe_id 1)与cod ( fish_id为2)相关联,那么你会做以下插入: insert into Cooking_Has_Fish (`recipe_id` ...
-
尝试将逆向工程转换为新模型并保存。 打开主模型,然后选择“文件” - >“包括模型”以包含其他模型。 顺便说一句:模型中的内容肯定存在限制(甚至更多:在单个图表上),但至少你应该能够一次对至少200个对象进行逆向工程。 Try reverse engineering into a new model and save that. Open your main model and choose File -> Include Model to include your other model. Btw: th ...