我想知道从C#内部分配内存到指针(C/C++风格)的正确方法。然后,长时间保持该内存。此外,这个分配的内存用于调用DeviceIoControl()。考虑这个类:非托管内存分配到托管对象
class Example {
const uint memCommit = 0x1000;
const uint pgReadWrite = 0x04;
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, uint flAllocationType, uint flProtect);
[StructLayout(LayoutKind.Sequential)]
struct AStruct {
uint val1;
uint val2;
uint val3;
}
private static unsafe AStruct* pStruct = (AStruct*)VirtualAlloc(IntPtr.Zero, (UIntPtr)(sizeof(AStruct)), memCommit, pgReadWrite).ToPointer();
public static unsafe void ReadFromDevice() {
// setup the structure for the IOCTL call
pStruct->val1 = 70; //
pStruct->val2 = 0;
pStruct->val3 = 0x0f;
// call P/Invoked DeviceIoControl() here with pStruct as both the in/out pointers
// check that all is well
}
}
这整个事情没有“感觉”我的权利,但我已经够学到了不立即执行问题,不研究它的年。这就是我带到这个论坛的原因。我看到了以前从未见过的行为。
使用调试器,我在通过调用VirtualAlloc()实例化指针的位置放置一个断点。我记下给我的地址(例如,0x03bf78cc)。我还在另一个调用上述方法ReadFromDevice()的函数中放置了一个断点。当我逐步通过ReadFromDevice()时,我注意到pStruct包含的地址与程序第一次启动时分配的地址不同。 pStruct的值已经从我上面的数字变成了,比方说0x03cd9004。
我已经调用了Kernel32函数DeviceIoControl()之前,并且使用的方法是实例化一个固定的GCHandle到在调用DeviceIoControl()中使用的数据结构,进行调用,复制出适当的数据,然后释放句柄。这种方法似乎不太容易出错,并与尽可能快地分配和释放非托管内存的模型保持一致。
正如我所提到的,我现在所使用的代码中使用的方法并不是“感觉”正确,但我不确定原因。我在谷歌搜索上没有找到任何东西,比如“c语言内存地址在alloc后更改”等等。这种方法应该改变吗? (过去,我使用固定的GC手柄。)上述方法是否正确?无论如何,指针在程序启动时会说一个内存地址,而在ReadFromDevice()调用实际执行时会有另一个内存地址?当我写这篇文章时,我想知道地址变化是否像我第一次想到的那样“奇怪”。不过,我仍然质疑指针的使用。请指教。
感谢, 安迪
这就是我习惯这样做的方式。或者,正如我在帖子中提到的那样,通过使用固定对象。基本上,我想知道是否使用的实现是好的,还是应该将其更改为您发布的内容?我想知道,在使用的方法中是否存在危险?即具有这样的静态不安全指针? –