COMate - control COM objects via automation - OBSOLETE!

Developed or developing a new product in PureBasic? Tell the world about it.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

COMate - control COM objects via automation - OBSOLETE!

Post by srod »

Announcement - 24th Apr. 2009.

COMate is now obsolete and unsupported!

That's right folks; I will no longer be supporting or updating COMate. I shall ask for this thread to be locked.

The good news, however, is that I shall be supporting COMatePLUS which has just been released and for which a forum announcement is imminent!

:)

=========================================


Update - 19th Feb. 2009.

COMate version 1.3.0.

First, only the version of COMate for PB 4.3 has had this update. COMate for PB 4.2 remains at version 1.1.7

This update massively revamps the way that COMate exposes events from ActiveX controls. So much so that all existing code using COMate to work with ActiveX controls will be broken if dealing with events etc. Only minor modifications will be required though to get your code working with this new version (details below).

Basically, there are two major changes/alterations here :
  1. Event handlers can now be attached to individual 'named' events. For example, you can attach a 'Click' handler to a control (assuming it exposes such an event!) and this handler will be called only when this particular event is raised. Contrast this with the old way of having a single 'global' handler for all events!

    The 'global' handler is still supported, however, as it can be very useful if investigating the full range of events supported by an individual object. Indeed, in cases where a global handler has been declared in addition to an individual handler, then when the underlying event is raised by the ActiveX control, the global handler will be called first, before the individual one.
  2. Many ActiveX controls make available a means for individual event handlers to return a value back to the ActiveX control. The most common method is for the ActiveX control to simply pass a parameter (or two!) 'by reference', thus allowing the client to modify the parameters etc. COMate has been able to handle this since version 1.2.1.

    A second (less common) mechanism employed by some controls is for the event handler to explicitly return a value direct to the ActiveX control itself. COMate now supports this method as well and allows individual event handlers to explicitly return an integer or a real or a string value as appropriate (there are no tricks here, you simply declare your handler as being of a certain type etc.) For return values not covered by this list, you can opt to return a variant type which thus covers all eventualities.

    I have to say though that this is untested at present whilst I endeavour to locate an ActiveX control which offers this! However, this was a simple addition to COMate and so I see no reason why it should fail to work! :)
There is quite a lot more to say about this (e.g. COMate only allows COM objects with a visual interface (such as an ActiveX control) to utilise individual named event handlers. Other objects are restricted to 'global' handlers as before) and so I have to point users towards the fully updated user manual (event handling methods section).

For those wishing to quickly get their code working with version 1.3.0 of COMate, all you need to do is switch your current event handler for a 'global' one. E.g. in the "MSComctlLib_TreeCtrl_WithEvents.pb" demo, you would switch the line :

Code: Select all

treeViewObject\SetEventHandler(@EventProc())
for :

Code: Select all

treeViewObject\SetEventHandler(#COMate_CatchAllEvents, @EventProc())
See the "FlexCellDemo.pb" demo for an example of declaring an individual named event handler (with ByRef parameters).

When I encounter an ActiveX control whose events explicitly return values then I can perhaps knock up a demo of such a handler in action; in the meantime all is detailed within the manual! :wink:


You can access the download through the nxSoftware site.

=========================================


Update - 14th Feb. 2009.

COMate version 1.2.1.

First, only the version of COMate for PB 4.3 has had this update. COMate for PB 4.2 remains at version 1.1.7

Following on from the recent 1.2.0 update, I discovered (with the aid of Kinglestat) the fact that our ActiveX event handlers were not re-entrant. Basically, if an event fired and your event handler invoked a method or property which caused another event to fire then all the parameters sent to your original handler would be invalidated!!!

This has now been fixed and event handlers are now fully re-entrant.

You can access the download through the nxSoftware site.

=========================================


Update - 13th Feb. 2009.

COMate version 1.2.0.

First, only the version of COMate for PB 4.3 has had this update. COMate for PB 4.2 remains at version 1.1.7

I finally encountered an ActiveX control (a grid control as it turns out) which fires some events in which some of the underlying parameters are sent 'by reference'. These parameters of course are intended to be altered (as appropriate) by the client application as an additional means of controlling the control. Indeed, I would guess that many ActiveX controls use such parameters instead of expecting return values from event handlers.

Anyhow, long story short; whilst COMate could retrieve such parameters sent by reference, it did not allow client applications to modify them and thus COMate driven apps could not make full use of these event handlers.

This 'hole' has now been plugged with the addition of a single method to the COMate_Object class; namely IsParameterPassedByReference().

This method not only allows you to determine if a parameter has been sent by reference, but it also allows you to determine the exact nature of the parameter (it's underlying variant #VT_... type) and to also obtain the appropriate address of the parameter so that you can alter it etc. A more advanced option allows you to get a pointer to it's underlying 'dispatch parameter' in it's native variant form (as sent by the ActiveX control to COMate), just in case it is of a type which COMate does not natively cater for (SafeArrays etc.)

If this all seems complicated then take my word for it that it is actually quite easy to use. I have a nice demo of the aforementioned grid control which shows just how easy. You will need to download the demo version of the ActiveX grid control (FlexCell - details in the COMate download).

The help manual has been updated and it is worth a look at the entry for this new method because it really is for 'advanced users' only.

You can access the download through the nxSoftware site.

=========================================


Bug fix - 29th Dec. 2008.

COMate version 1.1.9.

First, only the version of COMate for PB 4.3 has had this bug fix. COMate for PB 4.2 remains at version 1.1.7

A quite major shortcoming on COMate's part meant that it would effectively ignore some ActiveX control's events (e.g. ShockwaveFlash). I blame this on a severe lack of documentation on MS's part! :wink:

This has been fixed.

See the nxSoftware site for the download.

=========================================


Version compatible with PB 4.3 (release version) has been uploaded.
This version will not run on the beta versions of PB 4.3.

See the nxSoftware site for the download.

=========================================


Update and bug fix - 8th Dec. 2008.

COMate version 1.1.8.

First, only the version of COMate for PB 4.3 has had this update and bug fix. COMate for PB 4.2 remains at version 1.1.7

A dirty steaming couple of bugs would see COMate, in certain circumstances, enumerating through a chain of property-gets and even though the COMponents in question would signal success, a null object was nevertheless being returned! I just assumed that a successful return would always result in a valid object - doh! This would of course result in COMate subsequently attempting to execute a method or property against a null object - CRASH BANG WALLOP !!! :)

This has been fixed.

Have upgraded the error reporting to give detailed information in the case of a chain of property-gets being ruined by a null-object return.

See the nxSoftware site for the download.

=========================================


'Bug' fixed. 26th Nov. 2008.
An inconsistency between Windows 2000 (and presumably earlier versions of Windows) and XP etc. led to problems with the GetIntegerProperty() method on these earlier versions of Windows. This has been fixed. (The problem was with VariantChangeType_()).

See the nxSoftware site for the download.

=========================================


ADO demo added. 8th Nov. 2008.
I have translated (and added to the COMate package) Kiffi's PureDispHelper example for creating and adding/retrieving records from/to an OLE DB source using ADO. Also included is Kiffi's 'ado constants' file which will be required.

This is the first time I have used ADO with PB and I have to say it is nice. I likes it! :wink:

I am going to create a simple wrapper around ADO to allow for easy access to the basic commands etc. Shouldn't take too long. The wrapper will of course use COMate.

See the nxSoftware site for the download.

=========================================


Update - version 1.1.7. 9th Oct. 2008.
Version 1.1.7 adds a new method to the COMateObject class, namely : SetDesignTimeMode().

Basically, some ActiveX controls expose some properties which can only be set in a design-time environment (such as the VB IDE etc.) and are otherwise 'read-only' at execution time. A good example is the MS RichTextBox control which exposes 'Multiline' and 'Scrollbars' properties which can only be set at design time. At run-time we are forced to use either default values or those set at design time - which isn't a lot of use if not using VB etc!!!

I have thus added a new method : SetDesignTimeMode() to the COMateObject class which can be used in an attempt to fool the underlying ActiveX control into thinking it is being used in a design time environment - thus allowing us access to the read-only properties etc. I have tested with the aforementioned RichTextBox control and it worked fine.

The help manual has been updated.

See the nxSoftware site for the download.

=========================================


Update - version 1.1.6. 19th Sept. 2008.
Version 1.1.6 adds a new parameter type-modifier; "as COMateObject" for those COM methods / properties requiring you to pass an existing object as a parameter. Of course COMate does not pass the object as it is but instead 'reaches inside the COMate object' and retrieves the underlying COM interface which it sends off to the method instead.

To summarise the type-mofidiers dealing with passing objects (advanced users only) :
  1. "AS Object" or "AS iDispatch"
    Use when passing an iDispatch interface pointer obtained from some means or other - perhaps using CoCreateInstance_() etc.
  2. "AS iUnknown"
    Use when passing an iUnknown interface pointer obtained from some means or other - perhaps using CoCreateInstance_() etc.
  3. "AS COMateObject"
    Use when wishing to pass the iDispatch interface pointer at the heart of the COMateObject in question. COMate itself will retrieve the interface pointer. It is not possible to pass COMateObjects by reference (using BYREF) as a COM method will not understand the nature of such an object. Instead ask myself or Kiffi for a workaround if you need this.
My thanks to Kiffi.

See the nxSoftware site for the download.

=========================================


16th Sept. 2008.
Added a version of COMate suitable for PB 4.3 (32-bit only).

See the nxSoftware site for the download.

=========================================


Update - version 1.1.5. 11th Sept. 2008.
Version 1.1.5 fixes a bug related to the changes in version 1.1.4. Doh!!! Basically if using a CLSID in string form, COMate would sometimes fail in it's check to see if this represented a registered component or not! Double-doh!!!

See the nxSoftware site for the download.

=========================================


Update - version 1.1.4. 10th Sept. 2008.
Version 1.1.4 fixes a bug with the COMate_CreateObject() function which would not set the appropriate error fields under certain circumstances.

Problems interfacing with Microsoft's "TypeInfoLib" library also necessitated the following change:
  • ProgID's can now contain CLSIDs (class identifiers) in string form. These must be placed in braces; e.g. {8B217746-717D-11CE-AB5B-D41203C10000}. These are for those objects not exposing a 'friendly name' (of which the damn TypeInfoLib appears to be one such!)
See the nxSoftware site for the download.

=========================================


Update - version 1.1.3. 9th Sept. 2008.
Bug fixed with the COMate_WrapCOMObject() function.

See the nxSoftware site for the download.

=========================================


Update - version 1.1.2. 8th Sept. 2008.
Version 1.1.2 adds the ability to receive events raised by COM objects (particularly ActiveX controls). My thanks to freak for his permission to use and adapt his 'EventSink' code for use in COMate. :)

New features :
  • Added a new function COMate_WrapCOMObject(). This takes any COM interface obtained by any means and attempts to wrap the underlying object up within a COMate object so that you can easily call any dispinterface functions etc. Designed for use with event handling procedures in particular.
  • A new method (SetEventHandler()) added to the COMateObject class allowing the user to attach an event-procedure to the object which is called by the underlying COM object whenever it raises an event.
  • Four additional methods added to the COMateObject class for use only within an event-procedure for retrieving parameters passed by the underlying COM object as part of the event notification etc.
  • Added a couple more demo programs; one showing how to use the event-handling procedures etc. (A translation of a PureDispHelper demo.)
The help manual has been adjusted accordingly.

See the nxSoftware site for the download.

=========================================


Update - version 1.1.1. 7th Sept. 2008.
Apart from fixing the whole BYREF business which was completely flawed and ill thought out, I have plugged a major hole in COMate's supported parameter types, namely variants! Doh! Needless to say you can now pass variants by value or by reference (See Num3's Open Office example which is posted in this thread!)

There are a couple of things to beware of with COMate parameters (and in particular when using BYREF) which I leave to the help manual (see the page on 'COMate command strings' for details).

Finally, for those enaged with (or to :wink: ) WMI, there is a very very useful scripting utility which I came across which I have thrown into the COMate package and which should make things a lot easier!

See the nxSoftware site for the download.

Right, I'm off to study 'Event sinks' now... Let's hope I have more luck than I generally do with kitchen sinks! :wink:

=========================================


Update - version 1.1.0. 6th Sept. 2008.
My thanks to all those who have tested out the first version of COMate and to SFSxOI in particular for creating some nice WMI demos.

Changes for this new version include :
  • Addition of a 'BYREF' parameter type-modifier. This is for calling methods (VB) in which certain parameters have been declared with the 'ByRef' modifier. For many COM objects it is not enough to simply pass the address of a variable, you will also need to use this new modifier. Particularly true for components created in VB.
  • COMate can now house ActiveX controls. See the demo programs and the help manual for details. I haven't added 'Event sinks' yet for trapping events/messages sent by such controls, but it is only a matter of time! :wink: Consider this part to be in 'beta' stage because I took a slightly different approach here than PureDispHelper and so it remains to be seen whether more than just a handful of ActiveX controls will function correctly?
  • Have totally rewritten the command parser and various utility functions in order to increase the speed. DispHelper does not utilise such a parser and so will of course generally run faster. Increasing the speed has been accomplished by simply removing all PB string functions from the aforementioned functions and replacing with memory buffers and 'in place' alteration (via pointers) of strings. Tests on my machine of these functions (when stripped from COMate) show a x50 increase in speed. Take this with a pinch of salt though! It remains to be seen what effect (if any) these new routines will have, speed-wise, on COMate itself. :)
    This new version is now to be known as COMate-Turbo! :wink:
  • Have included a slightly modified version of mk-soft's / ts-soft's excellent 'VariantHelper' utility within the COMate-Turbo download, because there was a slight bug with the 'SafeArray' macros. Some COM methods/properties will return a SafeArray (yuk!) See the 'Demo_IPAddresses.pb' demo for an example of dealing with a return from a COM method in the form of a SafeArray.
    NOTE that the VariantHelper utility can only deal with SafeArray's of one dimension. Beyond this you are on your own! :wink:
See the nxSoftware site for the download.

=========================================


Hi,

in association with ts-soft enterprises :wink: I bring you COMate, a PB utility for controlling COM automation servers (components).

Realising that a couple of projects I am working on will soon require to use some COM I decided to study OLE automation in depth, and the best way I found of doing this was to grab the open-source DispHelper library (written in c) and convert it to Purebasic. :) I have of course modified the library to suit my own ends!

The main thing is that whilst the original DispHelper library uses a c-style Printf() syntax, my offering (COMate) uses what is, for me at least, a much more comfortable Visual Basic like syntax.

Contrast :

VB code :

Code: Select all

Dim excel As Object
Set excel = CreateObject("Excel.Application")
excel.Visible = blnTrue
converted to Purebasic with the PureDispHelper library :

Code: Select all

Define.l ExcelApp
ExcelApp = dhCreateObject("Excel.Application")
dhPutValue(ExcelApp, ".Visible = %b", #True)
and now converted to Purebasic with COMate :

Code: Select all

ExcelObject.COMateObject
ExcelObject = COMate_CreateObject("Excel.Application")
ExcelObject\SetProperty("Visible = #True")

Features of COMate :
  • Completely free!
  • It comes in the form of a PB source code include file.
  • Ansi or Unicode and/or Threadsafe etc. (Well, as threadsafe as any COM components you may be controlling!)
  • An oop interface.
  • Method / property parameters are encoded in a very natural (VB) way within command strings.
  • Method/property calls can embed a chain of property-gets, each of which return a subobject etc. (all handled automatically by COMate).
  • Command strings can include escape characters in the form $xxxx where xxxx represents a 4 hexadecimal digit character code.
  • Easy enumeration of collections.
  • Automatic freeing of all strings (unlike DispHelper).
  • Full threaded error reporting. Each thread can report (if requested) the most recent COM error as well as a 'friendly' text description if appropriate. This means that if two threads are, for example, working on the same instance of a COM component, then the errors reported in one thread will not affect the other thread!
I think you'd get a good feel for COMate (as well as the differences between this and DispHelper) by browsing the various demo programs which are mostly simple conversions of the PureDispHelper demo programs written by ts-soft, mk-soft and Kiffi; to whom I offer my thanks.

COMate itself uses some code developed by ts-soft and he has been instrumental in helping me test COMate and indeed he translated some of the demo programs for use with COMate. ts-soft is thus very much a part of this project. Indeed, I would like to state right now that he is to be held responsible for any bugs! :)

The COMate package includes the two source include files (one just has constants etc.) various demos and a very comprehensive CHM user manual. This manual is really the first place for those who have never used COM before. :)

You can access the download through the nxSoftware site.

Regards.
Last edited by srod on Fri Apr 24, 2009 2:16 pm, edited 31 times in total.
I may look like a mule, but I'm not a complete ass.
User avatar
Fluid Byte
Addict
Addict
Posts: 2336
Joined: Fri Jul 21, 2006 4:41 am
Location: Berlin, Germany

Post by Fluid Byte »

Didn't test it yet but the name is golden! :lol:
Windows 10 Pro, 64-Bit / Whose Hoff is it anyway?
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Fluid Byte wrote:Didn't test it yet but the name is golden! :lol:
:lol:

Someone else suggested COMmotion, which would have been even better! :wink:
I may look like a mule, but I'm not a complete ass.
gnozal
PureBasic Expert
PureBasic Expert
Posts: 4229
Joined: Sat Apr 26, 2003 8:27 am
Location: Strasbourg / France
Contact:

Post by gnozal »

Impressive, thanks, and I like the name very much :wink:
For free libraries and tools, visit my web site (also home of jaPBe V3 and PureFORM).
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Post by ts-soft »

:D thanks stephen, good work!
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Image
User avatar
Rings
Moderator
Moderator
Posts: 1435
Joined: Sat Apr 26, 2003 1:11 am

Post by Rings »

thx for the pure source !!!

anyway M$' Com-Object Viewer can be download here

or that here


ts-soft & srod :
next step is to implement the ocx & variant helper stuff please :)
SPAMINATOR NR.1
User avatar
Kiffi
Addict
Addict
Posts: 1484
Joined: Tue Mar 02, 2004 1:20 pm
Location: Amphibios 9

Post by Kiffi »

@Stephen and Thomas:

Thanks for your great work!

Image

And here is my first question ;-)

I don't know, how to pass a ByRef-Parameter to a COM-Method.

For example

Code: Select all

Dim myTest As New ActiveXTest.clsActiveXTest
  
Dim myByRefParam As Long
  
myByRefParam = 20
  
Call myTest.Test1(myByRefParam) ' Test1 changes the myByRefParam from 20 to 100

Debug.Print myByRefParam ' -> myByRefParam = 100
Here is the Test1-Sub in the ActiveX-DLL:

Code: Select all

Public Sub Test1(ByRef P As Long)
  P = 100
End Sub
How to realize it with COMate? :oops:

TIA & Greetings ... Kiffi
Hygge
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

I am guessing that SetPropertyRef() is not appropriate?

Try

Code: Select all

myTest\Invoke("Test1(" + Str(@myByRefParam) + " AS Integer)")
or simply :

Code: Select all

myTest\Invoke("Test1(" + Str(@myByRefParam) + ")")
I may look like a mule, but I'm not a complete ass.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

@Rings, yes I'll get around to adding the OCX stuff later on. As for variants, COMate really wraps all of that to such an extent that you perhaps do not need to trouble yourself with them at all - unless you are having to work with safe arrays of course. I guess it also depends on the particular components you are using though. COMate will return variants for you if you are in need of that?

Beside's which the variant helper include can be just bolted staright into any COM automation client. The OCX stuff does need 'wrapping' however before it can work with COMate.
I may look like a mule, but I'm not a complete ass.
User avatar
Kiffi
Addict
Addict
Posts: 1484
Joined: Tue Mar 02, 2004 1:20 pm
Location: Amphibios 9

Post by Kiffi »

Hello srod,

thanks für your quick reply!

Unfortunately the ByRef-Parameter do not change his value.

Code: Select all

myByRefParam = 20
obj\Invoke("Test1(" + Str(@myByRefParam) + ")") 
Debug myByRefParam ; -> 20 (should be 100)
Any idea?

Greetings ... Kiffi
Hygge
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Any chance of posting the whole code and point me towards the dll in question etc? I should say that COMate is only able (at the time being at least) to interface with automation servers registered on the local machine. I'll probably change that later.
I may look like a mule, but I'm not a complete ass.
Marco2007
Enthusiast
Enthusiast
Posts: 648
Joined: Tue Jun 12, 2007 10:30 am
Location: not there...

Post by Marco2007 »

Hi Srod,

sounds very good. Image

Excel-Demo Image
Image

Almost every Code doing more than opening a window is a trojan.

lg
Marco
PureBasic for Windows
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

I think you should change your AV program! :)
I may look like a mule, but I'm not a complete ass.
Marco2007
Enthusiast
Enthusiast
Posts: 648
Joined: Tue Jun 12, 2007 10:30 am
Location: not there...

Post by Marco2007 »

I bought the license for two years.
JR Ewing?
PureBasic for Windows
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Marco2007 wrote:...JR Ewing?
That'll be Bericko's doing! :) I commented some time ago that I wanted a cool forum ranking and this is what I've ended up with! :)
I may look like a mule, but I'm not a complete ass.
Post Reply