非托管内存中写入UInt32类型的数据应该怎样写啊

yangshuosky 2008-07-01 03:39:42
请问一下在非托管内存中写入UInt32类型的数据应该怎样写啊?
调用函数SI_Write (HANDLE Handle, LPVOID Buffer, DWORD NumBytesToWrite,
DWORD *NumBytesWritten)最后一个参数申请非托管内存IntPtr intptr = Marshal.AllocHGlobal(2);因为必须要初始化,所以要write一个数进去,但Marshal成员函数都是写人INT32等等,没有写无符号数的。
如果写入Int32类型,会造成托管与非托管不匹配的吧?
...全文
286 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
yangshuosky 2008-07-05
  • 打赏
  • 举报
回复
我照你的例子试了一下也是可以的,但一回到原来的SI_Write就不行了。到底什么时候才要申请非托管资源呢?这个跟调用函数的定义有关系的吗?
这个dll文件是封装好的一个USB驱动,所以我只能看到其函数的声明而看不到源程序啊。
或者是第一个参数的问题?
gomoku 2008-07-05
  • 打赏
  • 举报
回复
你写的那个dll调用的时候不需要把.h文件也加进去吗?
我以为只有改写成int _stdcall En_Init(); 这样的函数,然后加一个def文件才可以只要一个.dll文件就可以,然后才可以在C#中调用。


.h头文件不是必须的。(当然有了.h头文件,其他c++项目可以很方便的导入)
__declspec(dllexport)则告诉微软编译器要导出一个函数,完成了def文件的功能。在这里,def定义文件也不是必须的。

作为例子,当然越简洁越好,我就把头文件和def文件的内容放到.cpp里面了。
gomoku 2008-07-04
  • 打赏
  • 举报
回复

SI_Write(m_hUSBDevice, ref buf, written, ref written) ;


There is no ref in my post.

Test it again with Cdecl:


byte[] buf = new byte[] { 2, 125 };
SI_Write(m_hUSBDevice, buf, written, ref written); //<---
yangshuosky 2008-07-04
  • 打赏
  • 举报
回复
依然是:对 PInvoke 函数“Client!Client.Form1::SI_Write”的调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。
家鸣 2008-07-04
  • 打赏
  • 举报
回复
uint written;
IntPtr ptrBuf = Marshal.AllocCoTaskMem(4);
SI_Write(m_hUSBDevice, ptrBuf , 4, ref written);
//read ptrBuf
Marshal.FreeCoTaskMem(ptrBuf);//free buf.
家鸣 2008-07-04
  • 打赏
  • 举报
回复

uint written;
IntPtr ptrBuf = Marshal.AllocCoTaskMem(255);
SI_Write(m_hUSBDevice, ptrBuf , 255, ref written);
//read ptrBuf
Marshal.FreeCoTaskMem(ptrBuf);//free buf.
yangshuosky 2008-07-04
  • 打赏
  • 举报
回复
用Cdecl也不行的。函数是没有问题的,因为在C++的程序中已经有使用过。
我现在有两种方案:
1.申请非托管内存Buffer
public static extern int SI_Write(IntPtr Handle, IntPtr Buffer, uint NumBytesToWrite, ref uint NumBytesWritten);
byte[] buf = new byte[] { 2, 125 };
GCHandle gch = GCHandle.Alloc(buf, GCHandleType.Pinned);
IntPtr bufPtr = gch.AddrOfPinnedObject();
uint written = (uint)buf.Length;
SI_Write(m_hUSBDevice, bufPtr, (uint)buf.Length, ref written);
gch.Free();
调试:对 PInvoke 函数“Client!Client.Form1::SI_Write”的调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。
2.申请托管buffer
public static extern int SI_Write(IntPtr Handle,ref byte[] Buffer, uint NumBytesToWrite, ref uint NumBytesWritten);
byte[] buf = new byte[] { 2, 125 };
uint written = (uint)buf.Length;
SI_Write(m_hUSBDevice, ref buf, written, ref written) ;
调试:尝试读取或写入受保护的内存。这通常指示其他内存已损坏。
system_002 2008-07-04
  • 打赏
  • 举报
回复
up
system_001 2008-07-04
  • 打赏
  • 举报
回复
up
yilanwuyu123 2008-07-04
  • 打赏
  • 举报
回复
mark
gomoku 2008-07-04
  • 打赏
  • 举报
回复
...函数是这样的,但调用规则我不大清楚 ...

Then try using Cdecl call (CallingConvention = CallingConvention.Cdecl).
If you still have no luck, you might need to write a c++ program to test that function.


[DllImport("yourdll.dll", CallingConvention = CallingConvention.Cdecl)] //<----
static extern int SI_Write(IntPtr handle, byte[] buffer, int cbToWrite, ref int cbWritten);


{
byte[] buf = new byte[] { 1, 2, 3, 4 };
int written = 0;
SI_Write( yourHandle, buf, buf.Length, ref written);
}
yangshuosky 2008-07-04
  • 打赏
  • 举报
回复
请问一下这种调用不需要设置什么吧?
你写的那个dll调用的时候不需要把.h文件也加进去吗?
我以为只有改写成int _stdcall En_Init(); 这样的函数,然后加一个def文件才可以只要一个.dll文件就可以,然后才可以在C#中调用。
gomoku 2008-07-04
  • 打赏
  • 举报
回复
为什么我的就可以呢?你要检查SI_Write的真实原形是什么样的,以下代码供你试验:

#include "stdafx.h"
#include <windows.h>

extern "C" __declspec(dllexport) int __cdecl SI_Write(HANDLE Handle, LPVOID Buffer, DWORD NumBytesToWrite, DWORD *NumBytesWritten)
{
char buf[128] = {0};
for(int i=0; i<NumBytesToWrite && i<127; i++)
{
buf[i] = ((char*)Buffer)[i];
}
*NumBytesWritten = NumBytesToWrite;
MessageBoxA(NULL, buf, "", MB_OK);
return 1234;
}



using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
byte[] buf = new byte[] { (byte)'1', (byte)'2', (byte)'3', (byte)'5' };
int written = 0;
SI_Write( IntPtr.Zero, buf, buf.Length, ref written); // message popped up

System.Diagnostics.Debug.Assert(written == buf.Length); // ok
}
[DllImport("MyDll.dll",CallingConvention=CallingConvention.Cdecl)]
static extern int SI_Write(IntPtr handle, byte[] buffer, int cbToWrite, ref int cbWritten);
}
}


第二个参数是LPVOID Buffer,不是一个地址或者指针吗?可以直接用buf吗?
可以。buf本身就‘指向’了一个数组。
yangshuosky 2008-07-04
  • 打赏
  • 举报
回复
还是:对 PInvoke 函数“Client!Client.Form1::SI_Write”的调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。
我试了一下用Cdecl与否都是这样的。
第二个参数是LPVOID Buffer,不是一个地址或者指针吗?可以直接用buf吗?
yangshuosky 2008-07-03
  • 打赏
  • 举报
回复
函数是这样的,但调用规则我不大清楚
SI_STATUS SI_Write (HANDLE Handle, LPVOID Buffer, DWORD NumBytesToWrite,
DWORD *NumBytesWritten)
Parameters: 1. Handle—Handle to the device to write as returned by SI_Open.
2. Buffer—Address of a character buffer of data to be sent to the device.
3. NumBytesToWrite—Number of bytes to write to the device (0–4096 bytes).
4. NumBytesWritten—Address of a DWORD which will contain the number of bytes actually
written to the device.
是写USB的一个函数。
gomoku 2008-07-03
  • 打赏
  • 举报
回复
你把SI_Write()的原形贴出来(包括它的调用规则是stdcall还是cdecl)。
yangshuosky 2008-07-03
  • 打赏
  • 举报
回复
是这样报错的
对 PInvoke 函数“Client!Client.Form1::SI_Write”的调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。
请问是哪里错了呢?
gomoku 2008-07-01
  • 打赏
  • 举报
回复
还是托管与非托管不匹配
什么叫托管与非托管不匹配?

那么uint written 应该=buf.Length对吗?
运行正确的话应该是,如果written>0但<buf.Length,则要检查SI_Write的具体做法。

...
uint written = 0;
SI_Write( yourHandle, bufPtr, buf.Length, ref written);
Debug.Assert( written == (uint)buf.Length); // 检查是否所有数据全部写出
...
yangshuosky 2008-07-01
  • 打赏
  • 举报
回复
buf.Length不是uint型的啊。我强制转换了,还是托管与非托管不匹配。
而且定义
2. Buffer—Address of a character buffer of data to be sent to the device.
3. NumBytesToWrite—Number of bytes to write to the device (0–4096 bytes).
4. NumBytesWritten—Address of a DWORD which will contain the number of bytes actually
written to the device.
那么uint written 应该=buf.Length对吗?
谢谢!
gomoku 2008-07-01
  • 打赏
  • 举报
回复


[DllImport("...")]
static extern void SI_Write(IntPtr Handle, IntPtr Buffer, uing NumBytesToWrite, ref uint NumBytesWritten);
{
byte[] buf = new byte[] { 1, 2, 3, 4 };
GCHandle gch = GCHandle.Alloc(buf, GCHandleType.Pinned); // need to pin the object, otherwise the CLR could move the object.
IntPtr bufPtr = gch.AddrOfPinnedObject();
uint written = 0;

SI_Write( yourHandle, bufPtr, buf.Length, ref written); // you don't need to Marshal.AllocHGlobal, use 'ref uint written' instead

gch.Free();
}



111,125

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧