Guys,
Maybe this is a small example that shows how it works with PCall.
Please note that no String2psz() is needed anymore in the PCall because the .Net runtime takes care of that. Also the DLL prototypes now use STRING and ANSI, so the .Net runtime takes care of the converison as well.
Code: Select all
//
// compile with options: /dialect:vo /r:xsharp.core.dll /r:xsharp.vo.dll /vo6 /unsafe
// can compile with AnyCPU as long as you use the X# runtime
//
_DLL FUNCTION LoadLibrary( lpLibFileName AS STRING ) AS PTR PASCAL:KERNEL32.LoadLibraryA ANSI
_DLL FUNCTION FreeLibrary( hModule AS PTR ) AS VOID PASCAL:KERNEL32.FreeLibrary
_DLL FUNCTION GetProcAddress( hModule AS PTR, lpProcName AS STRING ) AS PTR PASCAL:KERNEL32.GetProcAddress ANSI
FUNCTION MyMessageBox( hOwner AS PTR, cMessage AS STRING, cMessage2 AS STRING, nOption AS DWORD) AS DWORD
RETURN 0
FUNCTION Start() AS VOID
LOCAL hModule AS PTR
LOCAL hFunc AS MyMessageBox PTR
hModule := LoadLibrary( "user32.dll" )
hFunc := GetProcAddress( hModule, "MessageBoxA" )
? "MessageBox() returns", PCall( hFunc, NULL, "Hello from XSharp", "PCall() From XSharp", 3 )
FreeLibrary( hModule )
RETURN
The compiler generates a delegate from the MyMessageBox prototype (C# syntax, because ILSpy in X# mode does not show the special $ characters in the names)
Code: Select all
internal unsafe delegate uint $PCall$Start$0(void* hOwner, string cMessage, string cMessage2, uint nOption);
Similar code will be generated for every PCall.
And a special method to request the delegate from the function pointer. If you have more than one PCall then this method will be reused:
Code: Select all
internal static T $PCallGetDelegate<T>(IntPtr p)
{
return (T)(object)Marshal.GetDelegateForFunctionPointer(p, typeof(T));
}
And the relevant code in the Start() function looks like this:
Code: Select all
public unsafe static void Start()
{
void* hModule = LoadLibrary("user32.dll");
IntPtr hFunc2 = (IntPtr)GetProcAddress(hModule, "MessageBoxA");
Functions.QOut("MessageBox() returns", $PCallGetDelegate<$PCall$Start$0>(hFunc2)(null, "Hello from XSharp", "PCall() From XSharp", 3u));
FreeLibrary(hModule);
hFunc2 = (IntPtr)(void*)null;
}
And remember: if you think this is difficult to understand, it was even more difficult to implement this. But it works !
Robert