|
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
|
|
|
|
|
Hello, I'm learning about COM and COM+ and will eventually (when I understand it properly) port a legacy MFC business application I'm responsible for into separate COM components created using ATL.
I'm starting to get an early grasp on things and have done a lot of reading and experimentation, but I have a practical question that doesn't seem to be answered in any of my COM books or anywhere in MSDN:
How much of a large application with many different components should a single .dll server ATL project contain?
Specifically: lets say I have a largish application that will consist of 3 tiers (not counting the presentation layer which is a separate application consuming the COM objects):
Collection and business objects layer
Transaction objects layer (for persistence to database and retrieval)
Data layer (OLEDB - SQL server)
Each business object (and their collection objects) will each have a mirrored transaction (persistence) object "below" them just "above" the data layer to allow for database indpendance among other things.
Most components will use other components (for example a Customer component will use an Address book component etc).
Should I build my .dll files to incorporate all related objects from all tiers into each .dll (for example a Suppliers collection, supplier object and their associated Supplier transaction objects in one ATL project (.dll file))?
Or should I build components of a similar tier into a single ATL project (.dll) file?
My guess is that they should be split tier by tier and then within each tier split again by business object to support re-use later depending upon how re-useable (and independant of other components) they will be.
The end result though could be dozens to hundreds of separate .dll files for my potential application.
If this is the case, is there a penalty for too much granularity this way?
What would be a practical "rule" for this? (I know, the answer probably is it depends
|
|
|
|
|
First, if the clients are ever going to execute remotely, I would suggest 'exe' and not 'dll'.
Second, I have migrated a previous COM solution involving a bunch of dll's into a single exe with dozens of pieces to it. One huge benefit is that you don't have to worry about different versions getting mixed together. When you have to make an inevitable change, instead of adding a bunch of version cross-checking in your dll's, you just update the single exe and not worry about it.
You may even find that some of your data layer is no longer needed. Some information is more easily and more efficiently maintained as global variables within this single process.
|
|
|
|
|
I was hoping someone could explain an easy way to serialize a COM or ActiveX object in VB.NET or C#. What I am trying to do is save the state of the Office XP Web Components (a spreadsheet to be specific) which are COM based and no matter what I have tried it has failed.
Do I HAVE to write a wrapper class that implements the Serializable attribute? Or is there a simpler way I just can’t find. I have even tried storing OcxState but can’t seem to figure out how to get it onto disk.
Aaron Luke Richey
|
|
|
|
|
If you know how to do this using raw C/C++ code (IPropertyBag interface), I believe you'll soon get it done with other languages.
In addition to posting in the right forum (isn't your question about .NET after all ? ), have you tried to cast one of the AxHost member (such as OcxState) to IPropertyBag ?
A good way to try this is to derive a class from AxHost so you access protected members. Also, use Anakrino[^] to disassemble the AxHost internals.
Back to real work : D-21.
|
|
|
|
|