最近做了一个C++项目,尝试使用了C#中创建图片的函数,因项目的特殊性C++项目属性只能为非托管,所以采用了C++调COM的方式来做。COM方式的优点是简单,缺点是需要在客户机上注册COM才能使用。经过一番折腾,最终实现了本地和客户机都能正常运行。在此做一点小的总结,让有需要的人少走弯路。
(1) 创建C#接口类库DLL;
using System;
using System.Runtime.InteropServices;
using System.Drawing;
namespace MyCOM
{
[ComVisible(true)]
[Guid("749F6942-1FBE-4039-935F-68232465B819")]
public interface IMyCSharp //定义接口
{
[DispId(1)]
string CreatBMP(int x, int y, out string outstr);
}
[ComVisible(true)]
[Guid("4E0FDBB5-C055-4A0E-92CE-0FB3B4912D71")]
[ClassInterface(ClassInterfaceType.None)]
public class MyCSharp : IMyCSharp //接口实现
{
public void CreatBMP(string bitmapPath, int width, int height, int[] pixels)
{
Bitmap bmp = new Bitmap(width, height);
for (int i = 0; i < bmp.Width; i++)
for (int j = 0; j < bmp.Height; j++)
{
Color c = Color.FromArgb(pixels[j * bmp.Width + i]);
bmp.SetPixel(i, j, c);
}
bmp.Save(bitmapPath, System.Drawing.Imaging.ImageFormat.Bmp);//指定图片格式
bmp.Dispose();
}
}
}
1.1项目属性无特殊指定。因本人项目的特殊性,所以选择了低版本的.NET Framework2.0框架
1.2编译生成MyCOM.tlb和MyCOM.DLL两个文件,将MyCOM.tlb复制到C++工程项目中。
(2)创建C++项目
#include <iostream>
#include <string.h>
#import "MyCOM.tlb"//导入COM库
...
...
...
//通过C#COM创建图片
void CreateImageByCsharp(string bmpfile, int x, int y, ::vector<int>pixels)//通过COM访问C#函数
{
CoInitialize(NULL);//初始化COM
MyCOM::ImyClassPtr pTR;
HRESULT hr = pTR.CreateInstance(__uuidof(MyCOM::myClass));
if (hr == S_OK)
{
int px_conut= (int)pixels.size();
SAFEARRAY *pSA = SafeArrayCreateVector(VT_INT, 0, px_conut);//将VECTOR转换为SAFEARRAY
for (long i = 0; i < npix; ++i)
SafeArrayPutElement(pSA, &i, &pixels[i]);
pTR->CreatBMP(bmpfile.c_str(), x, y, pSA);//调用COM实现BMP文件的创建
pTR->Release();
}
CoUninitialize();//释放COM
}
...
...
...
void main()
{
...
int xx, yy;
std::vector<int > mpixels;
...
...
...
CreateImageByCsharp("c:\\abc.bmp",xx, yy, mpixels);
...
...
...
}
编译生成C++ exe文件,将MyCOM.DLL复制到C++ 生成的exe文件夹中
(3) 注册COM组件
3.1将开发C# dll所使用.NET Framework版本一致的RegAsm.exe 复制到C++生成的 exe文件夹中。
3.2创建批处理文件,内容如下:
@echo off
RegAsm MyCOM.dll /codebase
3.3运行批处理即可注册成功。在客户机上同样需要注册才能正常使用,这是COM的特性所在。
ps.(此操作可以在C++程序中调用宏ShellExecute实现自动注册,此处略。。)