Browse DevX
Sign up for e-mail newsletters from DevX


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

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.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

For example, take the Windows GetPrivateProfileSectionNames API. This function exists in the Win32 API purely for compatibility with 16-bit Windows, so it wasn't a top compatibility priority for the .NET Framework designers. The weird thing about GetPrivateProfileSectionNames is that it returns a flattened array of strings in a single buffer. Each string is terminated by a null character, and the final string is terminated by two nulls in a row.

If you try to import that into .NET using a StringBuffer, you'll get the first string only. If you try to muck with the marshalling, all you're likely to do is to wind up with a corrupted form of the first string.

The weird thing about GetPrivateProfileSectionNames is that it returns a flattened array of strings in a single buffer.
The solution to this dilemma (and a big tip o' the hat to Russell Jones for figuring this out) is to return the strings into a byte array, call GetString from the System.Text namespace to convert that into a single string containing with internal nulls, and finally use the String class's Split method to separate the individual name strings.

As you'll see in the code that follows, we specified the ANSI form of the API function, so that it would work both on the Windows 9x and NT families.

using System; using System.Runtime.InteropServices; using System.Text; namespace ProfileFunctions { class Class1 { // DWORD GetPrivateProfileSectionNames( // LPTSTR lpszReturnBuffer, // return buffer // DWORD nSize, // size of return buffer // LPCTSTR lpFileName // initialization file name // ); [DllImport("kernel32.dll",CharSet=CharSet.Ansi)] static extern uint GetPrivateProfileSectionNamesA( byte[] lpszReturnBuffer, int nSize, String lpFileName); [STAThread] static void Main(string[] args) { byte[] buff=new byte[1024]; GetPrivateProfileSectionNamesA(buff, buff.Length,"win.ini"); String s = System.Text.Encoding.Default.GetString (buff); String[] names=s.Split('\0'); foreach(String name in names) { if(name=="") break; Console.WriteLine(name); } } } }

Essentially the same method will also work in Visual Basic .NET. When you run the downloadable code for this article, you'll get a list of the section names in the current machine's win.ini file. The exact list depends on what's been installed on the machine.

In the next part of this article, I'll discuss how to use the MarshalAs and the StructLayout options to control precisely how the runtime passes data to and from unmanaged code.

Martin Heller is a Web and Windows programming consultant, an author, and a Senior Contributing Editor at BYTE.com. His most recent publicly viewable project is PC Pitstop. You can reach Martin at webmail@mheller.com.
Comment and Contribute






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



Thanks for your registration, follow us on our social networks to keep up-to-date