c++/c# Marshal a struct to get a fixed pointer
I have an older app which accepts dll plugins. Each plugin has a function that creates a new instance of a "widget". This function identifies the new "widget" instance by returning a unique int. In the c++ plugin template I have it's done by declaring a new widget struct and returning its pointer cast as an int as a unique identifier (not my idea, but I have to work with it):
struct widget {
...
};
int widget_instance (HWND hwnd) {
开发者_如何学编程 widget* myWidget = new widget;
...
return (int) myWidget;
}
I'm working on a c# plugin for this app and I need to replicate this mechanism in c#. How do I declare a struct inside a function, so that each time the function is called it returns a fixed, non-changing pointer to the newly declared struct? My code so far:
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;
}
Does this seem right? Do I need to "pin" the struct for this to work as c++ does?
EDIT: To elaborate: the unique ID is not just a simple "cookie" int, it's in fact used later on in the c++ template to access the struct instance by casting the ID as a pointer:
widget* w = (widget*) WidgetID;
w->firstElement = 123;
I assume the c# equivalent would be:
widget w = (widget)Marshal.PtrToStructure((IntPtr)widgetID,typeof(widget));
w.firstElement = 123;
You seem to imply that the returned integer identifier is just a cookie, and isn't treated by the app as a pointer. That would mean that the app never performs operations on the widget, but always asks the plugin to perform the operations on the app's behalf. If that's the case then there's no reason why you can't use your own scheme for assigning cookie identifiers. So...
You could add a "cookie" member to your Widget class, and a static "next cookie" member for assigning cookies. This would be a simple and semantically sound implementation. Obviously it would require thread-safety measures. It would also avoid the C++ technique of casting the "this" pointer to an int, which you say you don't like although I think it's perfectly fine.
The C++ pointer-to-int cast technique might serve a second purpose in addition to providing a unique identifier. When the app gives the plugin a cookie, the plugin can find the widget directly and at zero runtime cost by casting the cookie back to a pointer. Although that's hardly safe. But I don't think you can do that in C# anyway.
Your proposed C# code means that for every widget the app asks for, you wantonly create and initialize a second widget. If you really want to mimic the C++ technique so that your cookies are guaranteed to be unique process-wide, as opposed to just unique within the single plugin, then you could just allocate a one-byte block but don't initialize it. Or even a zero-sized block, but I'm not quite certain that that would yield unique addresses.
Yes, it is correct, since AllocCoTaskMem
allocates the memory from the unmanaged COM allocator.
The memory is released or relocated only with the FreeCoTaskMem
or ReAllocCoTaskMem
functions, respectively.
精彩评论