RAD Studio for Microsoft .NET
Virtual Library Interfaces

This topic describes how to use a feature of Delphi called Virtual Library Interfaces. Virtual Library Interfaces allows you to discover, load, and call unmanaged code at runtime, without the use of the DllImport attribute.

To call an unmanaged function from managed code, you must use a .NET service called Platform Invoke, or PInvoke. The Platform Invoke service requires you to declare in source code, a prototype for each unmanaged function you wish to call. You can do this either within an existing .NET class, or you can create an entirely new class to organize the prototypes. You must also tag each unnamaged prototype declaration with the DllImport attribute. 

The DllImport attribute requires you to specify the name of the DLL in which the unmanaged function resides. Since the unmanaged prototype is tagged with the DllImport attribute at compile-time, dynamic discovery of DLLs and their exported unmanaged functions is difficult. Furthermore, if the unmanaged function is not actually exported from the DLL named in the DllImport attribute, a runtime failure will result. To avoid a runtime failure, you would have to use LoadLibrary to load the exact DLL you require, and then call GetProcAddress to verify the existance of the unmanaged function. Even so, you would not be able to directly call the function using the pointer returned from GetProcAddress. Instead you would have to pass the pointer along to a function in another unmanaged DLL. That function would then use the pointer to make the call.

Virtual Library Interfaces still must use the Platform Invoke service to call unmanaged code. However, instead of using the DllImport attribute, Virtual Library Interfaces creates an interface on the unmanaged DLL at runtime, using methods of the .NET System.Reflection.Emit namespace.  

Using Virtual Library Interfaces requires that you do three things:

  • Add Borland.Vcl.Win32 to the uses clause.
  • Declare an interface containing the exported, unmanaged functions you wish to call.
  • Call the Supports function to ensure that the unmanaged DLL exists and that the functions in the interface declaration are actually exported.
If the Supports function returns True, then the DLL supports all of the functions named in the interface declaration, so you know it is safe to call them. Within the interface declaration, you do not need to use the DllImport attribute on the prototypes. 

For example, if you have a DLL called MyFunctions.dll, that contains the following exported functions:

function AFunction       : Boolean;
function AnotherFunction : Boolean;

To call these functions from managed code, add the Borland.Vcl.Win32 unit to the uses clause and declare an interface in Delphi:

uses Borland.Vcl.Win32, ...;
IMyFunctions = interface
['Your GUID'] // Not strictly required, but good practice
function AFunction       : Boolean;
function AnotherFunction : Boolean;

The signature of the Supports function is:

function Supports(ModuleName: string; Source: System.Type; var Instance) : Boolean;

To call the unmanaged functions, first call Supports to load the DLL, and create the interface on the DLL:

MyFunctions : IMyFunctions;
  if Supports("MyFunctions.dll", IMyFunctions, MyFunctions) then
     if MyFunctions.AFunction then 

Virtual Library Interfaces have the same limitations in terms of compatible native parameter types and their mapping to .NET types. In addition, all unmanaged functions are expected to use the stdcall calling convention.

Copyright(C) 2008 CodeGear(TM). All Rights Reserved.
What do you think about this topic? Send feedback!