> I have a control, call it MyControl.ocx. It therefore has a type
> library, MyControl.tlb.

Let's assume that your control provides a dual interface (a custom interface
derived from IDispatch) and that interface is called IMyControl.

> I can use VC 6's ClassWizard to create wrapper classes for that type
> library, which is great - but since this control of mine is still in
> development (I'm experimenting, and testing the control as I go), the
> contents often change and thus I would need to keep recreating it -
> deleting the old files first, probably.

This method uses the IDispatch part of the interface, which is less
efficient than direct virtual function calls you can use on a dual
interface.

> If I use this method, I can declare and use objects of type
> _DMyControl with no problems.
>
> So I was trying to use something new (to me): #import. The import
> itself, and the creation of the .tlh and .tli files, went OK; but I'm
> struggling to be able to declare and use the object wrapping the type
> library. Looking in the .tlh, it declares structs. One is _DMyControl,
> derived from IDispatch, which sounds familiar; the other is plain
> MyControl.

First of all, beware of the namespace problem.  Unless you use #import with
no_namespace, it declares and defines everything inside namespace
TYPELIBRARY_NAME.

Now, the _DMyControl interface should logically not used unless your
control's interface is not dual (which is should be, by all means).
Usually, in the #import world, the _DXXX interfaces are used for handling
events using connection points.

The MyControl class forward declaration is only there to enable __uuidof().
It should look like this:

 class __declspec(uuid("...")) MyControl;

Which enables you to write __uuidof(MyControl) instead of CLSID_MyControl.
This is useful in template coding, but I personally prefer #import with
named_guids which creates the CLSID_MyControl variant as well.

> If I try to declare and use a MyControl object, the compiler complains
> of "... uses undefined type MyControl" (it is a forward reference
> only, no body).

Yup, like I said, MyControl is *only* intended to be used with __uuidof().

> If I try to declare and use a _DMyControl object, it complains of "...
> cannot instantiate abstract class _DMyControl because of..."
> and then it lists functions such as QueryInterface(), AddRef(), etc.

_DMyControl should be like this (correct me if I'm wrong):

 struct _DMyControl : IDispatch {};

It's not very useful, I guess.

> So based on the name MyControl.tlb, what class should I be declaring
> my objects as? The ClassWizard method gives me something derived from
> COleDispatchDriver, which allows me to use AttachDispatch() to connect
> an IDispatch to (some members may remember a question from a while
> back about one control using another).
>
> If I could just figure out how to use #import's results properly I
> think I'd be onto a winner.

COleDispatchDriver is a manipulator for IDispatch-based interfaces.  The
class ClassWizard creates has member functions with the same name as the
methods of the control, and internally, they all use IDispatch::Invoke( )
with a magic number DISPID and all the gory stuff - something you wouldn't
want to do with hand.

Now, what will help you is the #import-generated classes around the non-dual
part of your interface.  First, there will be a raw IMyControl interface
definition, and also, a wrapper named IMyControlPtr.  The last one is a
smart pointer based on _com_ptr_t, and is the one you should usually use.
Now, all the original virtual member functions named xxx can be access via
the raw_xxx methods of these wrappers, and also, they can be used with a
simplified VB-like syntax using the same 'xxx' name.

 // example:
 IMyControlPtr ptr;
 // somehow point it to your control (see below)  // access the Name
property  _bstr_t theName = ptr->Name;  // set it  ptr->Name = "my name";
// access the Foo method (taking a BSTR and an int param, and returning a
float):
 float result = ptr->Foo( "string", 0 );

All HRESULT error codes will be converted to _com_error exceptions, so you
should wrap these calls in a try/catch block.

Now, how you're supposed to point an IMyControlPtr to your control?  Just
act like before: obtain an IDispatch pointer to your control in whatever way
you used to, and QueryInterface( ) it for IMyControl, and then, pass in in
the IMyControlPtr's ctor, or as a param to IMyControlPtr::Attach( ) method.
See, it's just as simple as what you were doing by the ClassWizard-generated
class.

Hope this helps,
-------------
Ehsan Akhgari

List Owner: [EMAIL PROTECTED]

[ Email: [EMAIL PROTECTED] ]
[ WWW: http://www.beginthread.com/Ehsan ]

Light without eyes illuminates nothing.





Reply via email to