我认为答案很短,如是或否,所以我一次有两个问题。
问题#1 :我阅读了IntPtr的理论解释,但与本机C ++指针相比,它更容易理解。可以说我有一些结构。
ref struct CData
{
double Key;
};
使用本机代码中的指针,我可以这样做:
1) int address = & CData; // if i need its address
2) double value = * CData; // if i need value of its field
3) void * pointer1 = CData; // if i want create pointer to struct
4) CData * pointer2 = CData; // if i want create pointer to struct
如果CData是托管对象,则可以通过以下方式执行上述操作:
1) IntPtr address = GCHandle::Alloc(CData).AddrOfPinnedObject() // if i need address
2) cannot get one field within pointer, only direct access within CData.Key
3) IntPtr pointer = GCHandle::ToIntPtr(GCHandle::Alloc(CData)) // if i need pointer
4) the same as # 3
我是否正确地提出了关于本机代码和托管代码中指针之间相似性的建议?
问题#2 :在我的原生应用中,我没有 void * 这样的类型,我可以简单地使用 int 吗? / p>
此处显示的可用数据类型的完整列表http://www.mql5.com/en/docs/basis/types - 哪一个可以作为void *的有效替代品,因此我可以将其与IntPtr结合使用?
答案 0 :(得分:5)
IntPtr
不是指针。它是一个足以存储指针的整数,就像标准C和C ++中的uintptr_t
一样。
在C ++ / CLI中,&#34;指向托管对象的指针&#34; type是interior_ptr<T>
和pin_ptr<T>
伪模板。与c#fixed块一样,pin_ptr<T>
将托管堆上的对象固定,允许您将指针作为普通本机指针传递给现有代码,而不会将对象从该代码下移出。
在C ++ / CLI中很少有任何理由直接使用GCHandle
。请改用pin_ptr<T>
和gcroot<T>
模板。并且有充分的理由避免它,你在问题的一行代码中犯了两个严重的错误:
GCHandle::Alloc(CData).AddrOfPinnedObject()
你泄露了GCHandle。你在非钉扎GCHandle上打电话给AddrOfPinnedObject
。
使用为此目的构建的C ++ / CLI工具。他们会引导你远离这些错误。
答案 1 :(得分:0)
似乎我找到了解释,帮助我理解了如何使用IntPtr。
以下段落包含错误的建议。
这就是我所得到的,已经过测试并且有效,所以我认为这是正确的实施。
我不应该考虑固定指针,因为我会去工作 使用自定义托管类,它似乎不是Blittable类型和 可能无法固定。我可以使用一些泛型类型,比如byte 数组,使用AddrOfPinnedObject将其固定并获取实际地址。在这 我可以使用来自托管和非托管的数据进行操作 程序,但我决定留在管理方只是为了 简单。
我意识到IntPtr是指向数据的指针,类型为void **但对于托管堆,这意味着有两个指针,第一个指向&#34;处理&#34;和&#34;处理&#34;指向真实数据。如果实际数据被重新定位,则第二个指针(&#34;句柄&#34;)可以在GC循环后改变但是该句柄的地址保持不变,这意味着第一个指针在任何情况下都是持久的。我只使用托管代码处理数据,所以只保存第一个指针就足够了,然后,使用这个指针,我总是可以获得&#34; handle&#34;,无论GC的值是否被更改都无关紧要或不。给定句柄 - 可以自己获取数据。
对我来说模板int_ptr&lt;&gt;和interrior_prt&lt;&gt;看起来像是一个黑盒子,所以如果我使用它们那么可能会更难理解这些句柄是如何工作的,也许我会很快改变主意但现在我用GCHandle实现它
示例:
让我说我在C#DLL中有类,我想通过内存映射文件用作共享内存,我称之为Connection:
http://www.codeproject.com/Articles/138290/Programming-Memory-Mapped-Files-with-the-NET-Frame
然后在C ++ / CLI中我有:
#define ECV extern "C" __declspec(dllexport) void __cdecl
ECV MemoryOpen(char * name, int size, int &pointer)
{
try
{
Connection ^ memory = gcnew Connection(); // instantiate managed class
GCHandle gc = GCHandle::Alloc(memory); // get handle
pointer = (int) GCHandle::ToIntPtr(gc); // get pointer to handle and pass it to unmanaged code by reference
memory->Open(gcnew String(name), size); // do something from managed code
}
catch (Exception ^ e)
{
MessageBox::Show(e->Message + " " + e->StackTrace);
}
}
ECV MemoryClose(int pointer)
{
try
{
GCHandle gc = GCHandle::FromIntPtr(IntPtr(pointer)); // get pointer to handle
Connection ^ memory = (Connection ^) gc.Target; // get data using handle
memory->Close();
gc.Free(); // free handle
}
catch (Exception ^ e)
{
MessageBox::Show(e->Message + " " + e->StackTrace);
}
}