封送一个结构体以获得一个固定指针

c++/c# Marshal a struct to get a fixed pointer

本文关键字:一个 定指 指针 结构体      更新时间:2023-10-16

我有一个接受dll插件的旧应用程序。每个插件都有一个创建"widget"新实例的函数。这个函数通过返回一个惟一的int来标识新的"小部件"实例。在c++插件模板中,我通过声明一个新的小部件结构体并将其指针转换为int作为唯一标识符(不是我的想法,但我必须使用它)来完成:

struct widget {
    ...
};
int widget_instance (HWND hwnd) {
    widget* myWidget = new widget;
    ...
    return (int) myWidget;
}

我正在为这个应用程序做一个c#插件,我需要在c#中复制这个机制。如何在函数中声明结构,以便每次调用函数时,它返回一个固定的,不变的指针,指向新声明的结构?我的代码到目前为止:

public struct Widget {
   ...
}
public static int widget_instance(uint hwnd) {
    Widget w = new Widget();
    ...
    IntPtr myWidget = Marshal.AllocCoTaskMem(Marshal.SizeOf(w));
    Marshal.StructureToPtr(w, myWidget, false);
    return (int) myWidget;
}

这看起来对吗?我是否需要"固定"结构,以使其像c++一样工作?

编辑:详细说明:唯一ID不仅仅是一个简单的"cookie"int,它实际上后来在c++模板中使用,通过将ID转换为指针来访问结构体实例:

widget* w = (widget*) WidgetID;
w->firstElement = 123;

我认为c#的等效是:

widget w = (widget)Marshal.PtrToStructure((IntPtr)widgetID,typeof(widget));
w.firstElement = 123;

你似乎暗示返回的整数标识符只是一个cookie,而不是由应用程序作为指针处理。这意味着应用程序永远不会在小部件上执行操作,但总是要求插件代表应用程序执行操作。如果是这种情况,那么没有理由不能使用自己的方案来分配cookie标识符。所以…

你可以添加一个"cookie"成员到你的Widget类,和一个静态的"next cookie"成员分配cookie。这将是一个简单且语义合理的实现。显然,这需要线程安全措施。它还可以避免c++将"this"指针强制转换为int型的技术,你说你不喜欢这种技术,尽管我认为它完全没问题。

c++指针到整型的强制转换技术除了提供唯一标识符之外,还可以用于第二个目的。当应用程序给插件一个cookie时,插件可以直接找到这个小部件,并且通过将cookie转换回指针来零运行时成本。尽管这并不安全。但是我不认为你可以在c#中做到这一点。

你建议的c#代码意味着对于应用程序请求的每个小部件,你都要创建并初始化第二个小部件。如果您真的想模仿c++技术,以保证您的cookie在整个进程范围内是唯一的,而不仅仅是在单个插件中是唯一的,那么您可以只分配一个1字节块,但不初始化它。或者甚至是一个零大小的块,但我不太确定这会产生唯一的地址

是的,这是正确的,因为AllocCoTaskMem非托管 COM分配器分配内存。

仅使用FreeCoTaskMemReAllocCoTaskMem函数释放或重新定位内存

相关文章: