API callback

Top  Previous  Next

PInvoke > API callback

API function may use callback parameters. In this case not only the parameters of the API function have to be adapted, the parameters of the callback function have to be adapted too. The "EnumSystemLocales" function is such an example:

 

 

type

TFNLocaleEnumProc = Pointer;

 

{$EXTERNALSYM EnumSystemLocales}

function EnumSystemLocales(lpLocaleEnumProc: TFNLocaleEnumProc; dwFlags: DWORD): bool; stdcall;

 

 

implementation

 

function EnumSystemLocales; external kernel32 name 'EnumSystemLocales';

 

 

function EnumLocalesCallback(LocaleID: PChar): Integer; stdcall;

begin

  // ...

end;

 

procedure CallEnum;

begin

  EnumSystemLocales(@EnumLocalesCallback, LCID_SUPPORTED);

end;

 

 

The callback function "EnumLocalesCallback" has a PChar parameter, which becomes the simulated PChar-class in C#. Of course the unmanaged code couldn't do anything with it. Delphi2C# therefore creates a sibling function to "EnumLocalesCallback" with the same name, but with parameters, which are conform with unmanaged code and which can be used to call the original "EnumLocalesCallback" function. By means of the function "Marshall.GetFunctionPointerForDelegate<TDelegate>", the "EnumLocalesCallback" sibling can be converted than to a function pointer, that can be called in the unmanaged code.

 

This is what Delphi2C# makes from the code above:

 

 

public delegate int callback__0([MarshalAs(UnmanagedType.LPStr)] string LocaleID);  // LPWStr manually corrected here

public static int EnumLocalesCallback([MarshalAs(UnmanagedType.LPStr)] string LocaleID) // LPWStr manually corrected here

{

  return EnumLocalesCallback(new PChar(LocaleID));

}

 

 

 

[DllImport(kernel32, SetLastError=true)]

public static extern bool /*stdcall*/ EnumSystemLocales(

                          IntPtr lpLocaleEnumProc,

                          DWORD dwFlags);

 

public static int /*stdcall*/ EnumLocalesCallback(PChar LocaleID)

{

  int result = 0;

  // ...

  return result;

}

 

public static void CallEnum()

{

  EnumSystemLocales(Marshal.GetFunctionPointerForDelegate<callback__0>(EnumLocalesCallback), LCID_SUPPORTED);

}

 

 

 

As template parameter "TDelegate" for "GetFunctionPointerForDelegate<TDelegate>" the delegate "callback__0" is used. "callback__0" just has the signature of the "EnumLocalesCallback" sibling.

 

When "EnumSystemLocales" is called in the managed code, the unmanaged code will call the "EnumLocalesCallback" sibling, which then will call the original 

"EnumLocalesCallback".

 

 

 

 

 

 



This page belongs to the Delphi2C# Documentation

Delphi2C# home  Content