From: Hector Santos on
I never did this before under MFC C/C++. I added COM components to
the Toolbar

right click the ToolBox | Choose Items

and selected some Microsoft components, specifically the Microsoft
TabStrip component. It was added to the palette and now I can drop
the control into the dialog form. Then I right click the control and
"Add Variable" to create a m_tabs class member. When you do this, the
TLB information is used to a class wrapper for the dispatch commands.
In this case, it created, TabStrip2.h and TabStrips2.cpp.

What I want to get access to is the SelectedItem, which it has these
get/put functions to be used in property members:

LPDISPATCH get_SelectedItem()
{
LPDISPATCH result;
InvokeHelper(0xf, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&result,
NULL);
return result;
}
void putref_SelectedItem(LPDISPATCH newValue)
{
static BYTE parms[] = VTS_DISPATCH ;
InvokeHelper(0xf, DISPATCH_PROPERTYPUTREF, VT_EMPTY, NULL, parms,
newValue);
}
void put_SelectedItem(VARIANT * newValue)
{
static BYTE parms[] = VTS_PVARIANT ;
InvokeHelper(0xf, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,
newValue);
}

The question is how do use these in properties with LPDISPATCH?

For example, it is easier for a BOOL types such as get_ShowTips and
put_ShowTips:

BOOL get_ShowTips()
{
BOOL result;
InvokeHelper(0x3, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);
return result;
}
void put_ShowTips(BOOL newValue)
{
static BYTE parms[] = VTS_BOOL ;
InvokeHelper(0x3, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,
newValue);
}

By adding the following property to the TabStrip2.h class:

_declspec(property(get=get_ShowTips,put=put_ShowTips)) BOOL ShowTips;

I now can access this member in m_tabs:

m_tabs.ShowTips = FALSE;

What class or object is get_SelectedItem returning? I looked overall
google on this and there is no MFC C/C++ example with this.

I'm just explore it really, not sure if I will use it or not.

Thanks


--
HLS
From: Goran on
On Mar 26, 12:51 am, Hector Santos <sant9...(a)nospam.gmail.com> wrote:
> I never did this before under MFC C/C++.  I added COM components to
> the Toolbar
>
>          right click the ToolBox | Choose Items
>
> and selected some Microsoft components, specifically the Microsoft
> TabStrip component.  It was added to the palette and now I can drop
> the control into the dialog form.   Then I right click the control and
> "Add Variable" to create a m_tabs class member.  When you do this, the
> TLB information is used to a class wrapper for the dispatch commands.
>   In this case, it created, TabStrip2.h and TabStrips2.cpp.
>
> What I want to get access to is the SelectedItem, which it has these
> get/put functions to be used in property members:
>
>         LPDISPATCH get_SelectedItem()
>         {
>                 LPDISPATCH result;
>                 InvokeHelper(0xf, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&result,
> NULL);
>                 return result;
>         }
>         void putref_SelectedItem(LPDISPATCH newValue)
>         {
>                 static BYTE parms[] = VTS_DISPATCH ;
>                 InvokeHelper(0xf, DISPATCH_PROPERTYPUTREF, VT_EMPTY, NULL, parms,
> newValue);
>         }
>         void put_SelectedItem(VARIANT * newValue)
>         {
>                 static BYTE parms[] = VTS_PVARIANT ;
>                 InvokeHelper(0xf, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,
> newValue);
>         }
>
> The question is how do use these in properties with LPDISPATCH?
>
> For example, it is easier for a BOOL types such as get_ShowTips and
> put_ShowTips:
>
>         BOOL get_ShowTips()
>         {
>                 BOOL result;
>                 InvokeHelper(0x3, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);
>                 return result;
>         }
>         void put_ShowTips(BOOL newValue)
>         {
>                 static BYTE parms[] = VTS_BOOL ;
>                 InvokeHelper(0x3, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,
> newValue);
>         }
>
> By adding the following property to the TabStrip2.h class:
>
>   _declspec(property(get=get_ShowTips,put=put_ShowTips)) BOOL ShowTips;
>
> I now can access this member in m_tabs:
>
>      m_tabs.ShowTips = FALSE;
>
> What class or object is get_SelectedItem returning?  I looked overall
> google on this and there is no MFC C/C++ example with this.

OleView says that SelectedItem is returning an ITab*. (There's two MS
tab strips on my system, I picked one in mscomctl.ocx).

Overall, for better results, try to open the type library in OleView
(you can find this in your Win32 SDK, in Bin\OleView.Exe, but I would
guess it lurks somewhere else in VS installation, too).

BTW, from the type library, you should be able to find out where is
the help file for it's component(s) (if there is a help file). For
mscomctl.ocx on my machine, it's "cmctl198.chm".



In all honesty, I always preferred stuff provided by compiler COM
support ("#import") to what MFC wizards spit out. I'd recommend using
this, if you are ready to take the plunge into COM world (it really IS
a different world). You can e.g. use VS help to, say, drop control
onto a dialog, then just use stuff #import gives you (take LPDISPATCH
from the control, turn it into corresponding smart pointer from *.tlh
generated through #import and work with that).

Beware, by default, #import-generated stuff uses throws _com_error to
report errors, which is bad in context of MFC. So you need to either:

* try-catch-demarcate all calls to #import-generated stuff
* use _set_com_error_handler to turn COM errors into MFC exceptions
(IMO best approach by a long stretch, but curiously, this function was
never documented by MS, although it exists since, I dunno, forever)
* use "raw" interfaces only (I personally would never bother with that
PITA)

HTH,

Goran.
From: Liviu on
"Goran" <goran.pusic(a)gmail.com> wrote...
>
> In all honesty, I always preferred stuff provided by compiler COM
> support ("#import") to what MFC wizards spit out. I'd recommend using
> this, if you are ready to take the plunge into COM world (it really IS
> a different world). You can e.g. use VS help to, say, drop control
> onto a dialog, then just use stuff #import gives you (take LPDISPATCH
> from the control, turn it into corresponding smart pointer from *.tlh
> generated through #import and work with that).

I share the same preference. One general advice, though, especially on
"first dates" with #import, would be to debug a small snippet and step
all the way into the wrappers to get a feeling for what they do for (and
hide from) you - automatic type conversions, QIs etc.

> Beware, by default, #import-generated stuff uses throws _com_error to
> report errors, which is bad in context of MFC. So you need to either:
>
> * try-catch-demarcate all calls to #import-generated stuff
> * use _set_com_error_handler to turn COM errors into MFC exceptions
> (IMO best approach by a long stretch, but curiously, this function was
> never documented by MS, although it exists since, I dunno, forever)

I remember it wasn't, other maybe than "the source code is its best
documentation" ;-) but now that you mentioned it, I find that it's been
published <http://msdn.microsoft.com/en-us/library/ff357023.aspx>.

One other caveat about #import, for those who care about controlled and
repeatable builds... If one just writes "#import <mscomctl.ocx>" the
compiler will happily oblige, locate the .ocx in the %path% (such as
%systemroot%\system32), and use whatever it found. But if a colleague
rebuilds the same sources, he may well have a different .ocx on his
machine. Same if one applies some system updates, changes machines or
OSs, and rebuilds later. While in theory COM interfaces are immutable
and this shouldn't matter much, yet in practice it adds an element of
hazard to the build process. (Then, there is also the case where one
develops against COM interfaces not present on the build machine
e.g. ms-office automation without the target office version installed.)

This problem can be circumvented in a few different ways:

- #import once to generate the .tlh/.tli files, then archive those and
change #import to just #include the .tlh; drawback is that this would
need to be done again when the compiler changes since different versions
may #import differently;

- copy the binary file (in this case .ocx) to a known location and
arrange the build paths so that it's always picked up from there;
drawback is that the entire binary file becomes part of the "source
package" while in fact just its type library is needed (in this case
it'd be a 1MB .ocx for what's essentially a 140KB .tlb);

- extract the .tlb from the binary file and #import that, instead; use
your favorite resource editor to locate and save the first "typelib"
resource; to doublecheck, open the original PE file and the saved
..tlb in OleView and save the .idl's - they should compare identical.

To be clear, the above only applies to cases where (a) there is no
separate .tlb available already, and (b) one prefers not to #import
directly from the PE file because of versioning/logistics reasons.

Liviu


From: Hector Santos on


Goran wrote:

>> By adding the following property to the TabStrip2.h class:
>>
>> _declspec(property(get=get_ShowTips,put=put_ShowTips)) BOOL ShowTips;
>>
>> I now can access this member in m_tabs:
>>
>> m_tabs.ShowTips = FALSE;
>>
>> What class or object is get_SelectedItem returning? I looked overall
>> google on this and there is no MFC C/C++ example with this.
>
> OleView says that SelectedItem is returning an ITab*. (There's two MS
> tab strips on my system, I picked one in mscomctl.ocx).


Geez, I totally forgot about OleView. I was focusing it was a wrapper
around the TCITEM class members.

> In all honesty, I always preferred stuff provided by compiler COM
> support ("#import") to what MFC wizards spit out. I'd recommend using
> this, if you are ready to take the plunge into COM world (it really IS
> a different world).


Tell me about it. We are 100% RPC. COM/ACTIVEX for the few VB6 and
some Delphi based client side product utilities, but the rest all
C/C++ MFC by design to stay away from historical COM/ACTIVEX
installation deployment and security issues.

But most of the COM/DCOM/COM+ experience came for the SDK to expose
the SDK to COM ready languages. But I put that aside 2 years ago to
use .NET instead to kill two birds with one. It was a nightmare
trying to figure out how to best take our RPC IDL files and move it
COM. So we started fresh with .NET by using one of CPP2xxxxxxx
Language converters and with the help of a 3rd party developer we have
a complete .NET interop interface.

http://www.winserver.com/public/wcsdk

I used .NET to create drop controls to add to to toolbox and had fun
learning how create the property editor, especially for the events. :)

For our 14 year old product "Makeover Stategy", what I am trying to do
now is explore "making fancy" some of the MFC applets using some COM
controls. Many of the apps are simple enough to port to .NET, most
likely VB.NET or C#. But I'm going to wait until VS2010 comes in to
explore what this yet another method, WPF, is all about.

Anyway, ITab is the right interface. I am currently looking to if I
can get a generic dispatch wrapper to handle this and others using
templates. I wonder why "adding the variable" for the component class
only addd TabStrip but not the others Tabs and Tab.

I am refreshing my understanding of COM based IDL, TLB and the auto
produced imported source.

Thanks.

--
HLS
From: Hector Santos on
This is why I didn't work to much with the the auto generated stuff.

The COM work, beside trying to use it now a MFC application, it was
mostly for the SDK considerations. Take a look at the interop
marshalling API files created for .NET for the main RPC client DLLs to
get a feel of what we were facing and trying to automatic:

http://www.winserver.com/public/wcsdk

The .NET DLLs created from these allow me to create COM interfaces as
well.

Since we are RPC, the IDL are "almost" the same but different. Before
..NET, we had a VARIANT proxy dll for some of the API functions, i.e,
returning a BSTR or VB based string collection. That was for VB6 SDK
support.

But the need to do a complete COM for OOPS like languages was
difficult, do with create a UDT for each typedef structure? Do we
create class interfaces, etc.

To make a long story short, .NET helped here. Beside the lack of
VARIANT support, or harder to do now, .NET made it simpler.

Before .NET, we have a CPP2xxxxx language convert that takes our .H
files and create the appropriate API for the language.

VB WIN32 imports plus a proxy for string based or array
functions

DELPHI Win32

Java A streaming I/O proxy class based framework.

PHP A similar streaming I/O proxy for functional programming,
plus PHP class wrappers.

So before .NET, to create a COM interface do we:

1) Write a CPP2COM converter, using the CPP2Java or CPP2PHP model,
2) Use the existing RPC IDL as input for a COM IDL

By the time that tedious work decision was made, coupled that we
falling behind .NET, it was easily just to write it in .NET and
expose a COM interface as well.

That worked so far. :)


Liviu wrote:

> "Goran" <goran.pusic(a)gmail.com> wrote...
>> In all honesty, I always preferred stuff provided by compiler COM
>> support ("#import") to what MFC wizards spit out. I'd recommend using
>> this, if you are ready to take the plunge into COM world (it really IS
>> a different world). You can e.g. use VS help to, say, drop control
>> onto a dialog, then just use stuff #import gives you (take LPDISPATCH
>> from the control, turn it into corresponding smart pointer from *.tlh
>> generated through #import and work with that).
>
> I share the same preference. One general advice, though, especially on
> "first dates" with #import, would be to debug a small snippet and step
> all the way into the wrappers to get a feeling for what they do for (and
> hide from) you - automatic type conversions, QIs etc.

>

>> Beware, by default, #import-generated stuff uses throws _com_error to
>> report errors, which is bad in context of MFC. So you need to either:
>>
>> * try-catch-demarcate all calls to #import-generated stuff
>> * use _set_com_error_handler to turn COM errors into MFC exceptions
>> (IMO best approach by a long stretch, but curiously, this function was
>> never documented by MS, although it exists since, I dunno, forever)
>
> I remember it wasn't, other maybe than "the source code is its best
> documentation" ;-) but now that you mentioned it, I find that it's been
> published <http://msdn.microsoft.com/en-us/library/ff357023.aspx>.
>
> One other caveat about #import, for those who care about controlled and
> repeatable builds... If one just writes "#import <mscomctl.ocx>" the
> compiler will happily oblige, locate the .ocx in the %path% (such as
> %systemroot%\system32), and use whatever it found. But if a colleague
> rebuilds the same sources, he may well have a different .ocx on his
> machine. Same if one applies some system updates, changes machines or
> OSs, and rebuilds later. While in theory COM interfaces are immutable
> and this shouldn't matter much, yet in practice it adds an element of
> hazard to the build process. (Then, there is also the case where one
> develops against COM interfaces not present on the build machine
> e.g. ms-office automation without the target office version installed.)
>
> This problem can be circumvented in a few different ways:
>
> - #import once to generate the .tlh/.tli files, then archive those and
> change #import to just #include the .tlh; drawback is that this would
> need to be done again when the compiler changes since different versions
> may #import differently;
>
> - copy the binary file (in this case .ocx) to a known location and
> arrange the build paths so that it's always picked up from there;
> drawback is that the entire binary file becomes part of the "source
> package" while in fact just its type library is needed (in this case
> it'd be a 1MB .ocx for what's essentially a 140KB .tlb);
>
> - extract the .tlb from the binary file and #import that, instead; use
> your favorite resource editor to locate and save the first "typelib"
> resource; to doublecheck, open the original PE file and the saved
> .tlb in OleView and save the .idl's - they should compare identical.
>
> To be clear, the above only applies to cases where (a) there is no
> separate .tlb available already, and (b) one prefers not to #import
> directly from the PE file because of versioning/logistics reasons.
>
> Liviu
>
>



--
HLS
 | 
Pages: 1
Prev: Releated to JIT Error
Next: Apology to Joe