Thomson-Blog ( 学习,学习,再学习;努力,努力,再努力。)
在学习的路上不断成长,成功之路就在脚下。
用C#编写Com组件供C++调用

近期的北京项目需要将数据提供给用户C++6.0开发的Gis,可难倒我了,底层语言调高级语言??

而且我完全不懂C++,好在北京公司有骨灰级C++高手川总(紫光拼音输入法的设计者)指导,首先在技术可行性上摆平了客户,并写出了相关示例,在此表示感谢。。后来用户嫌调用麻烦,改用方法二。

方法一:直接在Com函数中返回结构体数组(不推荐,因为结构数组映射到Com里成了safearray,相当麻烦)

C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace ComServer
{
    [Guid("53B291E4-785C-4b39-8DAE-F551EABF7FF6")]
    [StructLayout(LayoutKind.Sequential, Pack=1,CharSet=CharSet.Unicode)]
    public struct T_Data
    {
        public int x;
        public int y;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst=128)]
        public char[] name;
    }

    [Guid("2A7151A5-FC77-410a-AB84-287E5E33224C")]
    public interface IDataService
    {
        void GetData(ref T_Data[] data);
    }

    [Guid("6368307B-1412-4d52-A1CD-4E9D01E2C805")]
    [ClassInterface(ClassInterfaceType.None)]
    public class DataService : IDataService
    {
        public void GetData(ref T_Data[] data)
        {
            System.Console.WriteLine("Got data");
            for (int i = 0; i < data.Length; i++)
            {
                data[i].x *= 2;
                data[i].y *= 2;
                data[i].name += "!!!!";
            }
        }
    }
}


C++

#include <iostream>
#include <objbase.h>

#import "..\\ComServer\\bin\\debug\\ComServer.tlb"

using namespace ComServer;
using namespace std;

int main()
{
//初始化Com调用
CoInitialize(NULL);

//获取ComServer服务的指针
IDataServicePtr pI(__uuidof(DataService));

//创建SAFEARRAY
IRecordInfo *rec_info;
int r = GetRecordInfoFromGuids(__uuidof(__ComServer), 1, 0, LOCALE_USER_DEFAULT, __uuidof(T_Data), &rec_info);
if (r != S_OK)
{
   cout << "获取记录类型信息失败\n";
   return -1;
}
SAFEARRAY *psa = SafeArrayCreateVectorEx(VT_RECORD, 0, 2, rec_info);
T_Data *p_data;

//填充数据
r = SafeArrayAccessData(psa, (void**)&p_data);
if (r != S_OK)
{
   cout << "获取记录数组失败\n";
   return -2;
}
p_data[0].x = 1;
p_data[0].y = 2;
strcpy_s((char*)p_data[0].name, sizeof(p_data[0].name), "hello");

p_data[1].x = 3;
p_data[1].y = 4;
strcpy_s((char*)p_data[1].name, sizeof(p_data[1].name), "no hello");

cout << "调用前数据\n";
cout << "第0个元素: x = " << p_data[0].x << ", y = " << p_data[0].y << ", name = " << p_data[0].name << endl;
cout << "第1个元素: x = " << p_data[1].x << ", y = " << p_data[1].y << ", name = " << p_data[1].name << endl;
SafeArrayUnaccessData(psa);

//调用函数
cout << "调用函数,所有的数据将翻倍\n"; //,字符串加上4个惊叹号\n";
r = pI->GetData(&psa);
if (r != S_OK)
{
   cout << "调用COM接口失败\n";
   return -3;
}

//访问最新数据
r = SafeArrayAccessData(psa, (void**)&p_data);
if (r != S_OK)
{
   cout << "获取记录数组失败\n";
   return -4;
}
cout << "调用后数据\n";
cout << "第0个元素: x = " << p_data[0].x << ", y = " << p_data[0].y << endl; //", name = " << p_data[0].name << endl;
cout << "第1个元素: x = " << p_data[1].x << ", y = " << p_data[1].y << endl; //", name = " << p_data[1].name << endl;
SafeArrayUnaccessData(psa);

//释放Com
CoUninitialize();
}

方法二:利用Marshal类将结构体压到内存中,返回指针给C++(推荐,藕合度极低,但C++中的结构体定义必须和C#中一样)

C#

[StructLayout(LayoutKind.Sequential)]
    public struct SystemCode
    {
        public string CodelName;//代码名称
        public string CodeValue;//代码值
        public int SXH;

    }
    [StructLayout(LayoutKind.Sequential)]
    public struct SystemCodeSZ
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
        public SystemCode[] SystemCodeS;
    }

         /// <summary>
        /// 获取代码列表
        /// </summary>

/// <param name="codeSetName">代码类别名称</param>
        /// <param name="syscodesz">指针</param>
        /// <param name="sizeReturn">有效长度</param>
        public void GetSystemCode(string codeSetName,ref IntPtr systemcodesz, ref int sizeReturn)
        {
            SystemCodeSZ sz = new SystemCodeSZ();
            sz.SystemCodeS = new SystemCode[100];

            Hashtable ht = new Hashtable();

                IList<SysCode> listSC = this.SysCodeSetService.FindCodesBySetName(codeSetName);
                foreach (SysCode vo in listSC)
                {
                    ht.Add(vo.CodeValue, vo.CodeName);
                }
            sizeReturn = ht.Count;

            int index = -1;
            IDictionaryEnumerator ie = ht.GetEnumerator();
            while (ie.MoveNext())
            {
                index++;
                sz.SystemCodeS[index].CodelName = ie.Value.ToString();
                sz.SystemCodeS[index].CodeValue = ie.Key.ToString();
            }
            systemcodesz = Marshal.AllocHGlobal(Marshal.SizeOf(sz));//计算数组在内存的长度
            Marshal.StructureToPtr(sz, systemcodesz, false);//将数组写入内存中
        }

C++

struct SystemCode
{
    char* CodelName;
    char* CodeValue;
    long SXH;
};
struct SystemCodeSZ
{
    struct SystemCode SystemCodeS[100];
};

void main(int argc, char* argv[])
{
//初始化Com调用
   CoInitialize(NULL);

KJCom::KJComInterfacePtr ptr(_uuidof(KJCom::KJComService));

long lon;
long sizeReturn;

printf("实例化成功\r\n");

//获取代码集
ptr->GetSystemCode("armyLevel",&lon,&sizeReturn);
SystemCodeSZ* scsz = (SystemCodeSZ*)lon;

   printf("获取数据成功\r\n");

CoUninitialize();
//scanf("%s");
//return 0;
}

posted on 2011-03-08 09:26  Thomson-Blog  阅读(379)  评论(0编辑  收藏  举报