|
No, i can't use COM+. I am trying to do it myself by overwriting
Release method of CComobject.
However, i fail to have template specification.
|
|
|
|
|
Hmmm... Maybe this is a case for COM aggregation. It seems easier to control AddRef/Release by creating a second component that aggregates the first. It can be done in such a way that's almost transparent to clients and this will ease turning on/off the pooling behaviour. I know it's more a workaround, I don't have a solution for your specific problem, but IMHO it would be a more elegant way of implementing this kind of functionality.
My latest article:
SQL Server DO's and DONT's[^]
|
|
|
|
|
Maybe I am reading this wrong, but if you want to overwrite the Release function provided by CComObject then you should be creating a class that inherits from CComObject and overwrite its Release function. In the code example you provided it appears that you are doing it the other way round.
Instead of
template<>
class CComObject<cmycom> : public CMyCOM
Try
template<>
class CMyCOM<> : public CComObject
This way CMyCOM provides all features of CComObject except those that you overwrite.
|
|
|
|
|
You didn't understand me.
When you work with ATL to create COM objects, you should know that ATL defines a template class, called CComObject, that derives from your COM class.
CComObject is the most derived class which implements AddRef, Release and QueryInterface methods. (Look at atlcom.h)
Therefore:
1) I can't inherit from CComObject because it is derived from my COM class.
2) I tried to have explicit specialization
template<> class CComobject<CmyCOM>:public CMyCom{...} .
But i get error C2934: 'CComObject<class CMyCOM>' : template-class-id redefined as a nested 'class' of '<Unknown>'
What does the error mean?
|
|
|
|
|
I am not sure what the error means, but you sure have me thinking now...
Is CMyCOM an ATL COM class or just a C++ class?
Also it seems you are creating CComObject. But that class already exists.
Also per MSDN :
CComObject implements IUnknown for a nonaggregated object. However, calls to QueryInterface, AddRef, and Release are delegated to CComObjectRootEx.
So to achieve what you want, i.e., overwrite Release, you could derive a class from CComObjectRootEx, and then make your COM classes inherit from the derived class rather than CComObjectRootEx. Or something like that
Just random rambling thoughts.....
|
|
|
|
|
CMyCOM is an ATL COM class.
This class is derived from CComObjectRootEx so i can overwrite 'InternalAddRef' and 'InternalRelease' methods.
Now, take a look at CComObject::Release():
STDMETHOD_(ULONG, Release)()
{
ULONG l = InternalRelease();
if (l == 0)
delete this;
return l;
}
This is where a decision is made according to the reference counter. I can overwrite InternalRelease but it won't help. I must change CComObject::Release so that if the refernce counter is 1 then the object should be return to the pool.
|
|
|
|
|
Hi,
This is some misundestanding, based on fact, that in ATL the CComObject is used in some other way than other classes. So if you want to override the CComObject functionality, you have to realize, that this is the class which will be derived from yours (CComObject is the topmost in the hierarchy)
Then the code will looks like that:
template <class Base><br />
class CMyComObject: public CComObject<Base><br />
{};
this will create CMyComObject, where you can override required functions and do whatever you want to. But this is only the half way to the goal.
Then, for allowing a creation of your specialized (pooled) COM, you have to create a class factory -
<br />
template <class T><br />
class CMyComClassFactory : public CComClassFactory<br />
{<br />
};
there is the most important function to be overrided (at least) - CreateInstance(...). Inside this function you will create your object in a way like that:
CMyComObject<T>::CreateInstance(&m_pObj) ;
(note the ..My.. in CMyComObject)
and the last point to achieve the custom-creation is to declare following macro inside your com class
DECLARE_CLASSFACTORY_EX(CMyComClassFactory<class> )
for that I use some macro defined:
#define DECLARE_MY_CLASSFACTORY(obj) DECLARE_CLASSFACTORY_EX(CMyComClassFactory<obj> )
then your component code will looks like:
class CMySuperPooledComponent : public ...whatewer was there...<br />
{<br />
DECLARE_MY_CLASSFACTORY(CMySuperPooledComponent);<br />
};
I hope this will helps you to achive whatever you want to. It looks quite complicated, then if you will need some more help, don't hesitate to contact me on my e-mail (-nospam)
|
|
|
|
|
Hi, thanks a lot.
Should the class factory and CMyComObject point to a global pool object manager, for the factory will pop out an object from there and CMyComObject will return it back?
|
|
|
|
|
Well, if I understood correctly, you would like to change your CMyComObject Release method to add the object to some manager instead of deletion and the factory will first ask this manager for an existing instance before creating new one.
This can be correct I would probably use the same way.
|
|
|
|
|
Yes, this is exactly what i wanted to do.
Thanks a lot,
Dudi
|
|
|
|
|
hi,
I need a help !! Please someone help me !
I am developing ATL COM which contains property of type COM object (ATL coclass): CComObject<dombookingareaholder> *m_AreaHolder.
Just for info: domBookingAreaHolder is a ATL co class.
I want to allow all clients (C++, VB, VBSCript) to be able to get and put the property.
Below is the code for ATL COM:
1) domBooking.CPP
<br />
<br />
class ATL_NO_VTABLE domBooking : <br />
public CComObjectRootEx<CComSingleThreadModel>,<br />
public CComCoClass<domBooking, &CLSID_domBooking>,<br />
public ISupportErrorInfo,<br />
public IDispatchImpl<IdomBooking, &IID_IdomBooking, &LIBID_DOMIBMSLib><br />
{<br />
public:<br />
domBooking()<br />
{<br />
}<br />
<br />
HRESULT FinalConstruct()<br />
{<br />
CComObject<domBookingAreaHolder>::CreateInstance(&m_AreaHolder);<br />
return S_OK;<br />
}<br />
<br />
void FinalRelease()<br />
{ <br />
m_AreaHolder = NULL;<br />
}<br />
<br />
DECLARE_REGISTRY_RESOURCEID(IDR_DOMBOOKING)<br />
<br />
DECLARE_PROTECT_FINAL_CONSTRUCT()<br />
<br />
BEGIN_COM_MAP(domBooking)<br />
COM_INTERFACE_ENTRY(IdomBooking)<br />
COM_INTERFACE_ENTRY(IDispatch) <br />
END_COM_MAP()<br />
<br />
public:<br />
<br />
STDMETHOD(get_AreaHolder)(IDispatch*** pVal);<br />
STDMETHOD(put_AreaHolder)(IDispatch** newVal);<br />
<br />
<big>CComObject<domBookingAreaHolder> *m_AreaHolder;</big><br />
<br />
};<br />
<br />
1) How I can accomplish this ?
2) how the propety for get and set being implemeted ?
3) and lastly how client can call to object property using set and put in VC++ ?
Thank u very very much in advance . Any advice and suggestions strongly aprreciated.
Regards,
Newbie
|
|
|
|
|
Use VARIANT instead of IDispatch
STDMETHOD(get_AreaHolder)(VARIANT** pVal);
STDMETHOD(put_AreaHolder)(VARIANT* newVal);
Example of use:
VARIANT v;
v.vt=VT_DISPATCH;
v.pdispVal=pInterfaceAreaHolder;
obDomBooking->put_AreaHolder(&v); Once the interface pointer arrives in the put_AreaHolder method, you should query it for the AreaHolder interface and store the result in m_AreaHolder; when destroying, call Release on the same m_AreaHolder. Of course, don't forget the usual checkings.
rechi
|
|
|
|
|
How do I pass an array from C# to a COM object.
What is the method parameter syntax for the COM object and how
does C# use the COM object
|
|
|
|
|
To pass an array into a COM object you need to use a VARIANT_ARRAY. How you build it in C#, I dunno.
Christian
No offense, but I don't really want to encourage the creation of another VB developer. - Larry Antram 22 Oct 2002
Hey, at least Logo had, at it's inception, a mechanical turtle. VB has always lacked even that... - Shog9 04-09-2002
Again, you can screw up a C/C++ program just as easily as a VB program. OK, maybe not as easily, but it's certainly doable. - Jamie Nordmeyer - 15-Nov-2002
|
|
|
|
|
Seems that in some cases one is more effective than the other. How to choose?
Thanks!
---------------
Concentrating on Ideas
http://www.edovia.com
|
|
|
|
|
CComQIPtr supports automatic querying of COM interfaces through QueryInterface. Both do automatic AddRefs and Releases. You should use CComPtr for IUnknowns. CComQIPtr is good for getting a particular interface:
CComQIPtr<IConnectionPointContainer, &IID_IConnectionPointContainer> pCPC(pUnk);
CComPtr is good for being passed into other COM calls where you're receiving an interface pointer back:
CComPtr<IConnectionPoint> pCP;
pCPC->FindConnectionPoint(IID_IPropertyNotifySink, &pCP);
|
|
|
|
|
Hey all,
I'm working on a component that returns a SAFEARRAY. Here's the IDL for the method as well as the C++ declaration:
[id(2), helpstring("List of Report Type (Names) available to a user on a specific date")] HRESULT GetReportTypes([in] BSTR UserID, [in] INT CloseDate, [out, retval] VARIANT* pReportTypes);
STDMETHODIMP CReports::GetReportTypes(BSTR UserID, INT CloseDate, VARIANT *pReportTypes)
Now without loading this up with a ton of code I'll explain what I am doing and then show the important parts of the code.
Basically, I want to return a SAFEARRAY that is mulitdimensionl, in this case the array is [x][1] in size and x is determined by the number of records retrieved. So here's how I'm creating the SAFEARRAY:
<br />
SAFEARRAYBOUND SABounds[2];<br />
SABounds[0].cElements = (DWORD)pRsHPASReports->RecordCount + 1;
SABounds[1].cElements = SABounds[0].cElements;<br />
SABounds[0].lLbound = 0;<br />
SABounds[1].lLbound = 0; <br />
<br />
VariantInit(pReportTypes);<br />
pReportTypes->vt = VT_VARIANT | VT_ARRAY;<br />
pReportTypes->parray = SafeArrayCreate(VT_VARIANT, 2, SABounds);<br />
and then after opening the recordset I loop through the records filling in the SAFEARRAY with my data, like so:
<br />
while(! pRsHPASReports->IsEOF)<br />
{<br />
ldimension[0] = lLoop++;<br />
ldimension[1] = 0;<br />
<br />
CComVariant bstrTmp( pRsHPASReports->Fields->Item["RptType"]->Value );<br />
TESTHR(SafeArrayPutElement( pReportTypes->parray, ldimension, &bstrTmp ));<br />
<br />
ldimension[1] = 1;<br />
CComVariant bstrTmp2( pRsHPASReports->Fields->Item["Title"]->Value );<br />
TESTHR(SafeArrayPutElement( pReportTypes->parray, ldimension, &bstrTmp2 ));<br />
<br />
pRsHPASReports->MoveNext();<br />
}<br />
pretty standard stuff, right? Well, as you can see from the comment above, If I have a record count of 1 then the SAFEARRAY does not appear to be initialized properly... I'm forced to add 1 to the count so that I can build the array. My question is why can't I create a SAFEARRAY with a size [1][1]?
On the client side, when checking the bounds on the SAFEARRAY I see 0 to 1 ... yet the element at postion 1 is empty. I've looked high and low on the web for a soloution and have not been successful...
So, anyone know how I can create a SAFEARRAY with just one element?
Thanks,
Dave "Dak Lozar" Loeser
When access is allowed to a member, it said to be accessible. Otherwise, it is inaccessible.
|
|
|
|
|
If you want to have the VB array (a to b) in i-th dimension bounds, you should initialize the SABounds[i].lLbound = a; and SABounds[i].cElements = b-a+1; As a rule, a is equal 0, so cElements = b-0+1 and = b+1.
But RecordCount is equal to size of array (cElements), therefore, you haven't to add extra "1". Your array in VB will have (0 to x-1) bounds.
SAFEARRAYBOUND SABounds[2];
SABounds[0].cElements = (DWORD)pRsHPASReports->RecordCount;
SABounds[0].lLbound = 0;
SABounds[1].cElements = 2;
SABounds[1].lLbound = 0;
VariantInit(pReportTypes);
pReportTypes->vt = VT_VARIANT | VT_ARRAY;
pReportTypes->parray = SafeArrayCreate(VT_VARIANT, 2, SABounds);
lLoop = 0;
while(! pRsHPASReports->IsEOF)
{
ldimension[0] = lLoop++;
ldimension[1] = 0;
CComVariant bstrTmp( pRsHPASReports->Fields->Item["RptType"]->Value );
TESTHR(SafeArrayPutElement( pReportTypes->parray, ldimension, &bstrTmp ));
ldimension[1]++;
CComVariant bstrTmp2( pRsHPASReports->Fields->Item["Title"]->Value );
TESTHR(SafeArrayPutElement( pReportTypes->parray, ldimension, &bstrTmp2 ));
pRsHPASReports->MoveNext();
}
With best wishes,
Vita
|
|
|
|
|
I have a simple COM server dll that creates dialogs through calls to interface methods. When creating the dialogs, the CWnd* is creating some difficulty for me (I think). The problem is that the main .exe (CFrameWnd) will dissapear (moves behind other windows) while the dialog is shown . I think the parent window is defaulting to NULL or some other window.
I pass in the HWND from the .exe main frame window to the interface method. I call CWnd::FromHandle(), and get a temporary window pointer. This pointer's m_hWnd doesn't match up with Spy++, but I'm not sure why this is?
I'm hoping that this is a simple problem, and that I'm doing something ridiculous.
Thanks for any help you can give.
Dave
|
|
|
|
|
What is the best way to register an ActiveX control created with MFC to the current user registry part to avoid administrator's right?
Best regards,
Paul.
Jesus Christ is LOVE! Please tell somebody.
|
|
|
|
|
I THINK NO WAY AT ALL..!!!
Code the Dreams.
|
|
|
|
|
What's the best way of passing a binary file through COM. For example, if I had a GIF file on my COM server and wanted to send it to a client then how would I go about it? I'm new to using COM and have only passed types like BSTR, etc.
Thanks
|
|
|
|
|
You can use an IStream (or ISequentialStream), or a SAFEARRAY of VT_UI1 (bytes), or even a BSTR if you wanted to. The first will result in more roundtrips, since you'd then call IStream methods to get the data, while the second (and the third is really a hack of the second) might mean that you need a lot of memory available if it was a big file (so not a GIF, then...)
Steve S
[This signature space available for rent]
|
|
|
|
|
Thanks loads Steve. Got it working using an IStream with the client grabbing 4K chunks. Is there an optimum erm.."chunk" size?
|
|
|
|
|
hi
I have embedded an excel spreadsheet in an ASP webpage. The problem occurs when the spreadsheet was repeatedly opened to populate data. The application becomes slow and eventually dies, with memory handles over 70 000!
I have used <object> to call the excel spreadsheet.
Could this be the reason? Can some one please help me with this?
Regards
|
|
|
|
|