|
I stand corrected, particularly in that an apartment is not a thread. I do find this topic hard to describe correctly and I think so does microsoft. I think the tangle comes with confusing the process of execution with the description of how it is to take place. And STA? Double whoops, you are right on that as well.
Geoffrey Feldman
geoff@seabasecns.com
|
|
|
|
|
How to understanding marshaling !
It is a bridge of commumication between proxy and stub code.
COM
|
|
|
|
|
Can you be a little more specific with your question?
Marshaling is just a term for the serialization of a routine's arguments. This allows for the call to be sent over a wire to another thread/process/machine. Then the return values are marshaled and returned to the calling process.
When you create an IDL file and compile it, you can also generate the proxy code which will do all the marshaling for you. Once this code is compiled and registered (and installed on the machines in question), COM will automatically load the proxy to marshal the calls.
Tim Smith
Descartes Systems Sciences, Inc.
|
|
|
|
|
I'm trying to implement IOleCommandTarget in my BHO class, using the following code:
// IEPowerUp.h : Declaration of the CIEPowerUp
#ifndef __IEPOWERUP_H_
#define __IEPOWERUP_H_
#include "resource.h" // main symbols
/////////////////////////////////////////////////////////////////////////////
// CIEPowerUp
class ATL_NO_VTABLE CIEPowerUp :
public CComObjectRootEx<ccomsinglethreadmodel>,
public CComCoClass<ciepowerup, &clsid_iepowerup="">,
public IOleCommandTarget,
public IObjectWithSiteImpl<ciepowerup>,
public IDispatchImpl<iiepowerup, &iid_iiepowerup,="" &libid_test2lib="">
{
public:
CIEPowerUp();
DECLARE_REGISTRY_RESOURCEID(IDR_IEPOWERUP)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CIEPowerUp)
COM_INTERFACE_ENTRY(IIEPowerUp)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IOleCommandTarget)
COM_INTERFACE_ENTRY_IMPL(IObjectWithSite)
END_COM_MAP()
// IOleCommandTarget
public:
STDMETHODIMP CIEPowerUp::QueryStatus(const GUID* pguidCmdGroup,ULONG cCmds,OLECMD prgCmds[],OLECMDTEXT* pCmdText);
// IObjectWithSite
public:
STDMETHOD(SetSite)(IUnknown* pUnkSite);
// IIEPowerUp
public:
STDMETHOD(InitHooks)(BOOL fUnload = false);
public:
CComQIPtr<iwebbrowser2, &iid_iwebbrowser2=""> m_spWebBrowser2;
protected:
HWND m_hWnd;
IInputObjectSite* m_pSite;
public:
BOOL m_bCtrlDown;
POINT m_pMPoint;
int m_iStatus;
int m_iLastStatus;
DWORD m_LastTime;
DWORD m_DelayAmount;
};
#endif //__IEPOWERUP_H_
Unfortunately, I get the following compile errors. Can anyone help me figure out what I'm doing wrong?
--------------------Configuration: Test2 - Win32 Debug--------------------
Compiling...
IEPowerUp.cpp
Test2.cpp
d:\program files\microsoft visual studio\vc98\atl\include\atlcom.h(1827) : error C2259: 'CComObject<class ciepowerup="">' : cannot instantiate abstract class due to following members:
d:\program files\microsoft visual studio\vc98\atl\include\atlcom.h(1823) : while compiling class-template member function 'long __stdcall ATL::CComCreator<class atl::ccomobject<class="" ciepowerup=""> >::CreateInstance(void *,const struct _GUID &,
void ** )'
d:\program files\microsoft visual studio\vc98\atl\include\atlcom.h(1827) : warning C4259: 'long __stdcall IOleCommandTarget::Exec(const struct _GUID *,unsigned long,unsigned long,struct tagVARIANT *,struct tagVARIANT *)' : pure virtual function was
not defined
d:\program files\microsoft visual studio\vc98\include\docobj.h(1453) : see declaration of 'Exec'
d:\program files\microsoft visual studio\vc98\atl\include\atlcom.h(1823) : while compiling class-template member function 'long __stdcall ATL::CComCreator<class atl::ccomobject<class="" ciepowerup=""> >::CreateInstance(void *,const struct _GUID &,
void ** )'
d:\program files\microsoft visual studio\vc98\atl\include\atlcom.h(1827) : error C2259: 'CComObject<class ciepowerup="">' : cannot instantiate abstract class due to following members:
d:\program files\microsoft visual studio\vc98\atl\include\atlcom.h(1823) : while compiling class-template member function 'long __stdcall ATL::CComCreator<class atl::ccomobject<class="" ciepowerup=""> >::CreateInstance(void *,const struct _GUID &,
void ** )'
d:\program files\microsoft visual studio\vc98\atl\include\atlcom.h(1827) : warning C4259: 'long __stdcall IOleCommandTarget::Exec(const struct _GUID *,unsigned long,unsigned long,struct tagVARIANT *,struct tagVARIANT *)' : pure virtual function was
not defined
d:\program files\microsoft visual studio\vc98\include\docobj.h(1453) : see declaration of 'Exec'
d:\program files\microsoft visual studio\vc98\atl\include\atlcom.h(1823) : while compiling class-template member function 'long __stdcall ATL::CComCreator<class atl::ccomobject<class="" ciepowerup=""> >::CreateInstance(void *,const struct _GUID &,
void ** )'
Generating Code...
Error executing cl.exe.
Test2.dll - 2 error(s), 2 warning(s)
|
|
|
|
|
I found the lines that are causing the errors. There're located in Test2.cpp (contains the regular regsvr32 functions):
BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_IEPowerUp, CIEPowerUp)
END_OBJECT_MAP()
|
|
|
|
|
Hint: pure virtual function was not defined. You forgot to put the Exec() method in your class.
--Mike--
My really out-of-date homepage
"Why does anyone have a web page? Too much free time... not enough friends... justifying owning a computer." -- Noel Crane on Felicity
Sonork - 100.10414 AcidHelm
Big fan of Alyson Hannigan.
|
|
|
|
|
Augh! I've spent hours and hours trying bunchs of different variations of implementing it, and it all comes down to this .
Thank you so much; it's working perfectly now!
|
|
|
|
|
How would i go about using IDirectDraw7 and IDirecDrawSurface7 inside my ATL type library.
The DirectShow IDL's do this but i cannot figure out how.
I've tried using "import "DDrawex.h" and "include "ddrawex.h" but these give type redefinitions.
Here's a clip from DirectShow's DDStream.idl
import "unknwn.idl";
import "mmstream.idl";
cpp_quote("//")
cpp_quote("// The following declarations within the 'if 0' block are dummy typedefs used to make")
cpp_quote("// the ddstream.idl file build. The actual definitions are contained in DDRAW.H")
cpp_quote("//")
cpp_quote("#if 0")
typedef void * LPDDSURFACEDESC;
typedef struct tDDSURFACEDESC DDSURFACEDESC;
cpp_quote("#endif")
cpp_quote("#include <ddraw.h>")
enum {
DDSFF_PROGRESSIVERENDER = 0x00000001
};
interface IDirectDraw;
interface IDirectDrawSurface;
interface IDirectDrawPalette;
interface IDirectDrawMediaStream;
interface IDirectDrawStreamSample;
// IDirectDrawMediaStream
[
object,
local,
uuid(F4104FCE-9A70-11d0-8FDE-00C04FD9189D),
pointer_default(unique)
]
interface IDirectDrawMediaStream : IMediaStream
{
HRESULT GetFormat(
[out] DDSURFACEDESC *pDDSDCurrent,
[out] IDirectDrawPalette **ppDirectDrawPalette,
[out] DDSURFACEDESC *pDDSDDesired,
[out] DWORD *pdwFlags);
....continued......
mmstream.idl doesn't use the directdraw interfaces at all.
Doing this gives me
error MIDL2337 : unsatisfied forward declaration : IDirectDrawSurface7
is there any way to do this?
"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken
Bobby Ward
|
|
|
|
|
The application that I'm working on has an OnIdle() handler. It was written by someone else - despite my suggestion that a timer would better suit the situation. :P
Now, I've added a few more ATL objects (the project already had a few), and for some strange reason, simply having the object created at initialization time causes an OnIdle() call after the App has closed and cleared some of it's state.
class CMyObject :
public CComObjectRootEx<CComSingleThreadModel>,
public IMyInterface {
...
};
class CMyApp : public CWinApp {
...
CComObject<CMyObject> *m_pObj;
...
BOOL OnIdle(long);
void Init();
...
};
void CMyApp::Init() {
...
CComObject<CMyObject>::CreateInstance(&m_pObj);
...
}
BOOL CMyApp::OnIdle(long) {
...
CMainFrame *pMF = static_cast<CMainFrame *>(m_pMainWnd);
...
}
The initialization goes fine, and hell it has nothing to do with the App or main frame. Then, when I close the application, it crashes because OnIdle() is getting called AFTER the App state has been cleared, and pMF is NULL.
Does simply creating an ATL object somehow screw around with the application message queues? Is the OnIdle() getting called from another thread? My ATL objects are all using CComSingleThreadModel...
J
|
|
|
|
|
If anyone's curious as to what the hell I was babbling about, I found the problem.
The trouble is, when the CMainFrame closes, it calls AfxOleCanExitApp() to check if there are any outstanding object references. If there are, the frame gets hidden but NOT destroyed. That's why OnIdle() was still being called, and why it was dying when it tried to use the CMainFrame.
Now, my problem has changed. I have to find a way to release all my objects before the main window gets closed. Seems a little odd...
J
|
|
|
|
|
Not Odd, that's the correct way to go. You must get the object pointer and
release it in OnDestroy(). For ActiveX, you should not have to do this since
CWnd does it for you.
|
|
|
|
|
I agree, it makes sense for graphic components and ActiveX controls. However, the object to which the dangling reference belongs is an Active Script engine, and is currently owned by the App. If I simply move it to the main frame, everything will probably work.
But that doesn't fit the conceptual layout of our application. We have a scripting engine that gets created when the application starts, and killed when the application ends. That makes more sense than a scripting engine that gets created and destroyed with the frame window...
J
|
|
|
|
|
I have a com object in a local server (ATL) with one method that just sets some dummy output data. If I set the parameter type to be:
[out] long* pLong
then it at least works in release mode (I can get the value from a different process). If I set the parameter type to be:
[out] BSTR* pString
then it will generate a "out of memory error". Both versions won't work in debug mode.
My question is, how do I specify output parameter type if it is not an in-proc-server?
|
|
|
|
|
The IDL used for returning data described is correct. The problem will be in how the data is being assigned to the pString. Can you post some more code?
Michael
|
|
|
|
|
For the case of the "[out] long* pLong" parameter, it is:
*pLong = 1000; // I can get this value in another process
For the case of the "[out] BSTR* pString" parameter, it is:
*pString = ::SysAllocString(L"This is an output string");
|
|
|
|
|
Dir forum,
I am a beginner in ATL, WTL, and COM. I want to write a WTL a program like IE. And I found a article in Codeproject. It is "Using WTL's Built-in Dialog Resizing Class" by Michael Dunn. I like his articles very much! But I don't know how to capture IE event like OnDocumentComplete and others, to disable and enable some key like Stop, Back, Forward ...
If you have another project to demo. Please show it to me!
Thank you very much!
|
|
|
|
|
There are a few questions. I am desperately seeking answers. Please do reply if you know any of them as it will save me a lot of time.
#1. What exactly is an apartment? Do we mean a method / function? What if a method call to a COM object internally calls another method of the same COM object? Will it still be ONE apartment?
#2. Do we ever need proxy / stubs for COM objects packaged as DLLs? Can you please come up with a scenario? DLLs are in-process so what process is the stub part of?
#3. This last one is lengthy and will require some concentration:
I have Beginning ATL 3 COM Programming (borrowed from Safri Ustaad). According to the example in the book (bare bone pure C++ COM implemented as a DLL), a COM class implementing IFoo should have these: a CFoo class implementing IFoo (and thus IUnknown) and a CClassFactory class implementing IClassFactory (and thus IUnknown). The DLL should have a method DllGetClassObject that should call CreateInstance of CClassFactory which should internally create a new CFoo and call it's QueryInterface. The pointer to CFoo should be returned by DllGetClassObject. However, to the best of my experiments, things are not working this way. I am afraid the book is wrong.
The call to DllGetClassObject should not call CreateInstance; instead it should return a pointer to CClassFactory. The CoCreateInstance of COM mechanism will then _itself_ call CreateInstance on this pointer (as it implements IClassFactory). The CreateInstance should then create a new CFoo and call it's QueryInterface and return it to the caller.
In short, the difference is between the stuff returned by DllGetClassObject and calling CreateInstance of CClassFactory. Do tell me whether my hypothesis is right or wrong as I am still not confident that the book from Wrox has such an error. Overall, the book is an excellent introduction to ATL programming and there are a couple of chapters on the background theory.
Waiting for a response....
Muhammad Ali Shah
~~~~~~~~~~~~~~~
Our scientific power has outrun our spiritual power. We have guided missiles and misguided men (Martin Luther King Jr)
|
|
|
|
|
Right. The DllGetClassObject gets an interface to the class factory for the .dll, not any particular object in the .dll. This will then be used to handle calls to CoCreateInstance by the run time. Client code does not need to be aware of the existence of the class factory.
Here's an excerpt from the documentation for the function. In the generic ATL code generated for you in ATL COM projects, you'll get a class factory, and an implementation of DllGetClassObject. The class factory will tie together the CLSID's for all of the objects that it knows how to create to the actual implementing classes through the OBJECT_MAP.
You could do something similar in raw C++, you just need to tie together the CLSID's with the actual classes for your implementation of a class factory. The DllGetClassObject will just return an interface to the the class factory, which does all of the real work.
STDAPI DllGetClassObject(
REFCLSID rclsid, //CLSID for the class object
REFIID riid, //Reference to the identifier of the interface
// that communicates with the class object
LPVOID * ppv //Address of output variable that receives the
// interface pointer requested in riid
);
Parameters
rclsid
[in] CLSID that will associate the correct data and code.
riid
[in] Reference to the identifier of the interface that the caller is to use to communicate with the class object. Usually, this is IID_IClassFactory (defined in the OLE headers as the interface identifier for IClassFactory).
ppv
[out] Address of pointer variable that receives the interface pointer requested in riid. Upon successful return, *ppv contains the requested interface pointer. If an error occurs, the interface pointer is NULL.
|
|
|
|
|
I've been wondering about marshalling issues in the following senerio
ObjA - Is a single-threaded ATL COM object singleton
ObjA is instantiated in Application A. Sometime later Application B is started and cocreates ObjA. Since it is a singleton they both have the same instance. My questions are whether their are any marshalling issues that have to be address because ObjA was created in a different process. Would it matter if ObjA where multi-threaded.
|
|
|
|
|
Yes, you need to synchronize method and property in your object with Semaphore
and critical section (your choice...). I did the same thing with a Local server
Component and it works really fine.
|
|
|
|
|
Thanks, but my questions were about marshaling not synchronization. I don't see synchronization as an issue since the object is single-threaded. Obviously a multi-threaded object would require it.
|
|
|
|
|
I have an apartmented ATL server program running on W2K at work. Now mangement has decided to run it on a fancy, spaning new machine with 1 gig ram, dual processors, and 4 90-gig hard drives.
Question: is it possible to change to server program to take advantage of the dual-processing capabilities? If it is, how? Is there a book or white paper some place that explains how to do that ?
|
|
|
|
|
just install windows2000 adn make it recognize that the server runs on dual processor. thats it. It will take care. Yes. there are ways in win32 in which u can use the dual processor feature and control them. But then that will defeat the idea on COMponent at all, because it will becomes windows proprietary
Ganesh Ramaswamy
|
|
|
|
|
I've created an ActiveX control with VC++ 6.0, and i try to call CoInitializeEx() at the beginning of a worker thread, but it doesnt recognize the API, and all I get is an undeclared identifier error for that
and COINIT_MULTITHREADED;
I linked to "ole32.lib" and i threw in <objbase.h> in for kicks at the top of the .cpp and in a separate case, the .h
I AM LIKE ----------------| |-------------------
^
THIS CLOSE
to getting this crap... i dont have a clue... i've running the project on a different machine as well and i get the same errors. i've tried to throw in just about every other library as well... am i missing a library? Could someone show me what libraries they link to in a project that works? Any suggestions would be so helpful...
Thanks,
~Tim
SHABBA!!
|
|
|
|
|
CoInitializeEx requires either NT 4.x or greater or Win 98 (Win 95 with DCOM).
Try either #define _WIN32_DCOM or #define WIN32_WINNT 0x0400.
Michael
|
|
|
|