Use F # in local code through COM #
Although in most cases, we may want to call the local code from the F # code, in some cases, we may also want to call the F # library function from the local code. For example, if we have a large program written in C ++, we may want the user interface to be maintained in C ++, while taking some logic, for example, the complex mathematical computing part is migrated to F # To facilitate maintenance. In this case, we need to call F # from the local code. The simple method is to use the tool provided by. NET to create COM packaging for our F # Assembly. Then, use COM to call the F # function from C ++ during runtime.
To publish functions through COM, special methods are required for development. First, you must define an interface and specify a contract for the function. The interface members must use the naming parameters (see section "calling F # library in C #" in this chapter ), the interface uses System. runtime. interopServices. guid feature to mark; then, a class must be provided to implement this interface, which should be System. runtime. interopServices. guid and System. runtime. interopServices. the ClassInterface feature should always be marked with ClassInterfaceType. the None enumeration member is passed to the constructor of the ClassInterface feature, indicating that no interface should be automatically generated.
Let's take a look at how the example is made. Suppose we want to expose two functions, Add and Sub, to an unmanaged client, we need to create an IMath interface under the namespace Strangelights, and then create a Math class to implement this interface, you also need to ensure that classes and interfaces are marked with appropriate features. The final code may look like this:
NamespaceStrangelights
Open System
Open System. Runtime. InteropServices
// Define an interface (since all COM classes must
// Have a seperateinterface)
// Mark it with afreshly generated Guid
[ ]
Type IMath =
Abstract Add: x: int * y: int-> int
Abstract Sub: x: int * y: int-> int
// Implement theinterface, the class must:
//-Have an emptyconstuctor
//-Be marked with itsown guid
//-Be marked with theClassInterface attribute
[
ClassInterface (ClassInterfaceType. None)>]
TypeMath () =
Interface IMath
Memberthis. Add (x, y) = x + y
Memberthis. Sub (x, y) = x-y
The Add and Sub functions are very simple. Therefore, it is no problem to implement them directly in the Math class. However, if you need to split them into other assistant functions other than the class, there is no problem either. You can use any method that you think is appropriate to implement class members. You only need to provide interfaces and classes so that the COM runtime can have an entry point in the code.
The following is the most complex part exposed in this process. register the Assembly so that COM can find it during running. This is implemented by using regasm.exe. Let's assume that we need to ensure that the class s is called ComLibrary. dll by compiling the previous sample code into. NET. dll through OM, we need to call RegAsm.exe twice and use the following command:
Regasm comlibrary. dll/tlb: comlibrary. tlb
Regasm comlibrary. dll
Create a Type Library file for the first time. tlb is a C ++ project that can be used for development. The second time is to register the Assembly so that it can be found at the COM runtime; these two steps also need to be run on the machine where the Assembly is distributed.
C ++ calls the Add function. The development environment and how to set the C ++ compiler will affect code compilation. Here, the Visual Studio project we created selects the console application template and enables ATL. Note: The following describes the source code:
# ImpZ finished? Http://www.bkjia.com/kf/ware/vc/ "target =" _ blank "class =" keylink "> vcnQgw/zb71_my9 + kernel + KjrL/kernel + kernel/CvM/CoaPL/LXE1/kernel/4tbQv8nTw7XEuq/K/kernel + examples/WtcSjuzwvcD4KPHA + examples/u/1 bzkysfAtNfUv + examples/zD + 7/examples + examples/samples + 2qNLlo7s8L3A + samples/K /examples/1eIgciBwRG90TmV0Q09NUHRyOyDKtbzKyc/examples + I2luY2x1ZGUg "stdafx. h"
// Import the meta data about. NET/COM library
# Import ".. \ ComLibrary. tlb" named_guids raw_interfaces_only
// The applications main entry point
Int _ tmain (int argc, _ TCHAR * argv [])
{
// Initialize the COM runtime
CoInitialize (NULL );
// A pointer to our COM class
Comlibrary: IMathPtr pDotNetCOMPtr;
// Create a new instance of the Math class
HRESULT hRes = pDotNetCOMPtr. CreateInstance (comlibrary: CLSID_Math );
// Check it was created okay
If (hRes = S_ OK)
{
// Define a local to hold the result
Long res = 0L;
// Call the Add function
HRes = pDotNetCOMPtr-> Add (1, 2, & res );
// Check Add was called okay
If (hRes = S_ OK)
{
// Print the result
Printf ("The result was: % ld", res );
}
// Release the pointer to the math COM class
PDotNetCOMPtr. Release ();
}
// Uninitialise the COM runtime
CoUninitialize ();
}
The running result of the example is as follows:
The result was: 3
When we run the final program, we must ensure that ComLibrary. dll is in the same directory as the program. Otherwise, the file cannot be found during the running of COM. If you want to make this library used by multiple clients, I strongly recommend that you sign the Assembly and put it in the Global Assembly Cache (GAC, all clients can find it, so there is no need to copy it in the first directory.