PRB: EKOALA5 Custom Marshaling Sample Error
ID: Q143314
|
The information in this article applies to:
-
EKOALA5, KOALAPRX and OBJUSER3 samples included with Chapter 6 of "Inside OLE" 2nd ed. by Kraig Brockschmidt, and any custom marshaling code based on these samples.
SYMPTOMS
It is only possible to instantiate the Koala object implemented by the
EKOALA5 sample if the client initially asks for the IUnknown interface. In
this case, subsequent calls to QueryInterface to retrieve pointers to the
custom interfaces IKoala or IAnimal will also succeed. This can be observed
by using the OBJUSER3 client sample included with Chapter 6.
However, if the client initially asks for IKoala or IAnimal, then
IClassFactory::CreateInstance and CoCreateInstance will fail with
E_NOINTERFACE. This can be observed by modifying OBJUSER3 to ask for one of
these interfaces when calling CoCreateInstance.
CAUSE
EKOALA5 does not actually implement IKoala or IAnimal as interfaces, and
returns E_NOINTERFACE when queried for those interfaces. This causes
EKOALA5's IClassFactory::CreateInstance and CoCreateInstance to fail.
NOTE: When an object is custom marshaled, its interfaces need only
exist in the client's process. Thus, the proxy must implement the object's
interfaces, but it is optional for the server (implementation dependent).
The error in this case is that the server claims the object does not
support IKoala and IAnimal when in fact it does (through the proxy).
RESOLUTION
One solution would be to add interface implementations for IKoala and
IAnimal to EKOALA5 and modify CKoala::HandleCall to simply call the
appropriate interface method for each request.
However, an easier solution is to modify CKoala::QueryInterface to return
IUnknown when queried for IKoala or IAnimal, even though the CKoala does
not implement these interfaces.
CAUTION: This solution is specific to the peculiar architecture of the
EKOALA5 sample. Returning IUnknown in place of unimplemented interfaces can
easily cause a crash in other situations.
In KOALA.CPP:
STDMETHODIMP CKoala::QueryInterface(REFIID riid, PPVOID ppv)
{
*ppv=NULL;
if (IID_IUnknown==riid || IID_IMarshal==riid)
*ppv=this;
// Add these 2 lines
else if (IID_IKoala==riid || IID_IAnimal==riid)
*ppv=this;
if (NULL!=*ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
NOTE: The OLE stub in the server process will never directly call
interface methods on an object that is custom marshaled, except for
IUnknown and IMarshal methods. Other interface method calls are handled in
the client process by the proxy (perhaps using private communication with
the server). Thus even if the server does not implement certain interfaces
supported by the object, as is the case with EKOALA5, it is safe to return
IUnknown when queried for those interfaces.
In general, it is incorrect for a server to disallow a request for an
interface from CoCreateInstance but allow it from the proxy.
STATUS
This behavior is by design.
MORE INFORMATION
The EKOALA5 server and corresponding proxy KOALAPRX implement custom
marshaling for the Koala object, which provides the IKoala and IAnimal
custom interfaces. These components are designed so that the proxy
implements the custom interfaces in the client's process, but delegates to
the server to do the actual work involved for some, but not all, of the
interface methods. The server does not implement the interfaces themselves,
but merely responds to specific requests from the proxy.
When creating the object, the requested interface is passed as a parameter
to the server's IClassFactory::CreateInstance method. In EKOALA5, this
method creates the object and then calls QueryInterface. If the requested
interface is IKoala or IAnimal, QueryInterface fails causing
IClassFactory::CreateInstance and CoCreateInstance to fail.
If the initially requested interface is IUnknown, QueryInterface and
CreateInstance succeed. The IUnknown interface is returned first to the OLE
stub, which then queries for IMarshal and proceeds to custom marshal the
object back to the client by calling the IMarshal methods. On the client
side, the proxy (KOALAPRX) is loaded and the object is unmarshaled. Any
subsequent calls to QueryInterface are handled by the proxy, which
implements IKoala and IAnimal so everything works normally from that point.
With the modifications noted in the "Resolution" section of this article,
the creation process works the same when the client asks for IKoala or
IAnimal using CoCreateInstance as it does when the client asks for
IUnknown.
Additional query words:
2.00 2.0
Keywords : kbole kbprg kbsample kbOLE200 kbGrpCom kbDSupport kbprb
Version :
Platform : NT WINDOWS
Issue type :