Automatic casting for string DllImport arguments vs Marshal.StringToCoTaskMemUni - c#

Consider the WM_SETTEXT message that you can use to set the text of another window via old school Win32 API. There are probably a multitude of ways of doing this in .NET, here's two that I know:
[DllImport("USER32", EntryPoint = "SendMessage", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, string lParam);
SendMessage(handle, WM_SETTEXT, IntPtr.Zero, "Magic String");
[DllImport("USER32", EntryPoint = "SendMessage", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
IntPtr textPointer = Marshal.StringToCoTaskMemUni("Magic String");
SendMessage(handle, WM_SETTEXT, IntPtr.Zero, textPointer);
Marshal.FreeCoTaskMem(textPointer);
The first one uses a string in the declaration of the dll import and lets .NET handle it. This second uses an IntPtr and explicitly creates a pointer using Marshal.StringToCoTaskMemUni and then freed using Marshal.FreeCoTaskMem. Both of these approaches work happily as far as I can tell.
Note I normally do the former (which in fact I used to do many years ago as a VB6 programmer), but I came across the latter on a comment on another StackOverflow post and was curious if the former was another bad habit that needed squashing.
I have also seen a variant of the first example using a char[] array in the declaration and passing in a StringBuilder
My question is simple - which (if any) is the correct way of doing it? For example, the SendMessage Win32 call only accepts pointers anyway, so "something" must be creating pointers behind the scenes for the first version, and if so does it do the cleaning up, or is it better to be verbose and use the explicit allocation and deallocation of pointers.

When you declare a parameter of string, the p/invoke marshaller will, behind the scenes, marshal that to a pointer to a null-terminated array of characters. The marshaller will handle all memory allocation and deallocation. You can do it yourself with an IntPtr parameter, but it comes to the same in the end.
Which you choose comes down to whether or not you plan to use the SendMessage declaration for any other messages that you send.
If you only ever call SendMessage for WM_SETTEXT, then you declare it to receive a string parameter.
If you also use SendMessage to send other messages, then you can declare the parameter to be IntPtr and perform the marshalling manually.
And yet another option is to declare multiple overloaded variants so that you can make the code that calls SendMessage as convenient as possible for the programmer.
Now, let's pick up that last option. Suppose you needed to send WM_GETTEXT as well as WM_SETTEXT. For WM_SETTEXT you need to pass string data from managed to native, so you'd prefer string. For WM_GETTEXT, you need to supply a buffer so that the native code can fill out the window text. And that means you want to use StringBuilder. So, declare two overloads, one receiving string and one receiving StringBuilder. Use the former for WM_SETTEXT and the latter for WM_GETTEXT.

Related

Should I use the ref keyword here?

I'm new to C# so I looked at this question but I'm still not sure whether I should be including the ref keyword here when marshalling the second parameter of the GetWindoInfo() Win32 API call using p/invoke:
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", EntryPoint = "GetWindowInfo", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool GetWindowInfo(IntPtr hwnd, [MarshalAs(UnmanagedType.Struct)] ref tagWINDOWINFO pwi);
From the MSDN documentation for ref:
The ref keyword causes an argument to be passed by reference, not by
value.
So in that case my code above seems to be correct, right? Would changing the marshalling clause to instead marshal an UnmanagedType.LPStruct and removing the ref keyword result in the same thing? Like so:
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", EntryPoint = "GetWindowInfo", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool GetWindowInfo(IntPtr hwnd, [MarshalAs(UnmanagedType.LPStruct)] tagWINDOWINFO pwi);
From the MSDN documentation for GetWindowInfo function:
BOOL WINAPI GetWindowInfo(
_In_ HWND hwnd,
_Inout_ PWINDOWINFO pwi
);
EDIT:
As mentioned in the comments to the answer, the first code example is correct. The second code block is incorrect because passing by pointer and passing by reference are different and reflect a fundamental misunderstanding on my part. I was thinking of C++ dereferencing. See this question for more.
Yes, you should use the ref keyword for the struct.
First, there's a really great resource for P/Invoke definitions that you can find at www.pinvoke.net - and the particular method you're dealing with is documented here: http://www.pinvoke.net/default.aspx/user32.getwindowinfo. You'll see that it's defined using the ref keyword. This makes sense when you consider that the method is documented as _Inout_ for that parameter in the MSDN docs you linked.
The reason for this is that the ref keyword will allow that reference to be passed and have the struct you're dealing with before calling the method get updated/modified - rather than passing it in as is and never getting to see what the method actually does to it. In other words, without the ref keyword, your code would never see changes to the struct made within the GetWindowInfo call - GetWindowInfo would be working with its "own" copy of that structure.
If you want to read a bit more about why your second version wouldn't work, check out JaredPar's great explanation to What is the difference between a C# Reference and a Pointer?

typedef void* alternative in c#

I am using DLL runtime which is made with C language into C#.
I came across below statement.
typedef void *JCCP_PROPERTY_HANDLE;
In function it is being used as:
JCCP_RESULT __JCCP_FUNCTION__ jccpGetProperty(
JCCP_HANDLE hjccp,
const char *name,
JCCP_PROPERTY_HANDLE *phproperty);
Now I want to call jccpGetProperty() method in my C# code.
Can anybody tell how can I pass third parameter(JCCP_PROPERTY_HANDLE *phproperty) to function from C#.
I tried with below code but not working.
Extern Method:
[DllImport(DLL_NAME, EntryPoint = "_jccpGetProperty", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr jccpGetProperty(IntPtr hjccp, string name, ref IntPtr JCCP_PROPERTY_HANDLE);
Usage
IntPtr handle = IntPtr.Zero;
string tag = "server.version";
var result = jccpGetProperty(hjccp, tag, ref handle);
Can anybody help me in this?
IntPtr is the correct type mapping for void*. The native type void* is generally used for an opaque pointer, and that is mapped to IntPtr in C#.
Those parts of the p/invoke declaration that we can verify are correct. The unverifible parts are:
The calling convention. You believe that it is cdecl, but we can't check.
The return type. You believe it to be pointer sized. Again we cannot check. My guess is that a 32 bit integer, int or uint is more likely. That would make a difference in a 64 bit process.
The values passed to the function. It's perfectly possible that the function is declared correctly, but you are passing invalid values.
Because you only showed partial code and details, it's hard to say much more. You will have to verify all the parts of the program that we cannot.
I suggest that you start with working C or C++ code and translate that, looking for the first point of deviation in behaviour between that code and your C# translation.

Constraints vs abstract class using SafeHandle

There is a method within BCryptNative called GetInt32Property.
It has the following signature:
internal static int GetInt32Property<T>(T algorithm, string property) where T : SafeHandle
This method only works when T is of type SafeBCryptAlgorithmHandle or SafeBCryptHashHandle. It calls native methods which are explicitly defined with those types of handles:
[DllImport("bcrypt.dll", EntryPoint = "BCryptGetProperty", CharSet = CharSet.Unicode)]
internal static extern ErrorCode BCryptGetAlgorithmProperty(SafeBCryptAlgorithmHandle hObject,
string pszProperty,
[MarshalAs(UnmanagedType.LPArray), In, Out] byte[] pbOutput,
int cbOutput,
[In, Out] ref int pcbResult,
int flags);
[DllImport("bcrypt.dll", EntryPoint = "BCryptGetProperty", CharSet = CharSet.Unicode)]
internal static extern ErrorCode BCryptGetHashProperty(SafeBCryptHashHandle hObject,
string pszProperty,
[MarshalAs(UnmanagedType.LPArray), In, Out] byte[] pbOutput,
int cbOutput,
[In, Out] ref int pcbResult,
int flags);
Microsoft uses function pointers / delegates to point to the correct native function. My question is, why didn't Microsoft just implemented the GetInt32Property method with the following signature:
internal static int GetInt32Property(SafeHandle algorithm, string property)
with the following native method:
[DllImport("bcrypt.dll", CharSet = CharSet.Unicode)]
internal static extern ErrorCode BCryptGetProperty(SafeHandle hObject,
string pszProperty,
[MarshalAs(UnmanagedType.LPArray), In, Out] byte[] pbOutput,
int cbOutput,
[In, Out] ref int pcbResult,
int flags);
Are there any downsides to this? (assuming that the SafeHandle passed to GetInt32Property is always either a SafeBCryptAlgorithmHandle or SafeBCryptHashHandle).
I'm just wondering about why Microsoft implemented this so relatively complicated.
Does it have to with:
Security-Transparent Code?
Type safety? (So that you never use any other than those two types)
Is it allowed to use SafeHandle explicitly?
According to the documentation the class must be inherited, and it is, however does a P/Invoked function handle it properly when given an abstract class of SafeHandle? Does it increment and decrement the reference counts appropriately?
It's hard to tell why Microsoft chose to implement something in one way or another, but I can answer your points.
The code isn't complex. The usage is clear (something like GetInt32Property(algorithm, str).
It doesn't force you to send one of the types you mentioned, you can still call it with a different class, as long as it implements SafeHandle.
The native methods that are used are actually the same. This is kind of odd, but I'm not an expert on this specific library so it may be for a good reason.
There's a hidden benefit for generic methods like this one. The typeof(T) == typeof(SafeBCryptHashHandle) type checks are not done in runtime, but in JIT time. This means that the method should perform slightly faster then a regular runtime check like algorith is SafeBCrypthHashHandle.
The SafeHandle class is an abstract class. This means that you cannot create an instance of it, but you can inherit it. The native function only get marshaled data, they don't get real references to objects. Don't worry about reference counting.

Proper calling convention of unmanaged DLL function

I'm trying to write a bare-bones ultra-simple light-weight wrapper for the LibVLC DLL Library. I don't need access to much, just the ability to play pause and stop media files. I'm looking at the documentation and this other link I found that explains an older version of LibVLC, but it's outdated for the most recent version. I also tried LibVLC.Net but it too is outdated and I can't find what I'm looking for in the source code to match it to the functions I'm trying to export.
I have the following signature I'm trying to export:
libvlc_new (int argc, const char *const *argv)
The description:
argc the number of arguments (should be 0)
argv list of arguments (should be NULL)
And this is the method I'm trying.
[DllImport("libvlc", EntryPoint = "libvlc_new")]
public static extern IntPtr New(Int32 argc, String[] argv);
The description suggests it should be an array, and I think the problem is the second argument. I've tried:
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] String[] argv
as according to here, and there are a couple of other options such as a String and StringBuilder as suggested here but it still happens that every time I call the function I get an Imbalanced PInvoke stack.
I need to know what the proper calling convention of this, and very likely several other, functions are. A "PInvoke For Dummies" online reference would be super good.
Not much point in declaring the argument type if only NULL is permitted. Just declare it IntPtr and pass IntPtr.Zero.
The debugger is pointing out that you forgot to declare the CallingConvention. It is not the default for .NET, this is a __cdecl function. So the proper declaration would be:
[DllImport("libvlc", EntryPoint = "libvlc_new",
CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr New(int argc, IntPtr argv);
Called as:
New(0, IntPtr.Zero);
Do try to pick a better name...

PInvoke in 64bit .net app through c++ 64 bit dll

I'm having an issue calling a function in a c++ dll inside of a c# app. I'm calling the function inside of c# like so:
[DllImport("cryptopp.dll")]
public static extern IntPtr RSAEncryptString(string filename, string seed, string message);
It is being exported in the c++ dll as shown below.
extern "C" __declspec(dllexport) const char* __cdecl RSAEncryptString(const char *pubFilename, const char *seed, const char *message);
What I get when I try to call this, however, is an "An External component has thrown an exception." exception, which is not very descriptive at all, and extremely unhelpful.
When I pull up the dll in an export viewer, it shows all the other exported functions with fully quantified declarations (I.E. public: void __cdecl CryptoPP::X509PublicKey::`vbase destructor'(void) __ptr64 ) , except for the function I am calling, which just displays the function name RSAEncryptString.
This is the only possible issue I can see, besides maybe mis-calling the function with an invalid declaration on the c# side. Am I using System.Runtime.InteropServices.Marshal wrong?
Please help <3 and thanks in advance.
I think you need to change the first line to:
[DllImport("cryptopp.dll",
CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
If you want to get very descriptive, you can also add these:
public static extern IntPtr RSAEncryptString(
[In, MarshalAs(UnmanagedType.LPStr)] string filename,
[In, MarshalAs(UnmanagedType.LPStr)] string seed,
[In, MarshalAs(UnmanagedType.LPStr)] string message);
IIRC think the CharSet should take care of the encoding thing for you, but if it doesn't, use the MarshalAs also, as shown above.
Edit:
Oh I think I got why you still get an error! Your code still had the above problems, but it's still erring because you can't return a string object since it's not a managed object; you need to return a pointer (like IntPtr) and then use Marshal.PtrToStringAnsi!
(I didn't really look at your return type when answering this at first.)
It appears you're trying to store the return value of type const char * (an LPCSTR) into an IntPtr type (usually used for HANDLEs, not LPSTRs.) Try this:
[DllImport("cryptopp.dll", CharSet = CharSet.Auto)]
public static extern String RSAEncryptString(String filename, String seed, String message);
Also keep in mind that if any argument is getting written to, you'll need to add out before its type, i.e. ..., out String message)

Categories

Resources