我想知道從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()調用實際執行時會有另一個內存地址?當我寫這篇文章時,我想知道地址變化是否像我第一次想到的那樣「奇怪」。不過,我仍然質疑指針的使用。請指教。
感謝, 安迪
這就是我習慣這樣做的方式。或者,正如我在帖子中提到的那樣,通過使用固定對象。基本上,我想知道是否使用的實現是好的,還是應該將其更改爲您發佈的內容?我想知道,在使用的方法中是否存在危險?即具有這樣的靜態不安全指針? –