COM封裝字節數組,並用於C#/c++中

因爲項目開發須要,原有的程序用C++開發,可是現有用C#開發,因此須要對用C++開發的接口利用COM進行封裝,供c#語言調用,在此處用到一個字節數組,因此此處對其進行封裝。c#

 

(一)用到的COM接口:

1.1 SAFEARRAY的建立

SAFEARRAY* SafeArrayCreate(
 VARTYPE vt,
 unsigned int cDims,
 SAFEARRRAYBOUND * rgsabound
);

VARTYPE 數組數據的類型,此處爲:VT_UI1表示1個字節的BYTE類型。具體類型以下:

VT_UI1 無符號1字節整數(BYTE)數組
VT_UI2 無符號2字節整數(WORD)數組
VT_UI4 無符號4字節整數(DWORD)數組
VT_UINT 無符號整數(UINT)數組
VT_INT  有符號整數(INT)數組
VT_I1   有符號1字節整數數組
VT_I2   有符號2字節整數數組
VT_I4   有符號4字節整數數組
VT_R4   IEEE 4字節浮點數(float)數組
VT_R8   IEEE 8字節浮點數(double)數組
VT_CY   8字節定點數貨幣值數組
VT_BSTR      VB字符串數組
VT_DECIMAL   12字節定點數(大數字)數組
VT_ERROR     標準錯誤編號數組
VT_BOOL      布爾值數組
VT_DATE      日期型數組
VT_VARIANT   VB Variant類型數組

 cDims 表示數組維數,此處賦值爲1,表示一維數組數組

SAFEARRAYBOUND* rgsabound:Pointer to a vector of bounds (one for each dimension) to allocate for the array.函數

存放的是一組數據,每一組表明一維中數據的個數以及下標下界。測試

typedef struct tagSAFEARRAYBOUND
{
       unsigned long cElements;	//該維元素個數
    unsigned long lLbound;   //該未下標的下界
} SAFEARRAYBOUND;


1.2. 數組數據的訪問:

HRESULT SafeArrayAccessData(
 SAFEARRAY * psa,
 void HUGEP ** ppvData
);

SAFEARRAY* psa [in] SAFEARRAY指針ui

ppvData [out],數組指針,若獲取成功,能夠用下標方式訪問數組中的數據, (*ppvData)[i];spa


1.3. 對數組訪問的釋放:對訪問上鎖數量減一,並使指針無效

HRESULT SafeArrayUnaccessData(
  SAFEARRAY FAR* psa 
);

Parameters

psa
[in, out] psa是由  SafeArrayCreate產生的。

Return Values

操做結果線程

E_UNEXPECTED         數組不能被解鎖
 S_OK                           操做成功
E_INVALIDARG          不合法的數針



(二).BYTE類型的數組類接口定義以及實現

[
	object,
	uuid(2D33B425-58DE-4D4C-BAC2-B39502E0644F),
	dual,
	nonextensible,
	helpstring("IComByteArray 接口"),
	pointer_default(unique)
]
interface IComByteArray : IDispatch{
	[id(1), helpstring("方法CreateArray")]   
	HRESULT CreateArray([in] UINT nArraySize, [out,retval] VARIANT_BOOL* retVal);
	[id(2), helpstring("方法PutItem")] 
	HRESULT PutItem([in]UINT itemIndex ,[in] BYTE content, [out,retval] VARIANT_BOOL* retVal);
	[id(3), helpstring("方法GetItem")] 
	HRESULT GetItem([in]UINT itemIndex, [out,retval] BYTE* retVal);
};

IDL文件中定義了以下接口:數組的建立、數據的put和get操做

.h文件定義以下:
/***********************************************************************
文件名: ComByteArray.h
類名:   CComByteArray
做者:
定義時間:2012-4-27
功能:字節數組COM封裝
************************************************************************/

#pragma once
#include "resource.h"       // 主符號
#include "COMM_COM_Client.h"

#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
#error "Windows CE 平臺(如不提供徹底 DCOM 支持的 Windows Mobile 平臺)上沒法正確支持單線程 COM 對象。定義 _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA 可強制 ATL 支持建立單線程 COM 對象實現並容許使用其單線程 COM 對象實現。rgs 文件中的線程模型已被設置爲「Free」,緣由是該模型是非 DCOM Windows CE 平臺支持的惟一線程模型。"
#endif


class ATL_NO_VTABLE CComByteArray :
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CComByteArray, &CLSID_ComByteArray>,
	public IDispatchImpl<IComByteArray, &IID_IComByteArray, &LIBID_COMM_COM_ClientLib, 
{
public:
	CComByteArray();
	~CComByteArray();

DECLARE_REGISTRY_RESOURCEID(IDR_COMBYTEARRAY)


BEGIN_COM_MAP(CComByteArray)
	COM_INTERFACE_ENTRY(IComByteArray)
	COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()


DECLARE_PROTECT_FINAL_CONSTRUCT()

	HRESULT FinalConstruct()
	{
		return S_OK;
	}

	void FinalRelease()
	{
	}

public:

private:
	UINT			  m_nSize;      //數組大小
	SAFEARRAY*		  m_pSafeArray; //SAFEARRAY指針
	VARIANT_BOOL 	          m_bAutoDelete;//是否自動刪除
	BYTE HUGEP*		  m_pContent;   //數組數據內存首指針

	STDMETHOD(CreateArray)(UINT nArraySize, VARIANT_BOOL* retVal);
	STDMETHOD(PutItem)(UINT itemIndex, BYTE content, VARIANT_BOOL* retVal);
	STDMETHOD(GetItem)(UINT itemIndex, BYTE* retVal);
};

OBJECT_ENTRY_AUTO(__uuidof(ComByteArray), CComByteArray)


c.pp文件主要說明定義的三個接口:
1. 數組的建立:
/************************************************************************
 函數名:Create
 功能:建立指定大小的數組內容
 參數:[in]nArraySize  數組大小
      [out]retVal		操做結果
/************************************************************************/
STDMETHODIMP CComByteArray::CreateArray(UINT nArraySize, VARIANT_BOOL* retVal)
{
	// TODO: 在此添加實現代碼
	HRESULT hr;
	if (nArraySize < 0)		
	{
		*retVal = VARIANT_FALSE;
		return E_INVALIDARG;
	}

	if (0 == nArraySize)
	{
		*retVal = VARIANT_TRUE;
		return S_OK;
	}

	SAFEARRAYBOUND rgsabound[1];  //定義數組維度信息並建立數組
	rgsabound[0].lLbound = 0;
	rgsabound[0].cElements = nArraySize;
	m_nSize = nArraySize;
	m_pSafeArray = SafeArrayCreate(VT_UI1, 1, rgsabound);
	if (NULL == m_pSafeArray)
	{
		hr = ResultFromScode(E_OUTOFMEMORY);
		return hr;
	}

	hr = ::SafeArrayAccessData(m_pSafeArray, (void**)&m_pContent); //獲取數據數據內存首指針
	if (FAILED(hr))	return hr;

	return S_OK;
}

數據的插入:
/************************************************************************
 函數名:PutItem
 功能:向指定下標的數組中存放內容
 參數:[in]itemIndex 數組下標
      [in]content    內容
      [out]retVal    操做結果
/************************************************************************/
STDMETHODIMP CComByteArray::PutItem(UINT itemIndex, BYTE content, VARIANT_BOOL* retVal)
{
	// TODO: 在此添加實現代碼
	if (m_nSize <= itemIndex || itemIndex < 0)		
	{
		*retVal = VARIANT_FALSE;
		return E_INVALIDARG;
	}
	
	m_pContent[itemIndex] = content;
	*retVal = VARIANT_TRUE;
	return S_OK;
}


數據的獲取:
/************************************************************************
 函數名:GetItem
 功能:獲取指定下標的數組內容
 參數:[in]itemIndex 數組下標
      [out]retVal   輸出數據位置指針
/************************************************************************/
STDMETHODIMP CComByteArray::GetItem(UINT itemIndex, BYTE* retVal)
{
	// TODO: 在此添加實現代碼
	if (m_nSize <= itemIndex || itemIndex < 0)		
	{
		*retVal = VARIANT_FALSE;
		return E_INVALIDARG;
	}
	*retVal = m_pContent[itemIndex]; 
	return S_OK;
}


(三)測試實例

先用C++語言調用COM進行測試,而後再用C#調用測試
緣由:用C++測試時能夠跟到COM內部,可是C#是不能夠的。

3.1 c#測試代碼:

using System;
using System.Collections.Generic;
using System.Text;
using COMM_COM_ClientLib;

namespace COMMClientTest
{
    class Program
    {
        static void Main(string[] args)
        {
            IComByteArray comByteArray = new ComByteArray(); //COM對象建立
            comByteArray.CreateArray((uint)100);

            for (uint i = 0; i < 5; i++)  //放入數據
            {
                bool bRet = comByteArray.PutItem(i, (Byte)i);
                if (bRet) Console.WriteLine("Put Item Succ");
                else Console.Write("Put Item Fail");
            }

            Console.WriteLine("-----------------------------------");
            for (uint i = 0; i < 5; i++)  //讀取放入的數據
            {
                Byte value;
                value = comByteArray.GetItem(i);
                Console.WriteLine(value);
            }

            Console.ReadLine();
        }
    }
}

測試結果:



3.2  C++測試:

//COM byteArray測試
void comTest()
{
	CoInitialize(NULL);
	
	{
		IComByteArrayPtr ptr = NULL;   //COM對象建立
		ptr.CreateInstance(__uuidof(ComByteArray));

		if (!ptr)
		{
			cout<<"Com Object Init Failed"<<endl;
			return ;
		}

	
		ptr->CreateArray(UINT(100));  //建立並放入數據
		for (UINT i = 0; i < 5; i++)
		{
		   ptr->PutItem(i, (BYTE)i);
		}

		for (UINT i = 0; i < 5; i++)  //讀取數據
		{
		   BYTE value;
		   value = ptr->GetItem(i);
		   cout<<(int)value<<endl;
		}
	}
	
		CoUninitialize();
}

測試結果:


(四)附:最後感謝流逝的風給予的技術支持,Thank you.

相關文章
相關標籤/搜索