利用接口技术进行进程通信,由于是跨进程,指针是不能传递的,COM提供了Variant类型的参数传递方式 。
如:进程P1把数据放在Var中, 调用进程2 P2.SetData(VARIANT Var)进行传送时,系统会进程1的Var数据在进程2的内存空间copy一份一模一样的数据,然后才调用真正的SetData。
如:进程P1把数据放在Var中, 调用进程2 P2.SetData(VARIANT Var)进行传送时,系统会进程1的Var数据在进程2的内存空间copy一份一模一样的数据,然后才调用真正的SetData。
方便操作Variant的类
CVariantBuffer.h
#pragma
once
// 1. Access buffer from ByteArray Variant
/*
CVariantBuffer vbuf;
if( SUCCEEDED(vbuf.Lock(&Var)))
{
char *buf = (char *)vbuf.getBuffer();
ULONG len = vbuf.getLength();
printf(buf);
...
vbuf.Unlock();
}
*/
// 2. Create Variant and copy data from Buffer
/*
VARIANT *pVar = CVariantBuffer::CreateVariant(buf, max);
...
VariantClear(pVar);
*/
class
CVariantBuffer
{
protected
:
VARIANT * m_pVariant;
void * m_pBuffer;
ULONG m_dwLength;
bool m_bLockData;
public
:
CVariantBuffer()
{
m_bLockData = false;
m_dwLength = 0;
m_bLockData = false;
m_pBuffer = NULL;
}
HRESULT Lock(VARIANT * pVariant)
{
m_dwLength = 0;
m_bLockData = false;
m_pBuffer = NULL;
if(pVariant == NULL) return E_INVALIDARG;
if((pVariant->vt & VT_ARRAY) && ((pVariant->vt & VT_UI1) || (pVariant->vt & VT_I1)))
{
m_pVariant = pVariant;
SAFEARRAY * psa = pVariant->parray;
if(psa && (psa->cbElements != 1)) return E_INVALIDARG;
HRESULT hr = SafeArrayAccessData(psa, &m_pBuffer);
if(FAILED(hr) ) return hr;
m_bLockData = true;
m_dwLength = psa->rgsabound[0].cElements;
return S_OK;
}
else return E_INVALIDARG;
}
HRESULT Unlock()
{
if(m_bLockData && (m_pBuffer != NULL))
{
SafeArrayUnaccessData(m_pVariant->parray);
CVariantBuffer();
return S_OK;
}
return E_FAIL;
}
void * getBuffer()
{
return m_pBuffer;
}
ULONG getLength()
{
return m_dwLength;
}
// create VARIANT, copy buf data to variant
// you must use VariantClear() to free
static VARIANT * CreateVariant(const void * pBuf, ULONG nLenght)
{
// SAFEARRAY
SAFEARRAY *psa;
SAFEARRAYBOUND rgsabound[1];
BYTE *p;
rgsabound[0].cElements = nLenght;
rgsabound[0].lLbound = 0;
psa = SafeArrayCreate(VT_UI1, 1, rgsabound);
// copy data
SafeArrayAccessData(psa, (void **)&p);
CopyMemory(p, pBuf, nLenght);
SafeArrayUnaccessData(psa);
// VARIANT
VARIANT * pv = new VARIANT;
pv->vt = VT_ARRAY | VT_UI1;
pv->parray = psa;
return pv;
}
};
Server实现接口主程序
// CSample.h : Declaration of the CSample
#pragma
once
#include
"resource.h" // main symbols
#include
"CVariantBuffer.h"
#if
defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
#endif
// ISample
[
object,
uuid("88FBCC25-E252-4E3F-859D-809CCFDBDB1F"),
dual, helpstring("ISample Interface"),
pointer_default(unique)
]
__interface
ISample : IDispatch
{
[id(1), helpstring("method GetData")] HRESULT GetData([out] VARIANT** ppVar);
[id(2), helpstring("method SetData")] HRESULT SetData([in] VARIANT Var);
};
// CSample
[
coclass,
default(ISample),
threading(apartment),
vi_progid("VariantServer.Sample"),
progid("VariantServer.Sample.1"),
version(1.0),
uuid("9A4AB3AE-4710-42B7-B360-120478BF8D51"),
helpstring("Sample Class")
]
class
ATL_NO_VTABLE CSample :
public ISample
{
public
:
CSample()
{
}
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
public
:
STDMETHODIMP GetData(VARIANT** ppVar)
{
const int max = 1000;
char buf[max];
for(int i = 0; i< max; i++)
buf[i] = 'A';
buf[max-1] = '/0';
*ppVar = CVariantBuffer::CreateVariant(buf, max);
return S_OK;
}
STDMETHODIMP SetData(VARIANT Var)
{
CVariantBuffer vbuf;
if( vbuf.Lock(&Var) == S_OK)
{
char *buf = (char *)vbuf.getBuffer();
ULONG len = vbuf.getLength();
printf(buf);
for(int i = 0; i< len - 1; i++)
buf[i] = 'C';
vbuf.Unlock();
}
return S_OK;
}
};
Clietn测试接口程序
// VariantClient.cpp : Defines the entry point for the console application.
//
#include
"stdafx.h"
#include
"../VariantServer/_VariantServer.h"
#include
"../VariantServer/CVariantBuffer.h"
static
const GUID IID_ISample =
{ 0x88FBCC25,0xE252,0x4E3F, {0x85,0x9D,0x80,0x9C,0xCF,0xDB,0xDB,0x1F} };
//("9A4AB3AE-4710-42B7-B360-120478BF8D51"),
static
const GUID CLSID_CSample =
{0x9A4AB3AE,0x4710,0x42B7, {0xB3,0x60,0x12,0x04,0x78,0xBF,0x8D,0x51}};
int
_tmain(int argc, _TCHAR* argv[])
{
ISample * pSample;
HRESULT hr;
CoInitialize(NULL);
hr = CoCreateInstance(CLSID_CSample, NULL, CLSCTX_LOCAL_SERVER, IID_ISample, (LPVOID *)&pSample);
if(SUCCEEDED(hr))
{
// GetData
VARIANT * pV;
pSample->GetData(&pV);
if(pV->vt && VT_ARRAY)
{
CVariantBuffer vbuf;
if(SUCCEEDED(vbuf.Lock(pV)))
{
char *buf = (char *)vbuf.getBuffer();
ULONG len = vbuf.getLength();
printf(buf);
// fill buf used 'B'
for(int i = 0; i< len - 1; i++) buf[i] = 'B';
vbuf.Unlock();
pSample->SetData(*pV);
// pV be not changed to 'C'
}
}
VariantClear(pV);
pSample->Release();
}
//getchar();
CoUninitialize();
return 0;
}