c ++ / c #Marshal一个结构来获得一个固定的指针

时间:2011-05-04 04:01:09

标签: c# c++ pointers struct marshalling

我有一个较旧的应用程序,它接受dll插件。每个插件都有一个创建“小部件”的新实例的功能。此函数通过返回唯一的 int 来标识新的“窗口小部件”实例。在c ++插件模板中,我通过声明一个新的小部件 struct 并将其指针强制转换为 int 作为唯一标识符(不是我的想法,但我必须使用它):

struct widget {
    ...
};

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

我正在为这个应用程序开发一个c#插件,我需要在c#中复制这个机制。如何在函数内部声明一个struct,这样每次调用该函数时它都会返回一个固定的,不变的指向新声明的struct的指针?到目前为止我的代码:

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 ++模板中稍后用于访问 struct 实例通过将ID转换为指针:

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

我认为c#等价物是:

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

2 个答案:

答案 0 :(得分:1)

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

您可以在Widget类中添加“cookie”成员,并为分配Cookie添加静态“下一个cookie”成员。这将是一个简单且语义上合理的实现。显然,它需要线程安全措施。它还可以避免使用C ++技术将“this”指针转换为int,你说你不喜欢它,尽管我认为它非常好。

除了提供唯一标识符之外,C ++指针到int转换技术可能还有第二个目的。当应用程序为插件提供cookie时,插件可以通过将cookie转换回指针来直接找到窗口小部件并且运行时成本为零。虽然这不安全。但我不认为你能在C#中做到这一点。

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

答案 1 :(得分:0)

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

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