COM组件开发笔记--字符串数组的传递

COM编程的好处就是可以跨语言,我们公司是用C#做开发的,所以用C++去开发COM组件就可以弥补图形渲染性能上的不足。但COM组件也有它的缺点,就是COM接口本身的调用开销比较大,所以我总结了,使用COM组件最好是通过最少次数的接口调用来达到目的。所以数组的传递就至关重要了。打个最简单的比方,调10000次SetX( double x )花的时间肯定要比一次性把x数组传进去SetX( double[] x )多的多。
    普通的值类型数组比如int[],short[]什么的,这个都好说,COM里都有对应的类型(VTS_PI4 VTS_PI2),而且就算是在C#里也可以用Marshal来分配非托管数组然后传递到COM里去进行操作。但字符串数组不同,它每一项长度都不一样,这给传递带来了一些困难。所以今天主要就说说字符串数组的传递。

    在COM里数组传递要用到一个叫做SAFEARRAY的东东包装一下。但是如果直接用SAFEARRAY进行传递,那么到C#里面的参数类型是IntPtr,还是一个指针,这样就给数据的获取带来不便。后来发现数组传递之前还要用VARIANT这个数据结构把SAFEARRAY再次包装一下,这样数据传到C#里后参数类型是Object,只需要用String[]强转一下就OK了,十分方便。其实我这段描述百度百科里好像也说的挺明白的,可以参考一下:http://baike.baidu.com/view/1907445.htm
    我们可以这样理解,SAFEARRAY就是存放数据的数组,而VARIANT就是一个壳子,就好比C#里装箱的概念一样,把变量变成Object后传递起来会方便一些。说的够多了,下面直接用代码举例了。
    
    首先,如果数组是传入参数的话,调度声明中需要用VTS_VARIANT,函数原型声明中类型是VARIANT*;如果是返回值的话调度声明要用VT_VARIANT,函数原型声明类型是VARIANT(注意不是VARIANT*,和传入参数有点不同,否则到C#里参数类型不是Object而是IntPtr);然后主要说下数组的构造和包装。
    VARIANT AryWarp;
    VariantInit( &AryWarp );
    AryWarp.vt = VT_ARRAY | VT_BSTR;   // 指定壳子是用来包装数组的,并且是字符串数组,注意COM里面字符串就是BSTR,其实就是宽字符串

    SAFEARRAY* psa; 
    SAFEARRAYBOUND bounds = { 10, 0 }; 
    psa = SafeArrayCreate( VT_BSTR, 1, &bounds );   // 这里就是初始化一个长度为10的字符串数组

    然后声明一个字符串数组 BSTR* bstrArray; 并且用SafeArrayAccessData将psa与bstrArray进行绑定(不知道绑定这个词合适不合适,反正给我的感觉就是绑定),然后要做的就是对bstrArray[ i ]赋值了,赋值完毕后记得用SafeArrayUnaccessData解除绑定。
    最后一步就是包壳子了, AryWarp.parray = psa; 然后就可以把AryWarp return了。COM组件开发笔记--字符串数组的传递




自己写的调用例子保存
// DLGeXEDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "DLGeXE.h"
#include "DLGeXEDlg.h"
#include "afxdialogex.h"
#include <math.h>
#include <string>
using namespace std;
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
//#import ".\Debug/AtlDll1.dll" no_namespace           //导入Dicom文件解析组件
#import ".\Debug/ComOpenDicomFile.dll" no_namespace           //导入Dicom文件解析组件
//#import ".\Debug/ComFileProcessing.dll" no_namespace           //导入Dicom文件解析组件
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

UINT ThreadFunction(LPVOID pParam );
static DWORD WINAPI ThreadB1(LPVOID lpParam); 
class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CDLGeXEDlg 对话框




CDLGeXEDlg::CDLGeXEDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CDLGeXEDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CDLGeXEDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CDLGeXEDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDOK, &CDLGeXEDlg::OnBnClickedOk)
	ON_BN_CLICKED(IDC_BUTTON1, &CDLGeXEDlg::OnBnClickedButton1)
	ON_WM_TIMER()
END_MESSAGE_MAP()


// CDLGeXEDlg 消息处理程序

BOOL CDLGeXEDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码
	m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);



	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CDLGeXEDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CDLGeXEDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CDLGeXEDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}



void CDLGeXEDlg::OnBnClickedOk()
{
	//ExitProcess(0);
	// TODO: 在此添加控件通知处理程序代码
//********************************************************************************************************
//AtlDll1.dll(第一版函数有点乱的版本com组件)
//********************************************************************************************************
	//IIDicomDS * dsPtr;//Dicom解析组件
	//CoInitialize(NULL);
	//CoCreateInstance(__uuidof(IDicomDS) ,NULL,CLSCTX_ALL,__uuidof(IIDicomDS),(void**)&dsPtr);//组件实例化									//类型转换	
	//
	打开dcm文件
	//HRESULT ret;
	//ret = dsPtr->LoadDicomFile(_T("C:\\Untitled-52.dcm"));
	ret = dsPtr->LoadDicomFile(_T("C:\\1.3.46.670589.11.32566.5.20.1.1.3360.2013070508422193616.dcm"));
	获取DCM文件名
	BSTR p;
	dsPtr->getFileName(&p);
	//char chName[256] = {0};
	//dsPtr->GetFileName(chName);


	获取DCM的数据行数
	//long nImageLine = 0;
	//nImageLine = dsPtr->GetImageLine(nImageLine);

	获取DCM的数据列数
	//long nImageCloumn = 0;
	//nImageCloumn = dsPtr->GetImageCloumn(nImageCloumn);

	获取DCM的数据Buffer
	//short *m_pBuff;
	//m_pBuff=new SHORT[nImageLine*nImageCloumn];
	//dsPtr->getBuff(m_pBuff);
	//FILE *fp1 = fopen("C:\\HHTmp\\DicomTmp\\IfcviewpHAPPY","wb");
	//fwrite(m_pBuff, nImageLine*nImageCloumn, sizeof(SHORT), fp1);
	//fclose(fp1);

	释放dicom
	//dsPtr->GetDicomBuffer(m_pBuff);
	//dsPtr->Release();
	//CoUninitialize(); 
	//return;
	//CDialogEx::OnOK();
//********************************************************************************************************
//ComOpenDicomFile.dll
//********************************************************************************************************
	IIDicomDp *dicomDp;
	CoInitialize(NULL);
	CoCreateInstance(__uuidof(IDicomDp) ,NULL,CLSCTX_ALL,__uuidof(IIDicomDp),(void**)&dicomDp);//组件实例化									//类型转换	

	CString fileName = _T("D:\\printdir\\1.2.826.0.1.3680043.2.42.18398468180992.2388.201505181849180.dcm");
	dicomDp->LoadDicomFile(_bstr_t(fileName));
	int nInstanceNumber = 0;
	dicomDp->GetInstanceNumber(&nInstanceNumber);
	

	//获取DCM的数据行数
	int  nImageLine = 0;
	int nImageCloumn = 0;
	dicomDp->raw_GetColumnAndRow(&nImageCloumn,&nImageLine);

	CString strBmpName = _T("d:\\printdir\\2222.bmp");
	//dicomDp->SaveDcmToZoomBmp(256,256,_bstr_t(strBmpName),1);
	
	//CString fileName1 = _T("C:\\Untitled-521.dcm");
	//dicomDp->LoadDicomFile(_bstr_t(fileName1));
	//int nInstanceNumber1 = 0;
	//dicomDp->GetInstanceNumber(&nInstanceNumber1);
	//dicomDp->ReleaseDicomFile();

	int nReportSize = 0;
	dicomDp->GetReprotSize(&nReportSize);
	//获取DCM的数据Buffer
	VARIANT * m_pBuff;
	m_pBuff=new VARIANT[nReportSize];
	dicomDp->GetReportBuff(m_pBuff);

	FILE *fp1 = fopen("D:\\printdir\\rportTest11.pdf","wb");
	fwrite(m_pBuff, nReportSize, sizeof(VARIANT), fp1);
	fclose(fp1);
	//dicomDp->GetDsaFrameBuffer(20,m_pBuff);
	char * m_pBuff1;
	m_pBuff1=new char[nReportSize];


	SAFEARRAY *psa = m_pBuff->parray; //使用数组整理读取的数据

	for (long i = 0; i < nReportSize; i++)
	{
		::SafeArrayGetElement(psa,&i,m_pBuff1+i);
	}
	FILE *fp2= fopen("D:\\printdir\\rportTest22.pdf","wb");
	fwrite(m_pBuff1, nReportSize, sizeof(char), fp2);
	fclose(fp2);

	//dicomDp->TestVar();

	//dicomDp->SaveWebMeasure(_T("C:\\Untitled-jdlkfjaslkdf.dcm"),_T("C:\\Untitled-jdlkfjaslkdf1111.dcm"),_T("lcblcb"));


	//CString strMeasureText = _T("");
	//BSTR bStr = SysAllocString(_T(""));
	//dicomDp->GetMeasureText(&bStr);
	
	dicomDp->ReleaseDicomFile();
//********************************************************************************************************
//ComFileProcessing.dll
//********************************************************************************************************
	//解析dicom文件,这里用lead
	//CString strFilePath = L"C:\\1.dcm";
	//IIDicomDS * dsPtr;																			//Dicom解析组件
	//CoInitialize(NULL);
	//CoCreateInstance(__uuidof(IDicomDS) ,NULL,CLSCTX_ALL,__uuidof(IIDicomDS),(void**)&dsPtr);	//组件实例化
	//CComBSTR bstrPath = strFilePath.AllocSysString();												//类型转换	
	//HRESULT ret;

	ret = dsPtr->LoadFile(bstr_t(bstrPath), 0, 0);
	//ret = dsPtr->LoadDicomFile(bstr_t(bstrPath), 0, 5, 0);

	//CString strInstanceNumber = _T("");
	dsPtr->InsertElementStr(_bstr_t(strInstanceNumber),0x00200013);//插入病人姓名
	//BSTR bStr = SysAllocString(_T(""));
	dsPtr->GetElementStr(&bStr,0x00100010);
	//dsPtr->GetElementStr(&bStr,0x00204000);
	//
	//dsPtr->GetElementStr(&bStr,0x00080018);

	//dsPtr->SaveFile("C:\\111111111.bmp",1);
	//dsPtr->CloseFile();

	//CoUninitialize();//释放COM
	AfxMessageBox(L"OK");
}


void CDLGeXEDlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码

	//CLog m_log(_T("C:\\dddddd.log")); 
	//m_log.logWrite(_T("1"));
	//m_log.logWrite(_T("2"));
	//m_log.logWrite(_T("3"));
	//m_log.logWrite(_T("4"));
	//m_log.logClose();
    
	CString str = L"病人姓名:";
	string s(CW2A((LPCTSTR)str));
	CString str2(CA2W(s.c_str()));

	
	int iType = 1;
	m_QueryThread = AfxBeginThread(ThreadFunction,this,THREAD_PRIORITY_NORMAL,
		0, CREATE_SUSPENDED, NULL);

	//SetTimer(1,1000,NULL);

	m_pHEvent = m_QueryThread->m_hThread;//用于监测线程是否退出
	//SetEvent(m_hEvent);//用于通知线程退出,现在是启动
	//	

	//PostThreadMessage(GetCurrentThreadId(), 0x0401,100,86);
	//MSG msg;
	//PeekMessage(&msg, NULL, 0x0401, 0x0401, PM_NOREMOVE);

 //   
	
	m_QueryThread->ResumeThread();
	
	
	if(WAIT_OBJECT_0 == WaitForSingleObject(m_pHEvent, 0))
	{
		MessageBox(_T("in"),_T("提示"),MB_OK);
		return;
	}

	double result;
	double x = 4.0;
	result = exp(x);
}

void CDLGeXEDlg::test()
{
	if(WAIT_TIMEOUT == WaitForSingleObject(m_hEvent, 0))
	{
		MessageBox(_T("in Thread"),_T("提示"),MB_OK);
		return;
	}
}

UINT ThreadFunction(LPVOID pParam )
{
	Sleep(2000);
	CDLGeXEDlg * pDlg = (CDLGeXEDlg*)pParam;
	int a = 10;
	int b = 100;
	//pDlg->test();
	return 0;
}



BOOL CDLGeXEDlg::PreTranslateMessage(MSG* pMsg)
{
	// TODO: 在此添加专用代码和/或调用基类
	if (pMsg->message == 0x0401)
	{
		AfxMessageBox(_T("收到消息 "));
	}
	return CDialogEx::PreTranslateMessage(pMsg);
}


void CDLGeXEDlg::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	switch(nIDEvent)
	{
	case 1:
		MessageBox(_T("in onTimer"),_T("提示"),MB_OK);
		break;
	default:
		break;
	}
	CDialogEx::OnTimer(nIDEvent);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值