Login | Register   
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Dealing with DllImport (Part 1 of 2)  : Page 2

Although the .NET framework encapsulates a large portion of the Win32 API, it's sometimes still necessary to call the API from your managed code using the DllImport attributeand that can get complicated.


advertisement
I tried a dozen different things to get this to work, wasting most of a day, and finally asked an expert for help. Before looking at the answer, you might want to see if you can spot my mistake.

The expert told me how to write the DLLImport correctly (well, almost correctly) off the top of his head, and then asked, by the way, was there any special reason why I wasn't using the System.Environment.Username property. Well, duh! I'd completely overlooked the System.Environment class in the .NET Framework, which provides all the information I happened to want for that part of my program.

Even though I wound up using the System.Environment class in my program, it's useful to look at the full, correct P/Invoke call to GetUserName:

using System; using System.Runtime.InteropServices; using System.Text; namespace TestGetUserName { class Class1 { [DllImport("advapi32.dll")] public static extern bool GetUserName (StringBuilder lpBuffer, ref int nSize); [STAThread] static void Main(string[] args) { StringBuilder b=new StringBuilder(100); int n=b.Capacity; bool rc=GetUserName(b, ref n); Console.WriteLine(b); } } }

What's changed? Two things: one that matters, and one that doesn't matter quite so much. The one that matters is that the second argument to GetUserName needs to be a reference in C#, since the underlying API calls for an LPDWORD, in other words for a pointer to a DWORD.

What was the other change? The best C# type to use for the LPTSTR lpBuffer argument of the underlying API call is a StringBuilder, not a Byte[]. The StringBuilder returned is directly usable as a string; the Byte[] would have to be explicitly converted.

If I'd had more experience with DllImport, I might have realized that the System.NullReferenceException I got originally was telling me that it needed a reference type where I was passing a value type. Of course, the bug wasn't where I was looking, because I was looking at the wrong place.

There's a rule or three you can take away from this example. The first rule is that a Win32 pointer type translates to a corresponding .NET reference type. The second rule is that a Win32 string pointer generally translates to a .NET StringBuilder type (or, sometimes, to a String type). The third rule is to look for a pointer/value mismatch if you get a System.NullReferenceException from a P/Invoke call.



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap