在本机代码中通过 COM 使用 F#

在本机代码中通过COM 使用 F#

虽然大多数情况下,我们可能希望从 F# 代码调用本机代码,但是,在某些情况下,也可能想从本机代码中调用 F# 库函数。例如,假设我们有一个大型的程序是用 C++ 写的,有可能希望用户界面保持用 C++,而把一些逻辑,比如执行复杂数学计算的部分迁移到 F#,以方便维护。在这种情况下,我们就要从本机代码中调用 F# 了。简单的方法是借用.NET 提供的工具,为我们的 F# 程序集创建 COM 包装;然后,使用COM 运行时从 C++ 中调用 F# 函数。

要通过 COM 公开函数,需要用特殊方法进行开发。首先,必须定义接口,为函数指定契约,接口的成员必须使用命名参数(参见本章前面的“C# 中调用 F# 库”一节),接口本身使用 System.Runtime.InteropServices.Guid特性来标记;然后,必须提供一个类来实现这个接口,这要用System.Runtime.InteropServices.Guid 和System.Runtime.InteropServices.ClassInterface 特性进行标记,还应该总是把 ClassInterfaceType.None枚举成员传递给
ClassInterface 特性的构造函数,说明没有接口应该自动生成。

我们来看一下示例是如何做的。假设我们想公开两个函数Add 和 Sub 给非托管的客户端,需要在命名空间Strangelights 下创建接口IMath,然后,创建类 Math 实现这个接口,还需要保证类和接口用适当的特性进行标记。最后的代码可能像这样:

namespaceStrangelights

open System

open System.Runtime.InteropServices

// define an interface(since all COM classes must

// have a seperateinterface)

// mark it with afreshly generated Guid

[<Guid("6180B9DF-2BA7-4a9f-8B67-AD43D4EE0563")>]

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

[<Guid("B040B134-734B-4a57-8B46-9090B41F0D62");

ClassInterface(ClassInterfaceType.None)>]

typeMath() =

interface IMath with

memberthis.Add(x, y) = x + y

memberthis.Sub(x, y) = x - y

函数 Add 和 Sub很简单,因此,直接在 Math 类的主体中实现,自然没有问题;但是,如果需要把它们拆分到类之外的其他助理函数,也不会有问题,可以用自己觉得合适的任何方法实现类成员,都行,只需要提供接口和类,这样,COM 运行时就能够在代码中有一个入口点。

下面是这个过程中公开的最复杂的部分,注册程序集,使 COM 运行时能找到它。这是通过使用工具RegAsm.exe 实现的。假设我们把前面的示例代码编译成的 .NET .dll 通过OM  需要保证类的s 叫 ComLibrary.dll,那么,需要调用 RegAsm.exe两次,使用下面的命令:

regasm comlibrary.dll /tlb:comlibrary.tlb

regasm comlibrary.dll

第一次创建类型库文件 .tlb,它是能够用于开发的 C++ 项目中的;第二次是注册程序集,使 COM 运行时能够找到它;这两个步骤还需要在分发程序集的机器上运行。

C++ 调用 Add 函数是这样的,开发环境以及如何设置 C++ 编译器都会对代码的编译产生影响。在这里,我们创建的Visual Studio 项目,选择了控制台应用程序模板,并启用了 ATL。注意,下面是有关源代码的描述:

#import 命令告诉编译器需要导入我们自己的类型库,可能需要使用文件(.tlb)的完整路径;编译器还将自动生成一个头文件,在这里是comlibrary.tlh,文件的位置在debug 或 release 目录下。它的作用是让我们知道类型库中可用的函数和标识符;

然后,需要初始化 COM 运行时,这是通过调用CoInitialize 函数实现的;

接着,需要声明一个指针,指向我们创建的接口 IMath,这是通过代码comlibrary::IMathPtr pDotNetCOMPtr; 完成的。注意,命名空间是来自库的名字,而不是 .NET 的命名空间;

下一步,需要创建 Math 类的实例,这是通过调用CreateInstance 方法完成的,把 Math 类的GUID 传递给它。幸运的是,为此目的,有一个常量定义;

如果这些都成功了,就能名调用 Add 函数了。注意,函数的返回返回dd 目的,有一个常量这 r pDotNetCOMPtr; 实际上是 HRESULT,这个值告诉我们调用是否已经成功,而实际的实际结果是通过一个输出参数传出来的。

// !!! C++ Source !!!

#include "stdafx.h"

// import the meta data about out.NET/COM library

#import "..\ComLibrary\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 result was: 3

当我们运行最后的程序时,必须保证ComLibrary.dll 与程序在同样的目录中,否则,COM 运行时会找不到文件。如果打算让这个库被多个客户端使用,那么,我强烈建议对程序集签名,并放在全局程序集缓存(Global Assembly Cache,GAC)中,这样,所有的客户端都能找到它,就不必要在第一个目录下都复制一份。

在本机代码中通过 COM 使用 F#

时间: 2024-12-18 02:32:41

在本机代码中通过 COM 使用 F#的相关文章

Linux中的命令 make -f 是什么意思

出处:http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece7631046893b4c4380146d96864968d4e414c42246091d21a8e07b770703a79b273b46e5540faab66d2369543de1cc8edb1183fa8f2d2d832735761892044f934fa0951d79866a875a98b86fe3ad863084afa2c4af5344bb55127bf0afd803570

C中的%d,%o,%f,%e,%x的区别

C中的格式字符有d,o,x,u,c,s,f,e,g等,之前有看到其中某些可以大写(待确定). 如: %d整型输出,%ld长整型输出, %o以八进制数形式输出整数, %x以十六进制数形式输出整数, %u以十进制数输出unsigned型数据(无符号数). %c用来输出一个字符, %s用来输出一个字符串, %f用来输出实数,以小数形式输出, %e以指数形式输出实数, %g根据大小自动选f格式或e格式,且不输出无意义的零. c语言中以16进制输出时%0x和%x有什么区别? 标准C语言库函数fprintf

eclipse中的Ctrl+Shift+F快捷键和Ctrl+D快捷键失灵

Ctrl+Shift+F快捷键失灵: 有可能是因为你的搜狗输入法那里的快捷键也有一个Ctrl+Shift+F,造成冲突了,这时你可以把搜狗输入法里面的快捷键改一下就可以了. 在"开始"那里找到"搜狗拼音输入法"-->"设置" 在这里换一个快捷键就可以了,或者取消此快捷键,就可以了. Ctrl+D快捷键失灵: 这时候可能是和eclipse的workspace中的 ".metadata" 文件有关,我那时候是先把eclips

【Linux】命令写在文件中并调用awk -f

我们在使用awk命令的时候,有时候命令特别长,在终端写出来格式太乱,难以阅读,以下是一个将命令写在文件中,并使用awk调用的具体案例 1.现在有文件file3.txt,内容如下: 2.ak2.awk脚本 #打印标题并格式化打印出数量合计 BEGIN { FS="\t" #设置字段分割符 printf("%10s %2s %5s %s\n\n", "Fruits","Num","Price","Pl

PowerDesigner中的P、F、M

P(主键) primary F(外键) foreign M(强制不可为空) mandatory 原文地址:https://www.cnblogs.com/wasi-991017/p/12286881.html

PowerDesigner表设计中的P F M分别代表什么意思?

版本 如下图中的P.F.M代表什么意思呢? P即primary,主键的意思 F即foreign key,外键的意思 M即mandatory,强制不可为空的意思 原文地址:https://www.cnblogs.com/lukefan/p/10217709.html

[Java面试四]Strust2总结及在面试中的一些问题.

1. JavaEE软件三层结构和MVC的区别? JavaEE软件三层机构是由sun公司提供JavaEE开发规范的:Web层(表现层).业务逻辑层.数据持久层.[其中WEB层会使用前端控制器模式] MVC是一种思想,是一种模式,将软件分为 Model模型.View视图.Controller控制器.[JavaEE开发更强调三层结构,web层开发更注重MVC] Struts2 就是web层开发框架,符合MVC模式:struts1 .webwork .jsf .SpringMVC 都是MVC 2. St

struts2与JasperReport整合应用中解决PDF中文不显示问题(让我烦恼了半天)

今天在struts2中以pdf导出JasperReport报表时,遇到了一个很奇怪的问题:在action中获取一些值并且将其放到map中,但是通过$F{name}取值时,有些值能显示,而有些值不能显示,有些值只能显示部分.刚开始还以为是action存放到map中的key和jsper中取到的是不一致的,检查了半天发现并没有问题.这个问题然我郁闷了半天,始终没找到问题所在,由于不知道问题出在哪了,在百度上搜索了半天也没找到解决的办法,无意间看到了一片文章解决了我的问题,下面整理了一下此问题的解决方案

前端开发中经常使用到的20个正则表达式

1 . 校验密码强度 密码的强度必须是包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间. ^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$ 2. 校验中文 字符串仅能是中文. ^[\\u4e00-\\u9fa5]{0,}$ 3. 由数字.26个英文字母或下划线组成的字符串 ^\\w+$ 4. 校验E-Mail 地址 同密码一样,下面是E-mail地址合规性的正则检查语句. [\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$