|
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
|
|
|
|
|
Use COM aggregation: OuterObject ICar, inner aggregated object IVehicle.
Have a VB scripting client.
When I create the (outer) car object, IntelliSense only shows me the methods and properties of this one (as in the IDL it is defines as the [default] interface for the coclass.
I would expect those of the aggregated IVehicle as well
Otherwise one can't know that IVehicle is aggregated and supported by ICar and therefore can be accessed through ICar.
The object browser only shows two separate Interfaces and its properties ICar and IVehicle.
So where can one see in VB, that ICar also supports the Interface IVehicle?
|
|
|
|
|
Hi,
I'm using ATL and have written an event that passes a SAFEARRAY (of
doubles) back to the client as one of its parameters
In the IDL file I've declared this as:
[id(2), helpstring("method SpoilValuesReadyEvent")] HRESULT
TFASpoilsReadyEvent(SAFEARRAY(double)* a, double b, double c);
producing:
HRESULT Fire_TFASpoilsReadyEvent(SAFEARRAY * * a, DOUBLE b, DOUBLE c) etc...
in the proxy file.
I'm testing the code from a VB client. The client produces:
Private Sub test_TFASpoilsReadyEvent(a() As Double, ByVal b As Double, ByVal
c As Double)
This all seems to be OK. However, when I fire the event, it is not caught
by the client. Is there any reason for this apart from probable
incompetence ?
|
|
|
|
|
Why don't you catch the error and get a error description of the failure, this way we might be able to help you ?
|
|
|
|
|
Hi, there is no error generated as such. The problems I'm having centre around:
1. The IDL complaining that an interface doesn't support automation.
2. The interface being seeminly ok until I try to use it in a client. The client (i'm testing in VB) will try to implement the event handler and either not catch it or crash at the first line of code in the handler.
Judging by other stuff i've seen on the net there seems to be a problem with passing SAFEARRAYS and VARIANTS through event interfaces.
|
|
|
|
|
download this sample from chris sells site
http://www.sellsbrothers.com/tools/CComSafeArray.zip
This has a excellent sample that uses Safearray between C++ and VB
But...
Looking at your code, everthing seems to be OK. It may be that you have some basic COM security problems. i.e. your server machine does not have the rights to fire data at your client machine.
|
|
|
|
|
Hi.
I read that there is a way to display addition attributes in Active directory on the context menu of Microsoft Window Shell and Active Directory administrative adds-in. Does anyone has a sample code for this or know where it is available?
Thank you.
|
|
|
|
|
Hi.
I read that there is a way to display addition attributes in Active directory on the context menu of Microsoft Window Shell and Active Directory administrative adds-in. Does anyone has a sample code for this or know where it is available?
Thank you.
|
|
|
|
|
In our shop we utilize an application generator "Cool Plex". It builds C++ code and compiles it into dlls. One of its abilities is to include ActiveX controls on a screen. We have written an ActiveX control that dynamically creates a form using Combo box, ListBox and Ms MaskEdBox control. A typical usage might include 2 or 3 instances of each.
The Problem:
Inside our ActiveX we capture the Tab key in each control (control_OnKeyUp) and set focus to the next control, except for the MaskedEdit controls. We get other keys in the KeyUp event, but not the Tab key!!??
If I create a VB app and embed the control in it, the tabbing works as normal, So far, even worse. Now it appears the PLEX generated application is inhibiting the Tab key from getting to the MaskedEdit control which is encapsulated in our ActiveX control. Other encapsulated controls seem to work fine.
It seems to me that these symptoms are mutually exclusive. I don't see how this is possible, but the developer on this project has convinced me that this is what is happening.
1. PLEX container passes (or never gets) Tab key presses to the ActiveX control.
2. PLEX container inhibits the Tab key when the focus inside the ActiveX control is in a MaskedEdit control.
3. I believe the encapsulated control with the focus, gets the events before PLEX, precluding inhibiting the tab key at all.
4. PLEX container has no way to differentiate the encapsulated control with the focus from any other.
5. PLEX container has no way to differentiate the type of control. How could it know that the focus in our Activex control is on a MaskEdBox?
Thanks for the help,
Bill
|
|
|
|
|