Links

Safe and Unsafe Methods Layer

Win-API

The Microsoft Windows application programming interface (Win API):
  • Allows calls to Windows OS functions directly.
  • All programs interact with the Windows API directly or through some other API.
Many system resources can be managed using this API.
Applications employ them to perform special functions not available from the programming language natively:
  • Working with the Windows registry.
  • Interacting directly with the user interface.
Implemented in several DLLs that reside on the Windows folder, such as kernel32.dll, advapi32.dll, user32.dll, etc.
These libraries contain what is called unmanaged code in .NET: code that is compiled directly to a binary that can be executed directly in the CPU.
The .NET platform provides the Platform Invocation Services also known as "PInvoke" to interact with unmanaged code from a managed environment.
The VBUC (migration tool) identifies all Windows API calls in the original VB6 code and translates them into their corresponding "PInvoke" signature:
Original VB6 Code
Private Declare Function RegQueryValueEx Lib "advapi32.dll" Alias "RegQueryValueExA" (ByVal hKey As Long, ByVal lpValueName As String, ByVal lpReserved As Long, lpType As Long, ByVal lpData As Long, lpcbData As Long) As Long
Upgraded C# Code
[DllImport("advapi32.dll", EntryPoint = "RegQueryValueExA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
extern public static int RegQueryValueEx(int hKey, [MarshalAs(UnmanagedType.VBByRefStr)] ref string lpszValueName, int dwReserved, ref int lpdwType, System.IntPtr lpbData, ref int cbData);

Code Organization

All the signatures found in the original code are organized by library, resulting in a class per library.
  • The code is better organized.
  • The original definitions are commented out.
  • The required interoperability data-type marshalling is generated.
  • The error handling is added for the upgraded API calls.
  • The correct data types for pointer-type parameters are generated.
PInvoke Classes
Example for the advapi32 class
namespace CompendiaSupport.PInvoke.UnsafeNative {
[System.Security.SuppressUnmanagedCodeSecurity]
public static class advapi32 {
[DllImport("advapi32.dll", EntryPoint = "RegQueryValueExA",
CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
extern public static int RegQueryValueEx(int hKey,
[MarshalAs(UnmanagedType.VBByRefStr)] ref string
lpszValueName, int dwReserved, ref int lpdwType, System.IntPtr lpbData, ref int cbData);
}
}
namespace CompendiaSupport.PInvoke.SafeNative {
public static class advapi32 {
public static int RegQueryValueEx(int hKey, ref string
lpszValueName, int dwReserved, ref int lpdwType, ref int lpbData, ref int cbData) {
int result = 0;
GCHandle handle = GCHandle.Alloc(lpbData, GCHandleType.Pinned);
try {
IntPtr tmpPtr = handle.AddrOfPinnedObject();
CompendiaSupport.PInvoke.UnsafeNative.advapi32.RegQueryValueEx(hKey, ref lpszValueName,
dwReserved, ref lpdwType, tmpPtr, ref cbData);
lpbData = Marshal.ReadInt32(tmpPtr);
}
finally {
handle.Free();
}
return result;
}
}
}

Looking for alternatives?

Microsoft provides an article with a list of Windows API functions and their mappings to .NET.
In the summary, they explicitly say that: "This article identifies the Microsoft .NET Framework version 1.0 or 1.1 APIs that provide similar functionality to Microsoft Win32 functions."
The replacement of API functions with .NET alternatives should be done on a case-by-case basis.
  • Imports of the required namespaces are needed.
  • Can require modification on the method's logic.
  • Creation of new objects
  • Calling of the new method(s).
  • How to retrieve the return value.
Example for the RegQueryValueEx method:
Win32 function
Description
.NET Framework API
RegQueryValueEx
Retrieves the type and data for a specified value name associated with an open registry key.
Microsoft.Win32.RegistryKey.GetValue