I have a function that return a pointer to an interface pointer via a paramater (project) :
CreateProject(std::string str, IDispatch** project);
Given two other Interface that implement IDispatch : A and B, is the following code legit given that the real type of project is A. ( I am trying to work with COM VCProjectEngine.CreateProject)
A** a;
B** b;
CreateProject("test.vcxproj", a); //should work but I don't know why
CreateProject("test.vcxproj", b); //should not work but I don't know why
Can someone explain me how this kind of thing is suppose to work ? I am sorry I am a little bit new with COM objects.
IDispatch** project argument typically assumes that you pass a pointer to IDispatch* variable, which is to be filled with actual interface pointer:
IDispatch* pDispatch;
pDispatch = NULL; // Sanity, optional
CreateProject("test.vcxproj", &pDispatch);
assert(pDispatch != NULL); // Filled by call above
// ...
pDispatch->Release();
Since dealing COM interface pointers make you care about proper reference counting, you typically want to use wrapper classes, instead of raw pointers:
CComPtr<IDispatch> pDispatch;
CreateProject("test.vcxproj", &pDispatch);
ATLASSERT(pDispatch != NULL);
Read up on CComPtr on MSDN.
Related
If I have two COM interface pointers (i.e. ID3D11Texture2D), and I want to check if they are the same underlying class instance, can I compare the two pointers directly for equality? I have seen code where we cast it to something else before the comparison is done, so wanted to confirm.
BOOL IsEqual (ID3D11Texture2D *pTexture1, ID3D11Texture2D *pTexture2)
{
if (pTexture1 == pTexture2)
{
return true;
}
else
{
return false;
}
}
Thanks.
The correct COM way to do this is to query interface with IUnknown. A quote from the remarks here in MSDN:
For any one object, a specific query for the IUnknown interface on any
of the object's interfaces must always return the same pointer value.
This enables a client to determine whether two pointers point to the
same component by calling QueryInterface with IID_IUnknown and
comparing the results. It is specifically not the case that queries
for interfaces other than IUnknown (even the same interface through
the same pointer) must return the same pointer value.
So the correct code is
BOOL IsEqual (ID3D11Texture2D *pTexture1, ID3D11Texture2D *pTexture2)
{
IUnknown *u1, *u2;
pTexture1->QueryInterface(IID_IUnknown, &u1);
pTexture2->QueryInterface(IID_IUnknown, &u2);
BOOL areSame = u1 == u2;
u1->Release();
u2->Release();
return areSame;
}
Update
Added a call to Release so decrease reference counts. Thanks for the good comments.
You can also use ComPtr for this job. Please look in MSDN.
I am trying to use the IFileSystemImage2 interface to create an ISO with multiple boot records using Imapi2.
To do this, I should be able to use put_BootImageOptionsArray passing in SAFEARRAY* of VT_DISPATCH type, i.e. COM pointers of type IBootOptions for each boot options configuration. As a short demo, I have the following code (I only created one IBootOptions in this case):
SAFEARRAYBOUND bounds[1];
bounds[0].cElements = 1;
bounds[1].lLbound = 0;
IBootOptions* BootOptionsArrayData = NULL;
SAFEARRAY* Array = SafeArrayCreateEx(VT_DISPATCH,
1,
bounds,
(void*) &IID_IBootOptions);
hr = SafeArrayAccessData(Array,
reinterpret_cast<void**>(&BootOptionsArrayData));
BootOptionsArrayData = BootOptions; // BootOptions = IBootOptions*
hr = SafeArrayUnaccessData(Array);
hr = IsoImage->put_BootImageOptionsArray(Array);
However, every time I call put_BootImageOptionsArray I get E_NOINTERFACE returned.
IsoImage is being created as you'd expect:
hr = CoCreateInstance(CLSID_MsftFileSystemImage,
NULL,
CLSCTX_ALL,
__uuidof(IFileSystemImage2),
(void**) &IsoImage);
Using IFileSystemImage2 any inherited functionality from IFileSystemImage works fine. Likewise, I can CoCreateInstance a IFileSystemImage instead, and this interface can be used just fine.
I have attached to my process in WinDbg and set a breakpoint in CMsftFileSystemImage::put_BootOptionsArray, however, this function (the underlying implementation) simply isn't being called.
My question, therefore is simple: the implementation appears to be there, but I don't seem to be able to call it. Does anyone have any experience of using this particular bit of functionality and if so how did you get it to work?
The documentation stipulates the SAFEARRAY must be an array of VARIANT that contain IDispatch interface pointers, so you could do something like this (I'm using smart pointers which is easier...):
CComPtr<IFileSystemImage2> image;
CComPtr<IBootOptions> options;
image.CoCreateInstance(CLSID_MsftFileSystemImage);
options.CoCreateInstance(CLSID_BootOptions);
// set various options here...
options->put_Manufacturer(CComBSTR(L"joe"));
// create a SAFEARRAY of VARIANT
CComSafeArray<VARIANT> a(1);
// create a VARIANT of type VT_UNKNONW (or VT_DISPATCH)
CComVariant v(options);
// put it in the array
a.SetAt(0, v);
HRESULT hr = pImage->put_BootImageOptionsArray(a.m_psa);
I came across a problem in my code today where an access violation was being caused, AFAICT, by casting a COM object of mine to an IUnknown**. The function it was passed into executed without a problem but when calling one of my object's functions it would execute some random function and corrupt the stack then die.
Indicative code (just ignore why it's done this way - I know it's bad and I know how to fix it but this is a question of why problems like this may occur):
void MyClass2::func(IMyInterface* pMyObj)
{
CComPtr<IMyInterface2> pMyObj2;
HRESULT hRes = pMyObj->GetInternalObject((IUnknown**)&pMyObj2);
if (SUCCEEDED(hRes))
pMyObj2->Function(); // corrupt stack
}
void MyClass::GetInternalObject(IUnknown** lpUnknown)
{
pInternalObject->QueryInterface(IID_IMyInterface2, (void**)lpUnknown);
}
I have always been a bit suspicious of using C/C++ casts on COM objects but I've never encountered (possibly through undefined behaviour) any problems until now.
I had a quick look and from what I can tell casting to IUnknown is technically valid so long as there is no multiple interitance in the inheritance chain, however it is not considered best practice - I should really pass an IUnknown to MyClass::GetInternalObject(IUnknown** lpUnknown) and then query the return value for the interface I want.
My question is, are there rules as to when C/C++ casts can be used on COM objects, and aside from multiple inheritance and the adjustor thunks they bring, how can casting COM objects result in surprises like access violations? Please be detailed.
Edit: They're all good examples of how it should be done properly but what I was hoping for was a technical explanation of why you shouldn't cast COM objects (assuming one exists) e.g. casting will return pMyObj2-4 in situation x but QueryInterface will return pMyObj2-8 because of y...or is casting COM objects simply a matter of bad practice/style?
TIA
I'd just use CComPtr and CComQIPtr to manage COM interfaces, instead of writing code with C-style casts that to me seem inappropriate in the context of COM:
void MyClass2::Func(IMyInterface* pMyObj)
{
// Assuming:
// HRESULT IMyInterface::GetInternalObject( /* [out] */ IUnknown** )
CComPtr<IUnknown> spUnk;
HRESULT hr = pMyObj->GetInternalObject(&spUnk);
if (SUCCEEDED(hr))
{
// Get IMyInterface2 via proper QueryInterface() call.
CComQIPtr<IMyInterface2> spMyObj2( spUnk );
if ( spMyObj2 )
{
// QueryInterface() succeeded
spMyObj2->Function();
}
}
}
Moreover, I'm not a COM expert, but I see with suspicion your code:
void MyClass::GetInternalObject(IUnknown** lpUnknown)
{
pInternalObject->QueryInterface(IID_IMyInterface2, (void**)lpUnknown);
}
If you are QueryInterface()'ing IID_MyInterface2, you should store that in an IMyInterface2*, not in an IUnknown*.
If your method returns an IUnknown*, then I'd QueryInterface() an IID_IUnknown:
// NOTE on naming convention: your "lpUnknown" is confusing.
// Since it's a double indirection pointer, you may want to use "ppUnknown".
//
void MyClass::GetInternalObject(IUnknown** ppUnknown)
{
pInternalObject->QueryInterface(IID_IUnknown, (void**)ppUnknown);
}
or better use IID_PPV_ARGS macro:
void MyClass::GetInternalObject(IUnknown** ppUnknown)
{
IUnknown* pUnk = NULL;
HRESULT hr = pInternalObject->QueryInterface(IID_PPV_ARGS(&pUnk));
// Check hr...
// Write output parameter
*ppUnknown = pUnk;
}
COM style casts have a specific name: QueryInterface().
I think the issue is that because a cast from IMyInterface* to IUnknown* is OK (in COM everything inherits from IUknown right?) you think that a cast from IMyInterface** to IUnknown** is also OK. But that's not true in C++, and I doubt it's true in COM either.
To me the following looks more logical, apologies if this isn't strictly correct, my COM is very rusty, but hopefully you get the idea.
CComPtr<IUnknown> pMyObj2;
HRESULT hRes = pMyObj->GetInternalObject(&pMyObj2);
if (SUCCEEDED(hRes))
{
CComPtr<IMyInterface> pMyObj3 = (IMyInterface*)pMyObj2;
pMyObj3->Function();
}
I.e. get an IUnknown object first, and then down cast that to your actual type.
I don't see any issues in your code snippets, the stack corruption perhaps has its cause but its somewhere else.
I don't think it is your actual code because GetInternalObject should be of HRESULT type and yours is not, so you lost something during copy/pasting.
To stay safer, just avoid direct QueryInterface calls because together with casting they might misinterpret interfaces. Casting to and from IUnknown* might be inevitable though. If the callee cannot be trusted to return proper interface casted to IUnknown, on the caller side you might prefer to QI once again to make sure you hold the interface of your interest.
Provided that GetInternalObject is a COM interface method on its own, you could have it like this:
void MyClass2::func(IMyInterface* pMyObj)
{
CComPtr<IUnknown> pMyObj2Unknown;
pMyObj->GetInternalObject((IUnknown**)&pMyObj2Unknown);
CComQIPtr<IMyInterface2> pMyObj2 = pMyObj2Unknown; // This is only needed if callee is not trusted to return you a correct pointer
if (pMyObj2)
pMyObj2->Function(); // corrupt stack
}
STDMETHODIMP MyClass::GetInternalObject(IUnknown** lpUnknown) // COM method is typically both HRESULT and __stdcall
{
CComQIPtr<IMyInterface2> pMyInterface2 = pInternalObject;
if(!pMyInterface2)
return E_NOINTERFACE;
*lpUnknown = pMyInterface2.Detach(); // *lpUnknown will have to me IMyInterface2 this way
return S_OK;
}
PS If GetInternalObject was a native method, not COM, you would avoid casting to IUnknown* at all.
I find myself in need of help. Now, I'm not all that unfamiliar with C++, but combining it with ATL provides a whole new level of confusion. Anyways, my problem: I (finally) managed to return an array of objects in my COM method to C# caller. But upon 'testing' (running said function a number of times repeatedly) I recognized a small memory leak.
IDL excerpt:
...
interface IDISControl : IDispatch{
...
[id(12)] HRESULT GetNets([out,retval] VARIANT* nets);
};
Header excerpt:
...
STDMETHOD(GetNets)(VARIANT* nets);
...
Code:
STDMETHODIMP CDISControl::GetNets(VARIANT* nets)
{
SNet *netz;
int32_t num;
int result, i;
result = DIS_GetNetNum(securityHandle, &num);
netz = new SNet[num];
result = DIS_GetNet(securityHandle, netz, num); //getting some data
CComSafeArray<IDispatch*> netArray;
CComObject<CDISNet> *net;
CComVariant *var;
netArray.Create(num, 0);
for (i = 0;i<num;i++){
CComObject<CDISNet>::CreateInstance(&net);
if (net == NULL)
return S_FALSE;
net->AddRef();
net->Convert(netz[i]);
netArray[i] = net;
net->Release();
net = NULL;
}
CComVariant val(netArray.Detach());
val.Detach(nets);
delete [] netz;
netArray.Destroy();
return S_OK;
}
I instantiate CDISNet objects and put some data in them (Convert()). I put them in my safearray and release. As I understand it, the responsibility for destroying them is transferred to safearray. Afterwards, I box the array in a VARIANT so I can fill my [out, retval] parameter. Since it's an out parameter, the responsibility for destruction should be transferred to caller (in my case C#, i.e. its GarbageCollector). I dispose of my dynamic array 'netz' and I destroy safearray wrapper.
So what am I missing? What is left allocated? (This project is really making me appreciate all the comforts of .net).
Help. Please.
EDIT: Further debugging revealed to me that the problem is certainely in my CComObject objects. They aren't being deallocated. If I delete net; in each iteration the array also looses data. I'm unsure as how to rectify that...
EDIT2:
Ok, I poked around this code for a bit, and the leak seems to go away when I comment out variant boxing. The problem is that I borrowed this piece of code from Visual Studio sample on safearrays. So, does anyone have any idea what's up with:
CComVariant val(netArray.Detach());
val.Detach(nets);
...and what to do about it?
Most, if not all, of ATL's wrappers follow COM conventions -- they copy/addref incoming data, as their destructor will destroy/release.
So when you pass your detached SAFEARRAY to CComVariant's constructor, it will make a copy of the SAFEARRAY, which means nobody releases the result from CComSafeArray::Detach.
In cases like this, I always found it easier to forego the wrapper for the return value entirely;
nets->vt = VT_ARRAY | VT_DISPATCH;
nets->parray = netArray.Detach();
The alternative would be to pass your CComSafeArray directly to CComVariant's constructor, without calling Detach, but that would cost you an extra copy. I'd prefer the raw access presented above, as it is most straightforward and cheapest.
As to your first edit, what you're doing with AddRef/Release is fine, if somewhat unnecessary. CComObject::CreateInstance returns an object with reference count 0, so the AddRef will bring it to 1, and then assigning it to the CComSafeArray will bump it to 2, and the following Release back down to 1.
Unless the Convert method does anything with the object's reference count (e.g. QueryInterface itself or pass itself to another COM method), you could skip the AddRef/Release pair, and let Convert execute with refcount == 0. Then adding it to the array would increase it, and it would stay alive until released.
I am a COM object written in ATL that is used from a C++ application, and I want to pass an array of BYTEs between the two. My experience of COM/IDL so far is limited to passing simple types (BSTRs, LONGs, etc.).
Is there a relatively easy way to have the COM object pass an array to the caller? For example, I want to pass a raw image (TIFF) instead of messing with temporary files.
Try passing a safearray variant to the COM Object. Something like this to put a BYTE array inside a safearray variant....
bool ArrayToVariant(CArray<BYTE, BYTE>& array, VARIANT& vtResult)
{
SAFEARRAY FAR* psarray;
SAFEARRAYBOUND sabounds[1];
sabounds[0].lLbound=0;
sabounds[0].cElements = (ULONG)array.GetSize();
long nLbound;
psarray = SafeArrayCreate(VT_UI1, 1, sabounds);
if(psarray == NULL)
return false;
for(nLbound = 0; nLbound < (long)sabounds[0].cElements ; nLbound++){
if(FAILED(SafeArrayPutElement(psarray, &nLbound, &array[nLbound]))){
SafeArrayDestroy(psarray);
return false;
}
}
VariantFree(vtResult);
vtResult.vt = VT_ARRAY|VT_UI1;
vtResult.parray = psarray;
return true;
}
SAFEARRAYs are the way to go if you want OLE-Automation compliance, and maybe use the COM interface from other languages such as VB6. But there is an alternative in IDL, for example: -
void Fx([in] long cItems, [in, size_is(cItems)] BYTE aItems[]);
This describes a method where the marshalling code can infer the number of bytes to be transfered by inspecting the value of the first parameter.
This is fine if your clients are all written in C/C++, but i think that an interface containing this would not be automation-compliant, so not usable from VB6, and possibly the standard marshaler will not be able to do the marshaling, so you'd need to generate your own proxy/stub DLL from the IDL. Not hard to do, but a bit harder than using SAFEARRAYs.
Check out using safearrays. Here's some example code:
The safearray is returned as a pointer to a VARIANT
[id(1), helpstring("LogCache")] HRESULT LogCache([out,retval] VARIANT* logCache);
Safearrays are pretty easy to use. Here's some example code which is a cache of the latest 1000 log messages of some application:
safearray_t<bstr_t> m_logCache;
...
if (m_logCache.size() > 1000)
{
m_logCache.pop_back();
}
m_logCache.push_front(Msg.str(), 0);
variant_t LogCache()
{
if (!m_logCache.is_empty())
{
variant_t cache(m_logCache);
return cache;
}
}
Note that the syntax in your case is almost certainly going to be different since I'm using the comet COM library, but the ideas/concepts are the same.
You can use BSTR to pass an array of bytes.
BYTE array[buffer_size];
...
BSTR toBePassed = SysAllocStringByteLen((OLECHAR*)array,length);
YourCOMMethod(toBePassed);
SysFreeString(toBePassed);
In your method:
BYTE* pData = (BYTE*)bstrPassed;
DWORD dataLength = SysStringByteLen(bstrPassed);