|
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!"
|
|
|
|
|
Are you sure that VB has generated a connnection point and not a custom event handler?
Michael
|
|
|
|
|
That's one of the problems with VB, it's hard to know exactly what's going on.
I guess my question should be, how do I create an event function that returns parameters from the client (without using a callback interface)?
Anyone have a clue on this one?
__scott
|
|
|
|
|
Why not just use the callback interface. It's easy to make in VC, and easy to use from VB...
- Anders
Money talks, but all mine ever says is "Goodbye!"
|
|
|
|
|
One of the good things about using connection points is that the client doesn't need to manage the connection to the incoming interface.
That is, to connect to the COM server callback interface, the client must pass a reference of itself to the server. Is there a way for the server to determine if the client is still there before calling the callback function? Is there a way for the server to implicitly connect to the client when the client instantiates an object from the server?
I'm not sure that made sense...oh well
__scott
|
|
|
|
|
SPENNER wrote:
I'm not sure that made sense...oh well
I know exactly what you mean. I just don't know of a solution...
- Anders
Money talks, but all mine ever says is "Goodbye!"
|
|
|
|
|
We have a communications ATL COM DLL used in a project here that used to load a Java COM object (on a web server) that communicates to a server running IMS transactions on a mainframe. The Java "object" was provided by the customer. Recently they "upgraded" to a newer component, an ActiveX DLL written in Microsoft J++. The old component wasn't a DLL, but a huge collection of Java class files. Because we couldn't import any DLL and had no Type Library to work with we had to do it the painful way, loading by ProgID (easy in VB, hard in ATL), getting the IDispatch pointer, and using Invoke.
This new version comes as a DLL which means I can easily #import the DLL itself and use that to make me a good ol smart pointer which I can use. That part was easy and appears to be fine. My smart pointer is using a single method in the new object called "processITOC". Visual Assist shows me that format of this sucker is:
_bstr_t processITOC ( BSTR * templatepath, BSTR * server, BSTR * port, BSTR * system, BSTR * UserId, BSTR * password, long * timeout, VARIANT * request, BSTR * sTranName );
Seems easy enough... more or less, I hate variants. However, every time I try to pass in the data, it blows with an Access Violation in MSVBVM60.DLL, 0xC0000005. I know this new DLL works fine because I can load it up in a VB project and use it just fine. However, in ATL it blows. I think I'm probably doing something really simple wrong but am currently lost. Could someone give me a hand?
_bstr_t Ret;
BSTR Template = L"file:///C:\\HostTemplates/";
BSTR LogDir = L"C:\\LOG\\";
BSTR Priority = L"3";
BSTR Mainframe = L"111.111.111.111";
WCHAR wchPort[10];
_itow(32000, wchPort, 10);
BSTR Port = wchPort;
BSTR User = L"user";
BSTR Password = L"password";
long Timeout = 240000;
BSTR System = L"DatabaseName";
BSTR TransID = L"ID";
VARIANT upArg;
VariantInit(&upArg);
V_VT(&upArg) = VT_BSTR;
V_BSTR(&upArg) = SysAllocString("ImAnXMLRequestwithtags");
m_pIHandler->setLoggingDirectory(&LogDir);
m_pIHandler->setLoggingPriority(&Priority);
Ret = m_pIHandler->processITOC( &Template,
&Mainframe,
&Port,
&System,
&User,
&Password,
&Timeout,
&upArg,
&TransID );
If someone could point something out I'd be grateful.
Thanks,
Matt
|
|
|
|
|
I have a COM object that returns a string to the calling program. It works perfectly under Win95(a) to Win2000. Under WinXP pro, it crashes in oleauto32 if returned as a BSTR, but passes successfully if passed as a safearray.
Any ideas? Thanks.
|
|
|
|
|
We have an ActiveX DLL containing both full controls and simple objects, implemented in C++ / ATL.
We've updated the library, and want to assign a new version number (say 2, instead of 1). If we edit the RGS and IDL files to reflect the new version number, our users find that the full controls aren't instantiated unless the registry contains the -old- version keys. When a VB project using the controls is opened, it recognizes that an updated version has been registered (asks if you want to update the project), but then can't instantiate the full controls.
There is no problem with simple controls, since there is no version number info for them in their registry entries. The problem is only exhibited with full controls.
What are we doing wrong? We've searched everywhere we can think of in MSDN and elsewhere for how to do this, but can't find any info. If someone can either answer or point us to documentation, we'd be greatly appreciative.
David Stranz
|
|
|
|
|
I've got this ActiveX Object (made w/ VC++6.0), it creates a thread (so i can have multiple running at the same time), but it also fires events to my Visual Basic App. With me creating threads cause problems for those events trying to get back to the application?
It seems that way. VB seems to crash when i Fire an event. When i use an activex control, does it have its own thread? Can i redirect the thread ID or something like that? It's just being flat out weird. Has anyone had the same trouble before? I set up connection points at the beginning when i made the obj., is there any other settings that i need to have? Even a little bit of help will go a long way for me...Thanks Y'all.
~TIM!
SHABBA!!
|
|
|
|
|
I need to be Free threaded. If you selected Apartment Threaded when you created the object it will fail.
Go into the rgs-file, and check the threading model, it should say "Free" and not "Apartment" or something else...
- Anders
Money talks, but all mine ever says is "Goodbye!"
|
|
|
|
|
As well as that, you need to initialise it as multithreaded. Do this in your thread function.
G.Luck
|
|
|
|
|