可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I want to implement a Mongoose (http://code.google.com/p/mongoose/) Binding in C#. There are some examples, but they don't work with the current version.
This is my current function call:
[DllImport("_mongoose",CallingConvention=CallingConvention.Cdecl)] private static extern IntPtr mg_start(int zero, Nullable, string options);
The (working) C equivalent would be:
const char *options[] = {
"document_root", "/var/www",
"listening_ports", "80,443s",
NULL
};
struct mg_context *ctx = mg_start(&my_func, NULL, options);
where mg_start is defined as:
struct mg_context *mg_start(mg_callback_t callback, void *user_data,
const char **options);
You can find the whole C example here:
https://svn.apache.org/repos/asf/incubator/celix/trunk/remote_services/remote_service_admin_http/private/include/mongoose.h
How do I transfer the const char *options[]
to c#?
Thank you
回答1:
DllImport("_mongoose",CallingConvention=CallingConvention.Cdecl)]
private static extern IntPtr mg_start(IntPtr callback, IntPtr userData,
[In][MarshalAsAttribute(UnmanagedType.LPArray,
ArraySubType=UnmanagedType.LPStr)] string[] options);
Haven't tried this, but I think this gets you there. You might need to make the ArraySubType be LPWStr if you want unicode in the C call. Making it LPStr gives you ANSI.
Are you doing the function pointers? That's where the real challenge is. Not so much from declaring and marshaling but rather from a pointer lifespan issue. If mg_start holds onto the unmanaged version of the delegate, you may find that the thunk gets garbage collected on you, in spite of what the documentation says. We've seen this happen so often that we've, where possible, rearchitected the underlying glue to not use that style of code.
Generally speaking, if the API is a chatty API with tons of callbacks, you're going to be hosed by the callbacks. You're better off trying to create a C++/CLI library that implements the API in a far less chatty way with clear managed/unmanaged boundaries.
回答2:
char[] in C# is a String.
Looks like you are defining a pointer to a char[]. In C this is the Array of Arrays, right?
So in C# it would be just:
String[] options = {
"document_root", "/var/www",
"listening_ports", "80,443s",
NULL
};
Hope it helps.
Regards.
回答3:
try
[DllImport("_mongoose",CallingConvention=CallingConvention.Cdecl)]
private static extern IntPtr mg_start(int zero, IntPtr userData, string[] options);
and use IntPtr.Zero
as userdata
. and something like
new [] { "document_root", "/var/www", "listening_ports", "80,443s", null }
as options.
回答4:
I just wanted to suggest using C# binding, on the project page in the features they have:
Have you tried this?
回答5:
In C# a char is an Unicode character, therefore consisting of two bytes. Using strings is not an option here, but you can use the Encoding.ASCII class to get the ASCII representation of the unicode string as a byte array:
byte[] asciiString = Encoding.ASCII.GetBytes(unicodeString);
C#'s arrays are references, aka pointers in C, so you can write your code as:
byte[][] options = {
Encoding.ASCII.GetBytes("document_root"),
Encoding.ASCII.GetBytes("/var/www"),
Encoding.ASCII.GetBytes("listening_ports"),
Encoding.ASCII.GetBytes("80,443s"),
null
};
You can't do anything about the const other than creating a wrapper class with read-only indexers and a private array of bytes, but this won't work in your case.