近期的北京项目需要将数据提供给用户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;
}