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.