COM server as windows service, cannot pass array a

2019-09-16 08:35发布

问题:

I'm implementing COM server (using ATL) as Windows service. I have the following method defined in service header:

STDMETHOD(SetBytes)(long lenSource, const BYTE* pSource, VARIANT_BOOL *pResult);

This method is declared in the IDL file:

[
object,
uuid(351C5A5F-3EB8-4CC5-AB79-6DCD27C2F7E0),
dual,
pointer_default(unique)
]
interface ISampleInterface: IUnknown {
  HRESULT SetBytes([in] long lenSource, [in,ref,size_is(lenSource)] const BYTE* pSource, [out,retval] VARIANT_BOOL *pResult);
};

I'm calling it from my test application like this:

CoInitialize(NULL);
IUnknownPtr unknown_ptr;
HRESULT hr = unknown_ptr.CreateInstance(__uuidof(MyLib::SampleManager));

if (FAILED(hr)) {
  ...
};

MyLib::ISampleInterfacePtr sample_ptr;
sample_ptr = unknown_ptr; // no check here, assume sample_ptr is not null

VARIANT_BOOL function_result = VARIANT_FALSE;
vector<uint8_t> flash_data(1000, 2);
function_result = sample_ptr->SetBytes(flash_data.size(), &flash_data[0]);

I'm registering service by performing:

MyService.exe /regserver
MyService.exe -service

Then I'm executing test code step by step. When I'm going to tli file where we can see the following

HRESULT _hr = raw_SetBytes(lenSource, pSource, &_result);

pSource is absolutely ok and points to the area of memory where my data is contained. But when I'm going further (I'm attached to the service with debugger) and I'm in service's function SetBytes, only one byte from this array is contained in memory area and this pointer points to the different address.

I have tried implementing server via dll (it's registered in the system with regsvr32 [dllname]) and the pointer was absolutely ok in it in this case and all the length was passed, not only one byte.

I'm new to COM technology and wondering where I am wrong.

回答1:

you could maybe wrap your BYTE array it into a SAFEARRAY.

       STDMETHODIMP MyClass::getVariantFromCharArray( char *inputCharArray, UINT inputCharArrayLength, VARIANT *outputVariant)
      {
          SAFEARRAYBOUND saBound;
          char  *pData = NULL;

          saBound.cElements = inputCharArrayLength;
           saBound.lLbound      = 0;

          VariantInit( outputVariant);
          (*outputVariant).vt = VT_UI1 | VT_ARRAY;
          (*outputVariant).parray = SafeArrayCreate( VT_UI1, 1, &saBound);

          if ( (*outputVariant).parray)
          {
             SafeArrayAccessData( (*outputVariant).parray, (void **)&pData);
        memcpy( pData, inputCharArray, inputCharArrayLength);
        SafeArrayUnaccessData( (*outputVariant).parray);    

        return S_OK;
    }
    else
    {
        return E_OUTOFMEMORY;
    }
}


回答2:

You need to use a SAFEARRAY to pass byte arrays around in COM.