|
|
Thanks for the reply but that's not really helping me, I understand the theory on using COM (I think) and I have downloaded and played around with the example but I still can't see how I handle an event from an existing object.
Now I have a new project with the correct methods and events, how do I use it in a C project?
|
|
|
|
|
Hi
To process COM events, you first have to implement an interface - this is what you've achieved by running the wizard. You'll have to create an instance of this class somewhere is your app. Secondly you'll have to pass this instance's interface to the COM object you want to listen to - typically this is done through IConnectPointContainer, etc. and associated IConnectionPoint::Advise/Unadvise methods (an observer pattern). Call QueryInterface(__uuidof(IConnectPointContainer), ...) on the object you want to listen to to see if it supports connection points.
If you're hosting an ActiveX control in an MFC application, this is easiest done with MFC's EVENT_MAP mechanism. ATL has a similar setup with SINK_MAP. Both of these MAPs hide the details of making calls to Advise and Unadvise, and the preceding discovery of IConnectPoint interfaces on the observable.
Connection Points is just one standard mechanism of binding the observer to the observable, and may or may not be supported by the object you want to listen to. Another way to achieve the same (and functionally similar) is a straight callback - the object you want to listen to has a method for registering the observer (eg. StartListening(IMyObjectsEvents *pObserver), and StopListening(...)). But since this is a more bespoke interaction, one that is less often supported. Also, since Connection Points is a generic implementation, it incurs an overhead in number of round-trips necessary to establish the 'connections', but I doubt that it's of any concern in your case.
HTH
Martin
|
|
|
|
|
Thanks, I think I have now made some progress, I have now regsitered the object successfully and created the new instance within my C project without any errors, but now I get a "Not Implemented" error when I try to use any of the commands from the original object.
In my C project, I have simply replaced the ID of the original object (CrystalDesignRunTime2.Application.Net) with the ID of the new object, what else do I need to do to make the functions work?
(I have started again on this to simply make the object work before I try implementing any event handling, any help is greatly appreciated on this, it's driving me mad!)
|
|
|
|
|
Hang on there; It's not required to register the event wrapper, and probably isn't going to help at all.
Let's work through this one step at a time.
Forget about the events for now.
How are you hosting this Crystal object in your application - is it an MFC app with the Crystal control dragged onto a dialog?
Martin
|
|
|
|
|
The Crystal object is hosted in a C DLL (It's a plugin for another application), it is created using this code:
m_pApp.CreateInstance("CrystalDesignRunTime2.Application.Net");
(m_pApp being an IApplicationPtr)
I then open the report with this code:
m_pRep = data->m_pApp->OpenReport(reportName, varOpenType);
(m_pRep begin an IReportPtr)
I then use the Export() function from the IReportPtr to export the report as necessary.
That all works fine, how can I create an event wrapper to work as above and capture the event?
(Thanks for your help on this!)
|
|
|
|
|
Hi
The following bit of code demonstrates what is possible with ATL and catching events from the MS Calendar ActiveX control;
<<<<<<<<< START OF CODE >>>>>>>>>>
// main.cpp
#define _WIN32_WINNT 0x0500 // if you want to use ::CoInitializeEx
#include <atlbase.h>
#include <atlcom.h>
#import "C:\Program Files\Microsoft Office\OFFICE11\mscal.ocx" \
rename_namespace("cal") \
raw_interfaces_only
const int CALENDAR_SOURCE_ID = 0;
class CMyCalendarEvents;
typedef IDispEventSimpleImpl<calendar_source_id, cmycalendarevents,="" &__uuidof(cal::dcalendarevents)="">
CalendarEventsImpl;
_ATL_FUNC_INFO OnNewMonthInfo = { CC_STDCALL, VT_EMPTY, 0, 0 };
class CMyCalendarEvents
: public CalendarEventsImpl
{
public:
BEGIN_SINK_MAP(CMyCalendarEvents)
SINK_ENTRY_INFO(CALENDAR_SOURCE_ID, __uuidof(cal::DCalendarEvents), 1, OnNewMonth, &OnNewMonthInfo)
END_SINK_MAP()
void __stdcall OnNewMonth()
{
_RPT0(_CRT_WARN, "## Month Changed!\n");
}
};
void main()
{
if (FAILED(::CoInitialize(0)))
return;
try
{
CMyCalendarEvents ce;
CComPtr<cal::icalendar> ptrCalendar;
HRESULT hr = ptrCalendar.CoCreateInstance(OLESTR("MSCAL.Calendar"));
_com_util::CheckError(hr);
// start listening
hr = ce.DispEventAdvise(ptrCalendar, &__uuidof(cal::DCalendarEvents));
_com_util::CheckError(hr);
hr = ptrCalendar->Today(); // OnNewMonth fires ??
_com_util::CheckError(hr);
hr = ptrCalendar->Today(); // OnNewMonth fires ??
_com_util::CheckError(hr);
// stop listening
hr = ce.DispEventUnadvise(ptrCalendar, &__uuidof(cal::DCalendarEvents));
_com_util::CheckError(hr);
hr = ptrCalendar->Today(); // OnNewMonth fires ??
_com_util::CheckError(hr);
}
catch (...)
{
// do nothing
}
::CoUninitialize();
}
<<<<<<<<< END OF CODE >>>>>>>>>>
In your case, the event sink would look different, for example, the IReportEvent::NoData handler would be (I think);
<<<<<<<<< START OF CODE >>>>>>>>>>
const int REPORT_SOURCE_ID = 0;
class CMyReportEvents;
typedef IDispEventSimpleImpl<report_source_id, cmyreportevents,="" &__uuidof(cr::ireportevent)="">
ReportEventsImpl;
_ATL_FUNC_INFO OnNoDataInfo = { CC_STDCALL, VT_EMPTY, 1, { VT_PTR | VT_BOOL } };
class CMyReportEvents
: public ReportEventsImpl
{
public:
BEGIN_SINK_MAP(CMyReportEvents)
SINK_ENTRY_INFO(REPORT_SOURCE_ID, __uuidof(cr::IReportEvent), 1, OnNoData, &OnNoDataInfo)
END_SINK_MAP()
void __stdcall OnNoData(VARIANT_BOOL *pCancel)
{
_ASSERT(false);
}
};
<<<<<<<<< END OF CODE >>>>>>>>>>
HTH
Martin
|
|
|
|
|
Thanks very much for the code!
I'm a little confused, do I use this code in the C project I have (The DLL I am working on) or in the ATL project? If I use it in the ATL project, how do I use this class in my DLL.
(Sorry if I sound really stupid but I am having a really hard time understanding how I should use COM/ATL objects)
Thanks in advance!
|
|
|
|
|
Chill
It's not really feasible to have 2 DLLs - you can have both, but to my mind it just confuses things too much.
The DLL that uses the COM object (eg. calling OpenReport, etc) should be the same one that provides the events object that implements the IReportEvent interface. The theory is; if you see the following in a type library;
coclass Report {
[default] interface IReport;
interface IDReport;
[default, source] dispinterface IReportEvent;
};
it means that the Report class promises to implement IReport and IDReport, but *not* IReportEvent because that's the one you need to implement and give to the Report instance (you've created) by using the Advise/Unadvise methods mentioned earlier - this is indicated with the 'source' IDL attribute.
So, the code I gave you resembles something to be put in your work DLL and replaces the need for an ATL wrapper DLL that is generated from the type library. You can use the wizard-generated ATL DLL code as a hint to what the SINK_MAP entries should look like ....a handy reference.
As an aside, if you haven't already, use OleView to inspect Crystal's CRAXDDRT20.DLL (or similar) to see what the type library looks like.
Also, get 'ATL Internals' by Brent Rector, Chris Sells - it explains all this stuff much better than I can.
Martin
|
|
|
|
|
I think I'm getting somewhere at last, just two questions I can't seem to figure out, when I try to use DispEventAdvise() function of CMyReportEvents, I get the message that it "must have class/struct/union type" which is obviously because that function does not exist in the class, how do I add the function to the class? Also, I get the message that there is no default constructor available for CMyReportEvents, is there any specific code I need in the constructor or can I use an empty constructor?
Thanks in advance!
|
|
|
|
|
I have worked out where my problem is, I need to declare the ReportEventsImpl properly, I have changed the code to this:
#import "C:\Program Files\Common Files\Crystal Decisions\1.0\Bin\craxddrt20.dll" rename_namespace("cr")
using namespace cr;
const int REPORT_SOURCE_ID = 0;
class CMyReportEvents;
typedef IDispEventSimpleImpl<report_source_id, cmyreportevents,="" &cr::ireportevent=""> ReportEventsImpl;
_ATL_FUNC_INFO OnNoDataInfo = { CC_STDCALL, VT_EMPTY, 1, { VT_PTR | VT_BOOL } };
class CMyReportEvents : public ReportEventsImpl
{
public:
BEGIN_SINK_MAP(CMyReportEvents)
SINK_ENTRY_INFO(REPORT_SOURCE_ID, __uuidof(IReportEvent), 1, OnNoData, &OnNoDataInfo)
END_SINK_MAP()
bool CMyReportEvents()
{
}
void __stdcall OnNoData(VARIANT_BOOL *pCancel)
{
_ASSERT(false);
}
};
I get the error that using "IReportEvent" in the typedef and that "Use of template requires argument list", could you point me in the direction of what I use instead of IReportEvent.
Thanks!
|
|
|
|
|
Hi
It's the declaration of ReportEventsImpl;
typedef IDispEventSimpleImpl ReportEventsImpl;
IDispEventSimpleImpl is a template class, so it requires parameters (source id, class, events IID), like so;
class CMyReportEvents;
typedef IDispEventSimpleImpl<report_source_id, cmyreportevents,
="" &__uuidof(cr::ireportevent)="">
ReportEventsImpl;
(note the forward declaration of CMyReportEvents)
just mail mkoorts@postmaster.co.uk directly and we can take this offline.
Martin
|
|
|
|
|
Any OLE clipboard experts out there? I'm seeing some odd behavior when pasting and embedding an object in Word 2003.
Here's the scenario: in my MFC application, I paste data to the clipboard in a handful of formats - the typical OLE document crew of Embed Source, Object Discriptor, and CF_METAFILEPICT; and a CF_DIB (which seems to have no bearing on the problem). When I paste into Word 2003, an instance of my app is launched, and the embedded data is serialized in. This wouldn't bother me so much if the instance would go away after I close Word. It reeks of a reference counting issue, yes, but I'm wondering why my app is being launched in the first place. The embedded object isn't active, and Word only needs a metafile to render the object's presentation - and the metafile is readily available on the clipboard.
The odd part about this is that no additional app instance is launched when I do the same thing under Word 2000. Any clues as to what's going on here? Is Word '03 looking for a different clipboard format, or otherwise handling clipboard operations differently than Word '00? Of course, my app may be buggy , but there haven't been issues until the '03 suite.
Any help is appreciated.
|
|
|
|
|
I am writing a MFC app that loads and runs external scripts written in VBScript.
To run a script, I instantiate an engine derived from COleDispatchDriver, and then get an interface to VBScript by
hr = CLSIDFromProgID(L"VBScript", &clsid);
This works just fine as long as my scripts contain only native VBScript statements, but I would really like to use the functionality of the WScript object as well, and VBScript apparently doesn't recognize it. I've tried every variation I can think of, like
hr = CLSIDFromProgID(L"WScript", &clsid);
and
hr = m_iActiveScript->AddNamedItem(L"WScript.exe", SCRIPTITEM_ISVISIBLE | SCRIPTITEM_ISSOURCE | SCRIPTITEM_GLOBALMEMBERS);
but nothing seems to work.
Any suggestions?
|
|
|
|
|
Hey,
I was wondering is it possible to modify the way the IDispatch
implements its member/property discovery. eg. modify the way ITypeInfo
works.
I want to be able to populate a collection with property names when
the client uses the object (when it does its discovery).
eg.
Dim objTestATL As GenAdapter.CAttribObj
objTestATL = New...
Now when the client types "objTestATL." they will be given a list of methods/properties
objTestATL.Height = 23
objTestATL.Width = 2
objTestATL.DoSomethingCool()
where height and width are stored in a collection and the method
DoSomethingCool() is defined as normal.
Thoughts and/or Ideas would be great.
Thanks
|
|
|
|
|
Hi
Typically, implementations for IDispatch is driven off a type library (eg. ATL's IDispatchImpl), but since a typelib is static, it won't work for you. Instead you'll have to provide the ITypeInfo implementation yourself. Have a look at CreateDispTypeInfo and see if it'll help you.
HTH
KakVraagSit .... (grappie)
|
|
|
|
|
For that the IDispatchEx was designed. Also the JScript and VBScript asks for that interface if you pass the object into the script engine.
For plain old VB there's a problem, that VB asks only for IDispatch AFAIK. Therefore you have to test, if VB supports the Ex version or go through the pain of manually defining your interface.
Anyway, I think, you have to cast your objects as Object only, because else the VB will store the values it receives during the compilation in the resulting binary - this means, if you changes the number/order of properties you're out of luck.
Don't worry to ask for more
|
|
|
|
|
hai all,
i created an arrow in MFC(exe) i want to export that arrow functioning into an ActiveX component. and i created that control. and i add my ctrl to toolbar, i getting the rectangular dotted lines and in that i arrow is placing but i don't want like that , i want to look like a "line which is provided by Windows".
In the program , i use, OnDraw ( , CRect rcBounds , ,) function , i take the rcBounds and i took two points (starting, ending) to draw the arrow. But , i want only a single point which is mousedown(which is at design time)..
not runtime.
plz Help.
Thanks in advance.
surya prakash
|
|
|
|
|
Hi,
I have an Activex DLL in VB6. I am creating threads within that using CreateThread API. When I try to access it from another application(std exe), it is giving run-time error. The same code works if it is made into a standard exe. Can anyone suggest the solution?
thx in adv.
--sandeep
|
|
|
|
|
I'm working on a plugin system, however I do not want end users to be able to discover what interfaces/coclasses I have implimented in the plugin DLLs.
If I remove the type library from the DLL's resources, will the plugged-into app still function correctly as long as it knows the definitions of the plugins' interfaces at compile-time?
If the plugin DLL does NOT contain a type library in itself, will the app and plugin still function properly?
|
|
|
|
|
The type library in the resources is just included for convenience so that other programmers can view the COM interfaces etc. but does not directly affect the actual interfaces implemented. If you remove this information from the DLLs resource (comment out the lines in the .rc file), the actual interfaces will still function normally.
|
|
|
|
|
Thanks
|
|
|
|
|
I know this very stupid Question ,just want to know which line to comment out in RC File .
Thanks
"I Think this Will Help"
Alok Gupta visit me at http://www.thisisalok.tk
|
|
|
|
|
Near the bottom of the .rc file, you will see a line like this:
1 TYPELIB "myproject.tlb"
If you comment out this line, then the type libary will not be included (assuming that APSTUDIO_INVOKED has not been defined).
If APSTUDIO_INVOKED has been defined, then you will need to comment out the TEXTINCLUDE section higher up in the .rc file which contain a similar TYPELIB line.
|
|
|
|
|
|