Re: ATL/COM: Interface as property of another interface
Hello Roman,
thanks for your answer. You are right, I'm trying to do this in order to use
the classes later with delphi, C++ a.s.o ...
My classes does inherit from IDispatch and are marked with the atribute
dual. I just tried to write a pseudo-interfaces here in order to get no much
code, but as I can see it was no such a good idea. So... here is the real
code (I figured out a way to do what I want... please let me know what do
you think):
//--------------------------------------------------------------------------------------------------
******INTERFACES******
[
object,
uuid(3D7274F0-09BB-443F-B252-B520D09920A3),
dual,
nonextensible,
pointer_default(unique)
]
interface IPCJName : IDispatch{
[propget, id(8)] HRESULT ManufactureCode([out, retval] USHORT* pVal);
[propput, id(8)] HRESULT ManufactureCode([in] USHORT newVal);
[propget, id(10)] HRESULT AsNumber([out, retval] ULONGLONG* pVal);
[propput, id(10)] HRESULT AsNumber([in] ULONGLONG newVal);
[id(11)] HRESULT GetAsArray([out] BYTE * arrayName);
};
[
object,
uuid(30C39381-F280-43D2-A041-D9A1165512C0),
dual,
nonextensible,
pointer_default(unique)
]
interface IPCJNode : IDispatch{
[propget, id(1)] HRESULT Client([out, retval] BYTE* pVal);
[propget, id(2)] HRESULT Name([out, retval] IPCJName** pVal);
};
[
uuid(B6EBCD51-BE48-4B56-ADE6-AA0AC852563A),
version(1.0)
]
******CLASSES******
------CPCJName------
class ATL_NO_VTABLE CPCJName :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CPCJName, &CLSID_PCJName>,
public IDispatchImpl<IPCJName, &IID_IPCJName, &LIBID_PCJ, /*wMajor =*/ 1,
/*wMinor =*/ 0>
{
public:
CPCJName() : m_objName()
{
}
DECLARE_REGISTRY_RESOURCEID(IDR_PCJNAME)
BEGIN_COM_MAP(CPCJName)
COM_INTERFACE_ENTRY(IPCJName)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
private:
clsJName m_objName;
public:
STDMETHOD(get_ManufactureCode)(USHORT* pVal) { return
m_objName.GetManufactureCode(pVal) ? S_OK : S_FALSE; }
STDMETHOD(put_ManufactureCode)(USHORT newVal) { return
m_objName.SetManufactureCode(newVal) ? S_OK : S_FALSE; }
STDMETHOD(get_AsNumber)(ULONGLONG* pVal) { return
m_objName.GetAsNumber(pVal) ? S_OK : S_FALSE; }
STDMETHOD(put_AsNumber)(ULONGLONG newVal) { return
m_objName.SetAsNumber(newVal) ? S_OK : S_FALSE; }
STDMETHOD(GetAsArray)(BYTE * arrayName) { return
m_objName.GetAsArray(arrayName) ? S_OK : S_FALSE; }
};
OBJECT_ENTRY_AUTO(__uuidof(PCJName), CPCJName)
------CPCJNode------
class ATL_NO_VTABLE CPCJNode :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CPCJNode, &CLSID_PCJNode>,
public IConnectionPointContainerImpl<CPCJNode>,
public CProxy_IPCJNodeEvents<CPCJNode>,
public IDispatchImpl<IPCJNode, &IID_IPCJNode, &LIBID_PCJ, /*wMajor =*/ 1,
/*wMinor =*/ 0>
{
public:
CPCJNode()
{
}
DECLARE_REGISTRY_RESOURCEID(IDR_PCJNODE)
DECLARE_GET_CONTROLLING_UNKNOWN()
BEGIN_COM_MAP(CPCJNode)
COM_INTERFACE_ENTRY(IPCJNode)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
END_COM_MAP()
BEGIN_CONNECTION_POINT_MAP(CPCJNode)
CONNECTION_POINT_ENTRY(__uuidof(IPCJNodeEvents))
END_CONNECTION_POINT_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
public:
private:
clsJNode m_objNode;
public:
STDMETHOD(get_Client)(BYTE* pVal) { return m_objNode.GetClient(pVal) ? S_OK
: S_FALSE; }
STDMETHOD(get_Name)(IPCJName** pVal) { ?????????????? a pointer to
m_objNode.JName; }
};
OBJECT_ENTRY_AUTO(__uuidof(PCJNode), CPCJNode)
//--------------------------------------------------------------------------------------------------
To the Scenarios:
in 1 and 2 I want to have a pointer to the same object, in my case an obj
contained by the class clsJNode (m_objNode in CPCJNode).
in 3, due to the fact that more pointers point to the same object, releasing
a parent object should make unusless the child objects.
//--------------------------------------------------------------------------------------------------
SOLUTION??????
I figured out how I can do what I want, but I do not know how to programm
it. First I need an small internal interface, not public, just visible for
me (let call it IInterName). Second, I can implement this interface in the
class CPCJName. This class will habe now an extra pointer to a TJName and a
boolean bIsUsedByNode, as well a function SetForNode():
interface IInterName : IUnknown
{
STDMETHOD(SetForNode)(TJName* name);
STDMETHOD(SetToNull)();
}
(complement to classe CPCJName, implementing IInterName)
....
private:
TJName m_objName;
TJName *m_objpName;
bool bIsUsedByNode;
public:
HRESULT FinalConstruct()
{
SetForNode(NULL);
return S_OK;
}
STDMETHOD(SetForNode)(TJName* name)
{
if(name != NULL)
{
bIsUsedByNode= true;
m_objpName = name;
}
else
{
bIsUsedByNode= false;
m_objpName = &m_objName;
}
return S_OK;
}
STDMETHOD(SetToNull)()
{
m_objpName = NULL;
}
In this way I would use the new m_objpName to resolve all methods in
CPCJName. In the constructor of CPCJNode a could use the new interface to
set the CPCJName to be modified.
A) in the CPCJNode constructor I could call CoCreateInstance to create a new
CPCJName and use it within a QueryInterface to get the IInterName. Then,
with that interface pointer I could call SetForNode(&m_objNode.JName ). This
created instance will be returned when a client ask for the property Name
(method get_Name) of IPCJNode.
B) in the CPCJNode destructor I could do the same procedure but this time
calling SeTtoNull.
....
Conclusion:
I think with the above explained I could have both object referenced (A),
and when a IPCJNode is released and there are still references to its Name
property, those will be showed as NULL (B).
//--------------------------------------------------------------------------------------------------
QUESTIONS:
- How can I create/define an Interface just for internal uses?
- How can I implement that interface in an already created ATL/COM class?
I hope you can help me with this.
Thanks a lot...
Keneth.
"Roman Ryl..." <ryltsov@gmail.com> schrieb im Newsbeitrag
news:4ed73c5f-9fbb-4f9e-9745-2e0b395a07d3@i24g2000prf.googlegroups.com...
Hi,
1. id(x) and propget/propput attributes don't make sense unless you
inherit your interfaces from IDispatch and they are marked as
oleautomation/dual and used from higher level languages (which seems
to be your goal taking into consideration usage examples).
2. [out] argument for an interface type has an incorrect level of
indirection. You need a pointer which will accept a pointer to
insterface, that is:
[propget, id(3)] HRESULT CValue([out, retval] IClass1** ppValue);
As for usage scenarios:
1 and 2: will depend on your implemetnation, whether CValue property
will return a pointer to another object, or QI to the same object
3: pClass1 will typically hold a reference to your object, so a
Release of another reference would not invalidate pClass1.
Roman