|
Gil,
There maybe very simple shortcut:
you've already mentioned "if (RunEmbedded() || RunAutomated()) ", because you want it to register with OLE even when runningf from command line: just comment that if , so COleTemplateServer::RegisterAll(); or similar will be called.
May work...
"...Ability to type is not enough to become a Programmer. Unless you type in VB. But then again you have to type really fast..."
Me
|
|
|
|
|
Maybe my first post wasn't clear enough, but that's basically what I've done. It now looks like this:
COleTemplateServer::RegisterAll();<br />
if (RunEmbedded() || RunAutomated())<br />
{<br />
}<br />
else<br />
{<br />
COleObjectFactory::UpdateRegistryAll();<br />
}
That change is what allowed a .vbs script to attach to the server instance that was started from the command line instead of creating a new one. But the problem is that the application still disappears when I close the dialog which leaves the clients with no server.
Gil
|
|
|
|
|
OK, now that's clearer.
Yes, your script now attaches to running instance of singleton, even the one started from command line.
Anyway: try AfxOleSetUserCtrl(FALSE); and put it at the end of InitInstance or even in your FrameWnd::OnCreate.
Also, because now you have singleton -- you can easily build Debug version and use Debug facilities to see what's going on. In fact I'm often using that trick with COleTemplateServer::RegisterAll(); to debug my outproc servers (which are not singletons).
Regrds
"...Ability to type is not enough to become a Programmer. Unless you type in VB. But then again you have to type really fast..."
Me
|
|
|
|
|
Oops...I'm not at home and I realized it actually has a "return TRUE" if embedded to keep the dialog from activating when accessed via automation.
Like this:
COleTemplateServer::RegisterAll();
if (RunEmbedded() || RunAutomated())
{
return TRUE;
}
else
{
COleObjectFactory::UpdateRegistryAll();
}
Gil
|
|
|
|
|
Unfortunately the AfxOleSetUserCtrl(FALSE) didn't seem to fix the issue. I don't think I have a FrameWnd::OnCreate in a dialog based application do I?
Here's instruction for how to reproduce the problem that I posted to the C++ forum:
http://www.codeproject.com/script/comments/forums.asp?forumid=1647&fr=126#xx600114xx
If your willing to take a few minutes and create a new project you should be able to see the problem.
Gil
|
|
|
|
|
Thanks for the help. I posted another response to the C++ thread on this issue. One thing I notice is that when your using the proxy dialog interface and you've made your server a singleton, if you activate the dialog, run a .vbs script to access the application interface, and then close the dialog before the .vbs script finishes, the server does remain active due to the CanExit() code added to the dialog by ClassWizard. The problem is that the server doesn't destroy when all clients have released their objects. That's because the ClassWizard hasn't created a mechanism for the dialogs CanExit() logic to be called each time a CDlgProxy objects destructor runs. I manually added some code to do this and now it works.
Gil
|
|
|
|
|
That's because the ClassWizard hasn't created a mechanism for the dialogs CanExit() logic to be called each time a CDlgProxy objects destructor runs. I manually added some code to do this and now it works.
Gil,
Right. Default MFC Server implementation is designed for an invokation of the server only through either Automation or as standalone. Not both, as you are doing.
Therefore, what you've done, maybe not clean, but appropriate. There are probably other ways to tweak desired behavior, but if your solution works -- that's what needed. Right? Better sometimes is worse then good.
Regards
"...Ability to type is not enough to become a Programmer. Unless you type in VB. But then again you have to type really fast..."
Me
|
|
|
|
|
Hi!
I am very new to COM and ATL and try to implement something like this:
I have a simple COM server with the following interface:
[
object, ...
]
interface ITest : IUnknown
{
[id(1), helpstring("Methode GetInterface")] HRESULT GetInterface([in] int n, [out] ITest2** pITest2);
};
The interface method GetInterface should return a new pointer to the interface
ITest2 . This function should not work like QueryInterface , the
interface ITest2 is not in the same coclass as the ITest , it's in
another coclass.
This function should work like the following DirectX (DirectDraw) function CreateSurface :
LPDIRECTDRAW lpDD = NULL;
LPDIRECTDRAWSURFACE lpDDSPrimary = NULL;
...
HRESULT hError = lpDD->CreateSurface(&DDSurfaceDesc, &lpDDSPrimary, NULL);
...
How can I implement the GetInterface function?
The ITest2 interface (and the coclass of the interface) should not be creatable
with the CoCreateInstance , it should be only created by the GetInterface
method!
Daniel
---------------------------
Never change a running system!
|
|
|
|
|
One solution is containment. Another solution is aggregation given that you want the client to gain direct access to the inner COM object.
Kuphryn
|
|
|
|
|
Can you give my a sample application or a link to a tutorial?
Thanks!
Daniel
---------------------------
Never change a running system!
|
|
|
|
|
If I didn't misunderstand you
static HRESULT CComObject<Base>::CreateInstance(CComObject<Base>** pp)
should be the solution to your problem.
|
|
|
|
|
Any sample or link to a tutorial?
Thanks!
Daniel
---------------------------
Never change a running system!
|
|
|
|
|
Hello Daniel,
I created a sample ATL project with two simple coclass's (Test and Test2). One of them, Test2 is specifically noncreatable. This noncreatble feature can be set easily by including the "noncreatable" attribute for the coclass statement in the IDL file :
[
uuid(A6C64958-F337-4981-8F31-F35AEA02DD98),
helpstring("Test2 Class"),
noncreatable
]
coclass Test2
{
[default] interface ITest2;
[default, source] dispinterface _ITest2Events;
};
This attribute is very useful when your client apps are Visual Basic based. In VB, if a coclass is noncreatable, then when you attempt to create a new instance of it via the "New" keyword, e.g. :
Dim Test2Obj As Test2
...
...
...
Set Test2Obj = New Test2
You will get an error message that reads : "Invalid use of New keyword".
However, the "noncreatable" attribute is not sufficient for VC++ clients. In a VC++ client app, if you have the following statement :
ITest2Ptr spTest2Ptr = NULL;
spTest2Ptr.CreateInstance(__uuidof(Test2));
Surprise, surprise, you will still succeed and obtain an ITest2 smart pointer.
In order to ensure that the above CreateInstance() function call will fail, you will need to comment out the Test2 Object Entry in the ATL Object Map of your ATL project :
BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_Test, CTest)
//OBJECT_ENTRY(CLSID_Test2, CTest2) <-- comment out this line.
END_OBJECT_MAP()
This will ensure that when your ATL DLL is asked to create an instance of an object of coclass Test2 (this happens in the global DllGetClassObject() function), a failure code will be returned.
Note that the good thing about the "noncreatable" attribute and the commenting out of the OBJECT_ENTRY statement will not prevent you from internally creating the CTest2 object. This is, of course, required when the GetInterface() method is called. My implementation of GetInterface() is as follows :
STDMETHODIMP CTest::GetInterface(int n, ITest2 **pITest2)
{
// TODO: Add your implementation code here
CComObject<ctest2> *pTest2New = NULL;
CComObject<ctest2>::CreateInstance(&pTest2New);
if (pTest2New)
{
pTest2New -> QueryInterface (IID_ITest2, (void**)pITest2);
}
return S_OK;
}
I will email you the sample source codes plus VB and a VC++ client apps.
Hope the aboe info will help.
Best Regards,
Bio.
|
|
|
|
|
Hello Daniel,
Please email me your email address so that I can send to you some sample codes.
Best Regards,
Bio.
|
|
|
|
|
Thanks! It works fine!
Cheers,
Daniel.
--
FIND A JOB YOU LOVE, AND YOU'LL NEVER HAVE TO WORK A DAY OF YOUR LIFE.
|
|
|
|
|
I add an interface to an OCX,
when I use the OCX, it throw an exception and pop a message box "parameter not optional".
Why? who can tell me reason?
Thanks a lot!
|
|
|
|
|
Are you passing a VT_EMPTY or a VT_NULL?
Well, you shouldn't
|
|
|
|
|
Just my 2 cents:
On insertion your OCX maybe querying container for some ambient property not supported by your container.
"...Ability to type is not enough to become a Programmer. Unless you type in VB. But then again you have to type really fast..."
Me
|
|
|
|
|
I have an out-of-proc COM server. In one of the method of my COM server, I need Thread Id of the client application who is calling the method. Is there any way to get thread id fo client process in COM server code?
Regards.
|
|
|
|
|
One solution is to require the client to pass in its ID as one of the parameters.
Kuphryn
|
|
|
|
|
You are right, but this is not a solution for the problem. I was looking for an API to get thread id of COM client.
|
|
|
|
|
There is no such API to my understanding. If the client does not provide the server with more information, then there is nothing linking the them except for the pointer that the client holds and the reference count on the server-side.
Kuphryn
|
|
|
|
|
Is there a way (free, not commercial programs) to detect un-released COM
interfaces? I use alot of CComPtr and also regular interfaces and I want
to make sure that there are no problems with reference counting.
thanks
|
|
|
|
|
I guess you already use
_ATL_DEBUG_INTERFACES and _ATL_DEBUG_QI ?
|
|
|
|
|
Actually it's the first time I hear about those defines. But
aren't those for use in ATL projects? Besides, I tried searching
them in MSDN (web site) and found nothing.
Can you briefly explain what they do?
thank you
|
|
|
|