|
Which interfaces?
Are you talking about IUnknown and IDispatch?
Michael
|
|
|
|
|
Hey guys and gals,
I've read some things on MSDN about trying to fire events from an ActiveX Control written in VC++ 6.0, but i just cant seem to get it. Is there any way to raise an event and get it to the main program from a worker thread? Is there any way you can explain this so that i can "comprehend" it? Can i just get some basics on how to do it? and if you do something strange, try to explain it.. (like any MFC Macro stuff cuz i really never use MFC if i dont have to) just do it in steps! 1.2.3.4.5.! <sigh> I'd love to hear a different insight on all of this... it's been bugging me for about a month, and i've been able to work around it, and now it's time to fix it.
SHABBA!!
|
|
|
|
|
It's a lot more complicated that it deserves an article by its own:
1) Yes you can fire even from a different thread but you need to make
sure that your component is MTA and not STA.
2) call CoInitializeEx(NULL, COINIT_MULTITHREADED) in the secondary thread;
and make sure your object is thread safe.
3) Since I have never used MFC to create ActiveX control, I don't know about
MFC Macro stuff for ActiveX.
4) In ATL, the wizard will create template file correctly for you if you
are using MTA or Free Thread marshaling.
This is just to help you start!
Good luck
|
|
|
|
|
it sounds like it would do the trick, but for some reason it wont recognize the header file <objbase.h>
which is where i'm supposed to get it from, and i am also linking to
ole32.lib as well, and it still says that it doesnt recognize the function...
i did use MTA just for the record..
but i also used an MFC ActiveX Control Wizard instead of ATL COM, which i had tried before, but i didnt add a control, so i'm gonna try that...
SHABBA!!
|
|
|
|
|
For your linking problem, I have no clue but as far as calling
CoInitializeEx from all threads that access the ActiveX
control, it should work. In the main thread, call CoInitializeEx in InitInstance(),
don't forget to call CoUninitialize() .
Good luck!
|
|
|
|
|
Hi,
I never succeeded firing Event directly from
Worker thread.
But one work-around way is to use Thread Messages.
You can use PostMessage(...) in your worker thread
to post a message to the main thread.
and in the Message Handler you can fire your Event.
Thanks
Firoz
|
|
|
|
|
i've tried that to no success... i'm gonna try CoInitializeEx(), and if that doesnt work, this is probably the only other way (that i feel like doing) that's not too much work. But i did try it, and it didnt work, i think it's because i didnt have a handle to the Window... and then people said to make an invisible window, and they just stopped. and didnt show you how... so that's where i'm at on that path.
SHABBA!!
|
|
|
|
|
Hi Shabba,
Ooops..I forgot to mention that.
You are right, you need a Window.
The steps are very simple...
...some modifications to your CoClass.
For Creating the Window ...
^^^^^^^^^^^^^^^
1) #include <atlwin.h>
2) Derive your CoClass from CWindowImpl<Your CoClass Name> .
3) DECLARE_WND_CLASS("Your CoClass Name")
4) Implementation for FinalConstruct() and FinalRelease().
In FinalConstruct(), you create the Window. and,
In FinalRelease(), you destroy the Window.
For Handling UserDefined Thread messages ...
^^^^^^^^^^^^^^^^^^^^^^^^^^
5) The MessageMap macro...
BEGIN_MSG_MAP(Your CoClass)
MESSAGE_HANDLER(500, OnUserMessage)
END_MSG_MAP()
6) Implementation for OnUserMessage() handler function.
Now, inside this handler, you can fire your COM Event.
Thats it.
Now in your Worker ThreadProc, whenever you want to fire the event,
use PostMessage(...).
Note: Postmessage needs HWND.
You can do either of this...
1) use HWND_BROADCAST or
2) use the HWND returned when you created the Window (in FinalConstruct()).
eg. ::PostMessage(HWND_BROADCAST,500,0,0);
Firoz
The following sample code may be Helpful...
#ifndef __LAWORKTHR_H_
#define __LAWORKTHR_H_
#include "resource.h"
#include "LAWorkThreadExeCP.h"
#include <atlwin.h>
class ATL_NO_VTABLE CLAWorkThr :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CLAWorkThr, &CLSID_LAWorkThr>,
public IConnectionPointContainerImpl<CLAWorkThr>,
public IDispatchImpl<ILAWorkThr, &IID_ILAWorkThr, &LIBID_LAWORKTHREADEXELib>,
public CProxy_ILAWorkThrEvents< CLAWorkThr >,
public CWindowImpl<CLAWorkThr>
{
public:
CLAWorkThr()
{
}
DECLARE_REGISTRY_RESOURCEID(IDR_LAWORKTHR)
DECLARE_NOT_AGGREGATABLE(CLAWorkThr)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CLAWorkThr)
COM_INTERFACE_ENTRY(ILAWorkThr)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
END_COM_MAP()
BEGIN_CONNECTION_POINT_MAP(CLAWorkThr)
CONNECTION_POINT_ENTRY(DIID__ILAWorkThrEvents)
END_CONNECTION_POINT_MAP()
DECLARE_WND_CLASS("CLAWorkThr")
HRESULT FinalConstruct()
{
HWND hwnd = Create(::GetDesktopWindow(),CWindow::rcDefault,"MyAtlWindow",WS_POPUP);
g_Myhwnd = hwnd;
if (hwnd)
return S_OK;
else
return HRESULT_FROM_WIN32(GetLastError());
}
void FinalRelease()
{
if (m_hWnd != NULL)
{
DestroyWindow();
}
}
BEGIN_MSG_MAP(CLAWorkThr)
MESSAGE_HANDLER(500, OnUserMessage)
END_MSG_MAP()
LRESULT OnUserMessage(UINT uMsg, WPARAM wpar, LPARAM lpar, BOOL& bHandled)
{
Fire_MyEvent();
return 0;
}
public:
STDMETHOD(MyMethod)();
};
#endif //__LAWORKTHR_H_
|
|
|
|
|
I see where you are going with this. Let say you have two threads in your
object (GUI and Worker threads). Your suggestion is to post a message to the
GUI thread then fire the event from the GUI thread. Yes it will work but
can become quite complicate if you have many events. But CoInitializeEx
can do the trick. Again it must be called for in every thread that access your object.
I may write an article how to do this as soon I find the time.
|
|
|
|
|
Hi all,
I recently wrote some code for a company to import contacts into Outlook from an access database. This cannot be done via Import.
My problem is that with the VBA code running at a stupidly slow speed through a macro I decided to use Visual C++ and automate Outlook. It runs much better but I have one problem, how do I add extra user properties to an outlook contact?
The code in VBA is:
Set Prop = c.UserProperties.Add("Yours", olText)
How do you do it in C++ though?
Any help appreciated.
Cheers,
James.
|
|
|
|
|
Hi,
Actually I want to add band objects in my app which hosts Web Browser control. Like IE adds bands objects (to the rebar control), I want to do the same in my app. I have gone thru a lot of topics regarding the band objects and all give ideas about how to develop it but not how to add band objects in my app.
Any help would be highly appreciated.
Thanks,
Perumalla Koteswara Rao, (B.Tech)
Computer Science & Engineering,
Hyderabad, Inida - 500072
|
|
|
|
|
Hi guys.
I have an ATL module with an outgoing dispinterface. I have no problem implementing an sink interface using MFC or ATL.
But now I'm working on a strait C++ project, no MFC and no ATL, where I need to create an sink interface.
Could someone give me some hints on how to implement this? All the information I have been able to find assumes that MFC or ATL is beeing used.
TIA
.Henrik
|
|
|
|
|
Since sink interfaces are dispinterfaces, you will have to implement IDispatch on your object. This also implies you'll have to implement IUnknown, since IDispatch is derived from it. Your version of the Invoke method will basically switch on the dispid of the event, unpack the event parameters from the DISPPARMS struct, and delegate to whatever method you want to be invoked when the event is fired. You will also need code for advising and unadvising the connection point.
So for IUknown, you need an implementation of QueryInterface, AddRef and Release.
For your implementation of IDispatch for the event interface, you can proably take some shortcuts and just implement Invoke, and return E_NOTIMPL from the remaining methods, since the Connection Point would only make use of this method to fire events.
Make sure your object is publicly derived from IDispatch. Your implementation for QueryInterface can then just use a static cast of the this pointer to implement QueryInterface. Look at the ATL code that does this for normal objects for an example.
Good Luck!
|
|
|
|
|
I use ATL COM Appwizard to create ActiveX,
I insert new "full controll" and in the "Stock Properties"
tab I add "Background color" and "Background Style".
when I test ActiveX in "ActiveX control text container"
there were not any propertypage for background color and
background style.
Should I add any code for it?
|
|
|
|
|
Hi!
I am trying to use a dll hosted through DllHost.exe on a remote machine.
Whn I try to run CoCreateInstance, my client (which is trying to access this dll on the remote machine) hangs, with no response.
I tried to find out the problem by running OleView on the remote machine and slecting CreateInstance on the component. However I get this error:
"CoGetClassObject" failed.
Any recommendations?
I have already registered the dll in question and also the proxy/stub
Thanks in advance!
|
|
|
|
|
It sounds like the COM Runtime could not find the class factory.
Here are some reasons:
1) your COM server is not registered in your client machine to be used remotely (if you use the implicit settings in the registry).
2) your COM server is not well registered in the server machine.
3) your COM server file (DLL) does not export the DllGetClassObject() method (seldom, but I already met it).
I have written an article about "COM Macro-Architecture" (http://www.codeproject.com/com/macrotopomain.asp) where I show out different configurations for the COM server and the client application.
You should have a look at the cases 8 & 9.
Joao
|
|
|
|
|
Hi,
could anybody explain please the reason for QueryInterface's second parameter being a double pointer?
Thanks
PP
|
|
|
|
|
I believe it is so QueryInterface can return a pointer.
Hope this helps,
Bill
|
|
|
|
|
Hi,
Let us start from the begining of the C/C++ language without COM. In the C/C++ language, whenever you have a class which contains at least ONE Virtual Function/Pure Function, a virtual table will be created at run time for this class which contains a list of the virtual functions in that class, and a Hidden pointer which called _vPtr is returned, this pointer points to the first entry in the virtual table.
Let us back to the COM world, QueryInterface is a method in the IUnknown interface, and IUknown interface is accessing the functionality of the component through virtual table.
The interface which returned from the QueryInterface is NOT poiting to the virtual table directly, it points to the hidden pointer _vPtr which points to the virtual table. For this reason we have pointer to pointer.
Regards,
ShadiK.
Shadi Al-Kahwaji
|
|
|
|
|
I have a COM server using MFC (.exe)
It has some methods to remote control it, eg. like that in VB
MyApplication = CreateObject(MyApplicationname.Application)
MyApplication.DoSomething
or has some methods who returns "built in" datatypes eg:
aInteger = MyApplication.returnaingeger
aBstring = MyApplication.returnaBstring
That was pretty easy to do, in fact all work was done by the class wizzard...
Now my problem:
I need to return a other COM object or class like that:
aClass = MyApplication.returnaClass
so I could do something like that:
aClass.somevalue = 1
Could anybody give me a hint how to do that, eg. point me to an article?
|
|
|
|
|
You create the other COM object with an IDispatch-derived interface, then return that IDispatch pointer as the [out, retval] parameter to the call.
Example from one of my controls (an X-Y data plot - IAxis is the COM object I want to return):
-> IDL:
[
object,
uuid( /* GUID */),
dual,
helpstring("IDataplot Interface"),
pointer_default(unique),
nonextensible
]
interface IDataplot : IDispatch
{
/* ... */
[ propget,
id(5),
helpstring("property AxisX")]
HRESULT AxisX(
[out, retval] IAxis * * ppVal );
}
-> C++ .h file:
STDMETHOD(get_AxisX)(/*[out, retval]*/ IAxis * * ppVal );
-> C++ .cpp file:
STDMETHODIMP CDataplot::get_AxisX( IAxis * * ppVal )
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
if ( 0 == ppVal )
return E_POINTER;
*ppVal = 0;
HRESULT hRes = S_OK;
CComObject< CAxis > * pObj = 0;
try
{
hRes = CComObject< CAxis >::CreateInstance( &pObj );
if ( SUCCEEDED( hRes ) )
{
hRes = pObj->QueryInterface( IID_IAxis, (void * *)ppVal );
assert( SUCCEEDED( hRes ) );
}
}
catch( ... )
{
hRes = E_OUTOFMEMORY;
*ppVal = 0;
}
return hRes;
}
I hope this is legible - the message editor on this site is less than adequate for replying. Whose bright idea was it to set the width of the editing window to 20 characters, with automatic wrapping?
Regards,
David
|
|
|
|
|
Does anyone know the trick to getting a connection point method to pass parameters by reference? Below is an example of a simple event, which should return a short from the client, but the variant varResult always returns empty?!?
Any ideas?
IDL:
[
uuid(48053E7C-D307-40D2-A380-3B9CB25282AB),
version(1.0),
helpstring("atl_event 1.0 Type Library")
]
library ATL_EVENTLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
[
uuid(224E5ED5-D64E-4556-A785-5ACE0DD8F0B3),
helpstring("_IEventTestEvents Interface")
]
dispinterface _IEventTestEvents
{
properties:
methods:
[id(1), helpstring("method TestEvent")] HRESULT TestEvent([in, out] short* sVar );
};
[
uuid(840EF1AE-F80F-4F71-9802-03DFE6555B19),
helpstring("EventTest Class")
]
coclass EventTest
{
[default] interface IEventTest;
[default, source] dispinterface _IEventTestEvents;
};
};
C++:
template <class t="">
class CProxy_IEventTestEvents : public IConnectionPointImpl<t, &diid__ieventtestevents,="" ccomdynamicunkarray="">
{
//Warning this class may be recreated by the wizard.
public:
HRESULT Fire_TestEvent(SHORT * sVar)
{
CComVariant varResult;
T* pT = static_cast<t*>(this);
int nConnectionIndex;
CComVariant* pvars = new CComVariant[1];
int nConnections = m_vec.GetSize();
for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
{
pT->Lock();
CComPtr<iunknown> sp = m_vec.GetAt(nConnectionIndex);
pT->Unlock();
IDispatch* pDispatch = reinterpret_cast<idispatch*>(sp.p);
if (pDispatch != NULL)
{
VariantClear(&varResult);
pvars[0] = *sVar;
DISPPARAMS disp = { pvars, NULL, 1, 0 };
pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
}
}
delete[] pvars;
// *sVar = varResult.iVal;
return varResult.scode;
}
};
__scott
|
|
|
|
|
SPENNER wrote:
[id(1), helpstring("method TestEvent")] HRESULT TestEvent([in, out] short* sVar );
Woops, you can't have out parameters on a connection point event function...
If you need a parameter back from the client, you need to implement a callback interface instead of using connection points.
- Anders
Money talks, but all mine ever says is "Goodbye!"
|
|
|
|
|
That's odd...
Because, and I know this isn't the best example, but if I create a quick COM object with VB and define an outgoing interface with a byref parameter, it works great. The resulting IDL is below:
[id(0x00000001)]
void TestEvent(
[in] short eventByVal,
[in, out] short* eventAsRef,
[in, out] VARIANT_BOOL* eventBoolRef);
So, I'm thinking there must be a C++/ATL equivalent, but I can't figure it out...I know I could use a call back interface, but using a connection point would make it more straight forward from the client side...
Any idea how to get this to work?
__scott
|
|
|
|
|
SPENNER wrote:
Any idea how to get this to work?
Nope, not right now. I have the "Inside ATL" book, but I left it at work...
I'll try to see if there's a solution in there... (on monday when I get to work...)
- Anders
Money talks, but all mine ever says is "Goodbye!"
|
|
|
|
|