1.概要
起因:
c++ 中使用c#的dll,如果使用的工程支持clr是没有问题的,但是如果不支持,就只能是用com方式。因为c++实现一个代理的http服务很麻烦,而用c#确很容易。这时候我就想用c#实现http代理的这部分功能,然后给c++工程提供接口。结果做完了确发现工程不支持 clr。这下麻烦了,原来的工程不能改只能改这个dll了。
知识概要:
#import "../ClassLibrary2/bin/Debug/ClassLibrary2.tlb"
using namespace ClassLibrary2;
CoInitialize(NULL);
ClassLibrary2::Interface1Ptr CalcPtr(__uuidof(Class1));//获取Calc所关联的GUID
int ret = CalcPtr->add(a,b);
CalcPtr->Release();
std::cout << ret;
CoUninitialize();
知识点分析(我把关键的关系体系出来,剩下的api什么的想你猜也知识是什么用途)
2.代码
dll代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace ClassLibrary2 {
[Guid("E379D41B-CAA9-4DC4-934D-AE86EDC2BB47")]
public interface Interface1
{
[DispId(1)]
int add(int a, int b);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace ClassLibrary2
{
[Guid("12DF130B-DF7B-43A2-BEE7-F9AD4EDE385D")]
[ClassInterface(ClassInterfaceType.None)]
public class Class1 : Interface1
{
public int add(int a, int b)
{
return a + b;
}
}
}
控制台代码
// ConsoleApplication3.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#import "../ClassLibrary2/bin/Debug/ClassLibrary2.tlb"
using namespace ClassLibrary2;
int main()
{
int a = 1;
int b = 2;
std::cout << "Hello World!\n";
CoInitialize(NULL);
ClassLibrary2::Interface1Ptr CalcPtr(__uuidof(Class1));//获取Calc所关联的GUID
int ret = CalcPtr->add(a,b);
//CalcPtr->Release();
std::cout << ret;
CoUninitialize();
}
3.运行结果
4.设置方法
4.1创建c# dll 的要求
4.1.1 是程序集com可见
4.2 为com互操作注册
4.2.1 vs 自动注册
4.3 注册dll
4.2.1 手动注册
regasm xxx.dll /tlb
regasm 命令无效,可以进入regasm.exe 所在的目录执行,且 regasm 目录/xxx.dll /tlb
4.3 com方式调用。
这种调用方式就是将dll转换成类com组件的方式调用。
直接看方法:C++ 调用C#dll不是直接调用dll, 而是调用一个转变后的文件:.tlb文件的支持
tlb文件:com类型库文件,它包含接口相关信息。在需要使用对应com类的模块里,通过"#import xxx.tlb"来调用。
在C++代码中使用: #import "../../out/debug/TGPDFSignLib.tlb"
这个.tlb文件会对应的生成tgpdfsignlib.tli 和 tgpdfsignlib.tlh两个文件。
在VC下#import "TGPDFSignLib.tlb" no_namespace;编译后产生TGPDFSignLib.tlh和TGPDFSignLib.tli两个文件,不生成namespace,如果没有no_namespace,则生成的内容都在namespaceTGPDFSignLib中。
如果dll中含有tlb资源,则也可以使用#import "xxx.dll"来生成tlh和tli文件,一般的c++ dll不能使用#import "xxx.dll"。
那么tlh、tli文件是什么?
tlh、tli文件是vc++编译器解析tlb文件生成的标准c++文件。因为tlb并不是C++标准的东西,有必要把它们翻译成标准的C++类型,使得C++开发者可以使用。tlh相当于类型申明(头文件),tli相当于定义实现(CPP文件,inline)。
当写到这里时所有的调用已经完成,你已经可以通过这种方法调用C#dll了。
但是有一个问题,我们需要通过.tlb文件调用,那么.tlb文件从哪来的呢???
5.补充说明
5.1 com方式调用dll的步骤
1.用xxx.dll生成xxx.tlb,有两种方法。
- 命令注册
- vs工具直接生成
2.引用xxx.tlb,生成xxx.tlh、xxx.tli。(※1,※2)
#import "../ClassLibrary2/bin/Debug/ClassLibrary2.tlb"
using namespace ClassLibrary2;
※1:tlh、tli文件:是vc++编译器解析tlb文件生成的标准c++文件。因为tlb并不是C++标准的东东,有必要把它们翻译成标准的C++类型,使得C++开发者可以使用。tlh相当于类型申明(头文件),tli相当于定义实现(CPP文件,inline)
※2:如果dll中含有tlb资源,则也可以使用#import "xxx.dll"来生成tlh和tli文件。一般的c++ dll不能使用#import "xxx.dll"
3.调用接口使用dll。
CoInitialize(NULL);
ClassLibrary3::Interface1Ptr CalcPtr(__uuidof(Class1));//获取Calc所关联的GUID
int ret = CalcPtr->add(a, b);
CalcPtr->Release();
std::cout << ret;
CoUninitialize();