PDA

View Full Version : How to create Events in Girder without using an IR ?



McRib
November 8th, 2002, 02:38 PM
I need to make Girder react to a command sent by another application (VB6) in the same way it would react for example to an IR-Event.

Has anybody an idea, how this could be accomplished ?

As Girder does not support receiving messages from other apps, I'm a bit lost here...

JimHugh
November 8th, 2002, 09:56 PM
Read the FAQ at http://www.girder.nl/help/faq.php#107

How can I trigger a Girder event from outside of Girder ?

Mark F
November 9th, 2002, 01:43 AM
There is also some good information here (http://www.girder.nl/phpBB2/viewtopic.php?t=2352).

McRib
November 10th, 2002, 12:21 AM
While the Info provided by Mark looks optimal, I wonder if it's making sense to use the other option (calling Girder with command-line options) - as this one would be easier to implement.

I always thought of the command-line thing as a way to get something like different on-load actions by using different command-lines. Wouldn't it have a heavy impact on the system, when using this way to send information on a regular basis - i.e. every few seconds or so ?

Ron
November 10th, 2002, 01:44 AM
Can VB link to .dll files and use exported functions ? I think it can. I'm thinking about supplying a .dll files that allowes you to easily send events to girder without writing a plugin. Simply link to that file and voila.

McRib
November 10th, 2002, 02:35 AM
Can VB link to .dll files and use exported functions ?

Yes - that's no problem. Such a DLL would be great.

Of course one could use the TCP/IP-variant referred to above - but I think it's a lot of work for a quite simple task...

Ron
November 10th, 2002, 02:49 AM
does VB have suport for PCHAR arrays ?

eg:

gir_send_event( char * eventstring, int device, char *pld[], int pcnt )

Ron
November 10th, 2002, 05:24 AM
Girder 3.2.6 now has support for this new mechanism. Download this package:

http://www.girder.nl/developer.php?Link=442

It includes the files needed for C, its probably pretty straightforward to translate them to VB.

JimHugh
November 10th, 2002, 09:31 AM
AFAIK, VB can't staically link to a LIB file, but we can do a private function declare to a function in a DLL. So VB would need gireventlib.dll instead of gireventlib.lib.

An example that I use is a function from user32.dll ( the _ are line continuation characters in VB )

Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByVal LParam As Any) As Long

So I believe that we should be able to declare

int __stdcall gir_send_event_easy ( char * event, int device, char *pld1, char* pld2, char *pld3);

As

Private Declare Function GirSendEventEasy Lib "gireventlib" _
Alias "gir_send_event_easy" ( ByVal event as String, _
ByVal device as Long, _
ByVal as pld1 as String, _
ByVal as pld2 as String, _
ByVal as pld3 as String) as Long

In order to use it from VB

As far as gir_send_event is concerned, I'm not sure how to declare the char *pld[] and void *binpld arguments...

Ron
November 10th, 2002, 09:34 AM
AFAIK, VB can't staically link to a LIB file, but we can do a private function declare to a function in a DLL. So VB would need gireventlib.dll instead of gireventlib.lib.

I had a feeling that would not be possible, so gireventlib.dll is included in the Girder 3.2.6 distro. It exports the needed functions in the normal way.

About the char*[] probably not being possible with VB, that's why I made gir_send_event_easy.

JimHugh
November 10th, 2002, 10:09 AM
Simple Visual Basic Example for GirSendEventEasy in gireventlib - worked for me! Thanks for providing gireventlib support Ron!

Watch for line wrap!

' VB 6 Standard EXE, using default Form1 with 3 controls
' Textbox as Text1, CommandButton as Command1 and Label as Label1

Option Explicit
' full path need not be specified if gireventlib.dll is in:
'Directory Containing .exe
'Current Directory
'The Windows system directory (not necessarily /Windows/System)
'The Windows Directory (not necessarily /Windows)
'Path Environment Variable (This is the MS DOS path variable that can be checked by going into DOS and typing path.
'Visual Basic will search all of the directories listed in the path to find the DLL.)

Private Declare Function GirSendEventEasy Lib "d:\program files\girder\gireventlib.dll" Alias "gir_send_event_easy" (ByVal vEvent As String, ByVal vDevice As Long, ByVal pld1 As String, ByVal pld2 As String, ByVal pld3 As String) As Long

' 203 device code used by me because I already had the Internet Event Server setup
'Use appropriate device code for your install.
' Didn't need payload strings for this test

Private Sub Command1_Click()
Label1.Caption = GirderStatus(GirSendEventEasy(Text1.Text, 203, "", "", ""))
End Sub

Private Function GirderStatus(ByVal ret As Long) As String
Select Case ret
Case -1: GirderStatus = "Girder is not running, event not sent"
Case -2: GirderStatus = "Input devices not enabled, event not sent"
Case 1: GirderStatus = "Event sent successfully."
End Select
End Function

Ron
November 10th, 2002, 10:17 AM
I'm glad its working !

Can I include your example in the readme ?

JimHugh
November 10th, 2002, 10:18 AM
Absolutely!

Ron
November 10th, 2002, 10:21 AM
Thanks, it's included now. :-)

JimHugh
November 11th, 2002, 08:54 PM
As far as gir_send_event is concerned, I'm not sure how to declare the char *pld[] and void *binpld arguments...

I learned today that the *binpld argument should be declared "ByRef binpld As Any".

Still working on how to declare the PCHAR *pld[]. I suspect that I would use "ByRef pld() as String" which should provide the memory location of a VB String array.

I would appreciate it if someone would be kind enough to provide a C++ sample of calling gir_send_event.

In turn I will try my best to provide a matching VB example. I already provided a working VB example for gir_send_event_easy that Ron included in the updated gireventlib download.

Ron
November 12th, 2002, 01:38 AM
Here you go, the C/C++ version



char *a[3]; // our char array
char b[2]; // our binary data ( is not void * but only to keep the compiler happy )

a[0]="hello"; // load some default strings
a[1]="world"; // warning they are not allowed to be NULL
a[2]="again";

b[0]=(char)5; // load some binary data
b[1]=(char)254;

r = gir_send_event(event, dev, a, 3, (void*)b, 2); // send it.

JimHugh
November 12th, 2002, 11:21 AM
I found this article that shows how it might be done,

http://support.microsoft.com/default.aspx?scid=KB;en-us;q199824

But everything I have tried so far has ended up with a memory access violation and crashes the Visual Basic IDE.

I don't really need it for what I wanted to do, since the easy call works, but as any programmer can attest, it nags at you when you can't get something to work!

I'll keep trying though, either that or start working in C, C++, or C# again!

Ron
November 12th, 2002, 02:40 PM
Jim, the library will crash if any of the pointers to strings are NULL ( 0 ). That isn't really good behaviour, but sadly it slipped my attention. Make sure that isn't causing your crashes.

JimHugh
November 12th, 2002, 02:50 PM
Thanks for the tip, I wasn't passing null pointers.

GirderEventLib wasn't getting the memory exception and crashing, it was definitely VB. Girder was still up and running and working.

This is a snippet of what I tried last.

Private Declare Function gir_send_event Lib "gireventlib.dll" _
(ByVal vEvent As String, ByVal vDevice As Long, ByVal pld As Any, ByVal pldcnt As Long, _
ByVal binpld As Any, ByVal binlen As Long)

Private Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Var() As Any) As Long

Private Sub Command2_Click()
Dim a(2) As String
Dim b(0 To 1) As Byte
a(0) = "Hello"
a(1) = "World"
a(2) = "Again"
b(0) = Asc(5)
b(1) = Asc(254)
Label1.Caption = GirderStatus(gir_send_event(Text1.Text, 203, _
VarPtrStringArray(a()), UBound(a) + 1, VarPtrArray(b()), UBound(b) + 1))
End Sub

Ron
November 12th, 2002, 03:35 PM
The library isn't inside of Girder, if the library crashes Girder goes on happily... so the crash might still be in my lib.

The UBound function have you checked its return value ?

JimHugh
November 12th, 2002, 03:40 PM
UBound and LBound are a built in functions in VB.

VB Arrays are 0 based, as they are in C.

I did check UBound(a) and Ubound(b) in the Immediate window in VB. They returned 2 and 1 respectively, so I added 1 so the number of pld and pldbin array elements that you provided in your example was the same. I also tried hard coding it to 3 and 2.

Ron
November 12th, 2002, 03:52 PM
If I have some time tomorrow I'll update the eventlib to be a little bit more forgiving. Maybe that I'll get us closer to the answer.

MMcM
November 12th, 2002, 07:31 PM
I'm afraid that KB article isn't as helpful as it might be. I believe that the short answer is that you cannot do what you want with just these functions.

Arrays in VB are COM automation arrays, that is SAFEARRAY.

Take their lngArrayOfLongs(9) case. If you do VarPtrArray(lngArrayOfLongs), you will pass a SAFEARRAY**. From that, you can get the pvData as a long*. If you wanted to pass that long* directly, you would do VarPtr(lngArrayOfLongs(0)). That is, call by reference to the first element of the array. So far so good.

A String array is a SAFEARRAY of BSTRs. That is, UNICODE strings. If you do VarPtrStringArray(MyArrayOfStrings), you again pass a SAFEARRAY** whose pvData is a BSTR*. VarPtr(myArrayOfStrings(0)) will pass an ANSI char**, but only the one element will have been converted. VarPtrArray(MyArrayOfStrings) seems to also encounter this ANSI translation, but in a way that ends up with garbage. You can avoid this ANSI mess with the ODL trick described in the KB. That's how VarPtrStringArray is defined. You can do this again for a string by reference. Then VarPtrString(MyArrayOfStrings(0)) will pass a BSTR*. That's the closest you can get. It's an array of strings, but UNICODE strings.



[entry("VarPtr")]
long RTCALL VarPtrString([in] BSTR *Ptr);


In my opinion, the simplest way to avoid all of this hassle is to make gireventlib an in-proc automation server as well as a straight function library. This is pretty easy with ATL. Then VB can call its object method.

Ron
November 12th, 2002, 10:56 PM
Thanks Mike. I'm reading up on ATL.

http://www.codeproject.com/atl/

Ron
November 13th, 2002, 12:25 AM
Okay so I've got this



#include "gireventlib.h"
#define _UNICODE

#include <atlbase.h>
#include <atlconv.h>
#include "safearray_macro.h" // http&#58;//www.codeproject.com/atl/safearray_macro.asp


int __stdcall gir_vb_send_event &#40; char *event, int device, SAFEARRAY* vArray, void *p, int binlen &#41;
&#123;
USES_CONVERSION;

BSTR* pbstr;
PCHAR s;

BEGIN_SA&#40;vArray,pbstr&#41;
BEGIN_SA_LOOP&#40;&#41;
s=OLE2A&#40;pbstr&#91;INDEX_SA&#93;&#41;;
MessageBoxA&#40; 0, s , "String Array", 0&#41;;
END_SA_LOOP&#40;&#41;;
END_SA&#40;&#41;;

return 0;
&#125;


It SHOULD display one popup box for every string in the array that you pass. Since I do not have VB could you give this function a try. Its compiled into the .dll attached below.

MMcM
November 13th, 2002, 08:17 AM
If you put the code in a method on a Simple Object instead of just an exported function, it can be called from JScript and VBScript as well as full VB. Even from VBA in Excel, Word, ... (I guess an HT lobby written in PowerPoint almost makes sense. :wink: ) That also means you will be able to test it without needing VB. You'll need to limit the types to COM automation compatible ones.

Ron
November 13th, 2002, 09:09 AM
Yeah, but I have no clue about writing com stuff,... there is a lot of info on the web but so little time to read it.

Ron
November 13th, 2002, 11:03 AM
There is a small bug in gireventlib. It causes the library to send the first payload as payload 1,2 and 3. and forgetting payload 2 and 3. (Typo in sourcecode ).

Get the updated library.

http://www.girder.nl/temp/gireventlib.zip

JimHugh
November 14th, 2002, 08:18 AM
Tried it last night, still crashing VB.

I'm wondering if it is the binary payload array? Do both arrays need to be SafeArrays?

Ron
November 14th, 2002, 09:27 AM
Hmm,.. so you tried the gir_vb_send_event function (Note the VB in the name ). As you can see the code ignores the binary payload. So if it crashes its not the payload. Get the dll I gave in the post that I actually talk about the special VB function.

How did you define the function in VB ?

JimHugh
November 14th, 2002, 09:30 AM
Private Declare Function gir_vb_send_event Lib "gireventlib.dll" _
(ByVal vEvent As String, ByVal vDevice As Long, ByRef pld() As String, _
ByRef binpld() As Any, ByVal binlen As Long)

Private Sub Command3_Click()
Dim a(2) As String
Dim b(0 To 1) As Byte
a(0) = "Hello"
a(1) = "World"
a(2) = "Again"
b(0) = Asc(5)
b(1) = Asc(254)
Label1.Caption = GirderStatus(gir_vb_send_event(Text1.Text, 203, a, b, 3))
End Sub

Ron
November 14th, 2002, 09:32 AM
hmm,.. something strikes me here. I'm not a VB guy ( which you obviously already know ) but you DIM the string array with Param 2, but actually use 3 strings...

What does the 2 stand for,.. the number of strings ( as in C ) or the highest number of array element. If the latter where does the counting start 0 or 1...

JimHugh
November 14th, 2002, 09:40 AM
VB Arrays start at 0, just as in C.

So a(2) gives three elements, a(0) thru a(2)

Ron
November 14th, 2002, 09:42 AM
okay so that is different from c;



char *a&#91;3&#93;


would give 3 array elements named



a&#91;0&#93;
a&#91;1&#93;
a&#91;2&#93;


Well, I have no clue what to try next. Guess we are stuck with send_easy function until someone who actually knows C and VB helps us.

MMcM
November 14th, 2002, 08:10 PM
ATL objects are pretty easy to make. Just run the App Wizard for an ATL DLL. Then do Insert ATL Object and choose Simple Object. Then click right on the object's interface and do Add Method. The .IDL, .H, and .CPP files should all be made consistently for you. You just have to fill in the implementation, for which you have the basic idea already.

The only slightly tricky part is knowing what signature to give the method parameters. I suggest


&#91;in&#93; BSTR event, &#91;in&#93; short device, &#91;in&#93; SAFEARRAY&#40;BSTR&#41;* pld, &#91;in&#93; SAFEARRAY&#40;unsigned char&#41;* binpld

because this is the kind of thing VB likes.

This will result in a C++ method something like


BSTR event, short device, SAFEARRAY **pld, SAFEARRAY **binpld

which is very much like what you already have.

I further suggest that you add several methods. One with just the event, one with a single string payload, one with a string payload array, and one with everything. They should be able to share quite a lot of the implementation code.

I would take the result code from the C function and turn it into COM exceptions. Check ISupportErrorInfo when you add the Simple Object. Then use return AtlReportError in your method body to set up an error message and return the proper HRESULT.

Get it working as a separate DLL calling gireventlib first. Then just copy and paste the existing gireventlib code into that project and rename the result to be gireventlib.dll. Then we should have a nice self-registering in-process DLL that can be used from a variety of places.

I can give you more of the details this weekend if this is not enough to go on.

JimHugh
November 14th, 2002, 09:07 PM
MMcM,

Thank you for sharing your insight and experience, it sounds like you have the ability to facilitate a nice fusion of the fantastic power of Girder with the programming API needs of the (like it or not <g> ) masses!

Ron
November 14th, 2002, 11:27 PM
Thanks Mike,

Is there some application in which I can easily test my creation ? ( I do not have VB so that is not an option )

A quick test of your suggestion yield this function:



STDMETHODIMP CGirderEvent&#58;&#58;GirderEvent&#40;BSTR event, short device&#41;
&#123;
// TODO&#58; Add your implementation code here

return S_OK;
&#125;

and this definition


&#91;id&#40;1&#41;, helpstring&#40;"method GirderEvent"&#41;&#93; HRESULT GirderEvent&#40;&#91;in&#93; BSTR event, &#91;in&#93; short device, &#91;in&#93; SAFEARRAY&#40;BSTR&#41;* pld, &#91;in&#93; SAFEARRAY&#40;unsigned char&#41;* binpld &#41;;


Where did the safearrays go ??

Ron
November 15th, 2002, 01:31 AM
Hmm,.. doesn't even compile, there seems to be a problem with the SAFEARRAY definition...

Ron
November 15th, 2002, 01:53 AM
k, some hand tweaking and peaking in these sources :

http://www.codeguru.com/atl/COM_ATL_Tutorial.shtml
http://www.codeguru.com/atl/passing.html

Make the thing compile...

Ron
November 15th, 2002, 02:21 AM
Okay some new stuff to test.

This dll includes the com server with 4 functions :


SendEvent1, just a MessageBox that pops up.
SendEvent2, sends the eventstring and device into girder
SendEvent3, just a MessageBox popup that pops up for every Playload in the array
SendEvent4, almost fully functional SendEvent, only the binary payload is ignored.


Let me know how it works out.

Two questions;
1: this dll is automatically registered on my machine but how does this work on other machines ?
2: What files do I need to distribute ?

Thanks!




STDMETHODIMP CGirderEvent&#58;&#58;SendEvent1&#40;BSTR event, short device, SAFEARRAY *pPld, SAFEARRAY *pData&#41;
&#123;

MessageBox&#40;0,"Okay SendEvent1 call succesfull!","Success",0&#41;;

return S_OK;
&#125;

STDMETHODIMP CGirderEvent&#58;&#58;SendEvent2&#40;BSTR event, short device, SAFEARRAY *pPld, SAFEARRAY *pData&#41;
&#123;
USES_CONVERSION;
PCHAR s;

s=OLE2A&#40; event &#41;;
gir_send_event &#40; s, device, NULL, 0, 0, 0&#41;;

return S_OK;
&#125;



STDMETHODIMP CGirderEvent&#58;&#58;SendEvent3&#40;BSTR event, short device, SAFEARRAY *pPld, SAFEARRAY *pData&#41;
&#123;
USES_CONVERSION;
PCHAR s;
BSTR* pbstr;

BEGIN_SA&#40;pPld,pbstr&#41;
BEGIN_SA_LOOP&#40;&#41;

s=OLE2A&#40;pbstr&#91;INDEX_SA&#93;&#41;;
MessageBoxA&#40; 0, s , "String Array", 0&#41;;

END_SA_LOOP&#40;&#41;;
END_SA&#40;&#41;;


return S_OK;
&#125;


STDMETHODIMP CGirderEvent&#58;&#58;SendEvent4&#40;BSTR event, short device, SAFEARRAY *pPld, SAFEARRAY *pData&#41;
&#123;
USES_CONVERSION;
PCHAR s;
char *plda&#91;255&#93;;
int j,i=0;
BSTR* pbstr;


BEGIN_SA&#40;pPld,pbstr&#41;
BEGIN_SA_LOOP&#40;&#41;

s=OLE2A&#40;pbstr&#91;INDEX_SA&#93;&#41;;
plda&#91;i&#93; = strdup &#40; s &#41;;
i++;

END_SA_LOOP&#40;&#41;;
END_SA&#40;&#41;;


s=OLE2A&#40; event &#41;;
gir_send_event &#40; s, device, plda, i, 0, 0&#41;;


for &#40;j=0; j < i ; j++&#41;
&#123;
free&#40;plda&#91;j&#93;&#41;;
&#125;

return S_OK;
&#125;

Ron
November 15th, 2002, 04:16 AM
I tried this in powerpoint, but that did not work to well



Private Sub Girder_Test&#40;&#41;
Dim objTestATL As GIREVENTLib.GirderEvent
Dim a&#40;2&#41; As String
Dim b&#40;0 To 1&#41; As Byte
a&#40;0&#41; = "Hello"
a&#40;1&#41; = "World"
a&#40;2&#41; = "Again"
b&#40;0&#41; = Asc&#40;5&#41;
b&#40;1&#41; = Asc&#40;254&#41;

Set objTestATL = New GirderEvent

objTestATL.SendEvent1 "asdf", 18, a, b

objTestATL.SendEvent1 "asdf", 18, a, a

End Sub


Something about " interface is marked reserved ?" or Automation type not supported. ( note these are translation by me as I have a dutch version of Powerpoint ).

Mark F
November 15th, 2002, 05:41 AM
From WAY back in my deep dark past, I remember having to mark objects as scriptable when you build them. I don't rememebr how though. :(

JimHugh
November 15th, 2002, 06:30 AM
VB auto registered the girevent.dll when I used the Project | References and browsed to the DLL. RegSvr32 can be used manually register it.

I received the following when trying to execute SendEvent1

Function or Interface marked as restricted, or the function uses an automation type not supported in Visual Basic.

But at least VB did not crash this time!

From http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncomg/html/comwatl.asp

"Every OLE object must implement the IUnknown interface, which allows controllers to query the object to find out what interfaces it supports. IUnknown has three member functions: QueryInterface, AddRef, and Release"

This also provides Intellisense within the VB/VBA programming environment, which SendEvent1 (and 2,3,4) does not have.

MMcM
November 15th, 2002, 08:16 AM
Very briefly and in order.

You can test with VBScript. You will need to write additional methods that just take a SAFEARRAY (that is, an array of VARIANT) and convert each element to BSTR. Again, this is pretty easy in ATL using CComVariant::ChangeType(VT_BSTR, pvData+i). VBScript doesn't have arrays with specific element types (which means binary payload is out of the question, pretty much, so the number of methods in the end will be less). Set the Debug executable to wscript.exe and give the .VBS file as the command line argument. But maybe don't worry about this first.

When the App Wizard screws up, you can get the correct signature for the methods from the .H file generated by MIDL. Likewise if you need to edit the .IDL file. (Always a problem with wizards.) The .IDL file is the thing that drives the rest, so that's what you need to get right.

On the client machine, your installer can do REGSVR32 /S xxx.DLL. If you build Release MinDependency, nothing special will be needed beyond what Windows already has.

You can often work around type problems by using IDispatch instead of the custom dual interface. Then you won't get compile time type checking, but more comprehensive type conversion will be done by the callee. Switch to Dim objTestATL As Object and Set objTestATL = CreateObject("GIREVENTLib.GirderEvent").

Are you sure you did SAFEARRAY(BSTR)*? You ended up with SAFEARRAY* and not SAFEARRAY**. I glanced at the .TLB in your .ZIP and it doesn't have the VT_BYREF. VB insists that arrays be by reference.

I have to get to a meeting. I'll try to offer more specific suggestions tonight (East Coast time).

Ron
November 15th, 2002, 08:58 AM
Thanks Mike, I just figured it out a few seconds ago. It was a combination of things that made it go wrong :( ( Including the * instead of the ** ). That went wrong right from the start for some reason VC++ doesn't like the definition that you gave before. But entering it by hand does work.

I'm cleaning it up,...

Ron
November 15th, 2002, 09:28 AM
Okay here it is.

Things todo:
Binary payload
ErrorHandling

Wishes
Exporting events ( event sink ?? How on earth to implement this )

JimHugh
November 15th, 2002, 09:42 AM
Thanks Ron, I appreciate the your efforts!

It now works from VB as a regular object without the need for API declarations.

It appears that SendEvent returns a Void now so in effect is a now a Sub instead of a function, therefore no return value.

After sending a test event to Girder from VB using your example code, the event executed, but when I looked at Girders Show Variables, pld0 through pld10 are blank. It did set the EventDeviceID

Ron
November 15th, 2002, 09:55 AM
pld#'s are only set DURING the event.

Actually the EventDeviceID should have been zero too outside of the event. ( but that is a know 'bug' ).

JimHugh
November 15th, 2002, 10:09 AM
Oops, you are right of course! Hadn't paid too close attention to that before.

I have been using an event with an OSD that has two commands in a MultiGroup to get the Screen Resolution and store it, then display it.

I just modified it to display pld0 through 4.

Current Resolution is [LASTRESOLUTION]

[pld0]
[pld1]
[pld2]
[pld3]
[pld4]

With the last test code it displayed:

Current Resolution is 1024x768x32@60

Hello
Hello
World
Again

In other words pld0 and pld1 were set to the same value.

Ron
November 15th, 2002, 11:13 AM
Congrats,.. pld0 is another known bug :-) ( It should not be there at all )

Ron
November 15th, 2002, 12:40 PM
Mike, is it possible to create overloaded function with COM/ATL ?

Ron
November 15th, 2002, 03:13 PM
Okay this is an official RFC (Request for comment).

Look at the GirderEvent lib and tell me if this is the way it should be implemented to be generally usefull. ( I've tested VBA ) I would like to add some way of sending events back to the applications but for now that seems a little tricky. So we are going to have to do with this unless someone has another hint on how to go about this ;-)




Private Sub Girder_Test&#40;&#41;

Dim GirderEventLib As GIRDERLib.GirderEvent
Dim a&#40;2&#41; As String
Dim b&#40;0 To 1&#41; As Byte

a&#40;0&#41; = "Payload 1"
a&#40;1&#41; = "Payload 2"
a&#40;2&#41; = "Payload 3"
b&#40;0&#41; = 5
b&#40;1&#41; = 25

Set GirderEventLib = New GirderEvent

On Error GoTo ErrLabel&#58;

GirderEventLib.SendEventSimple "Event1-Simple", 18
GirderEventLib.SendEvent "Event2-Normal", 18, a
GirderEventLib.SendEventFull "Event3-Full", 18, a, b

Exit Sub

ErrLabel&#58;

Select Case Err.Number

Case -2147483647 ' input devices not enabled

Debug.Print "Input device not enabled"


Case -2147483648# ' girder not running

Debug.Print "Girder not Running"

Case Else

Err.Raise Err.Number, Err.Source, Err.Description, _
Err.HelpFile, Err.HelpContext

End Select

End Sub

MMcM
November 15th, 2002, 04:30 PM
There is no real overloading in COM automation, unfortunately.

There are optional parameters. But they must be VARIANT (needed to store the out-of-band missing indicator). That means no compile time type checking and a bit more work in the callee doing type checking / coercion by hand. But you could get away with a simpler signature. And you could have some data-type flexibility, such as allowing a scalar string value for the payload as equivalent to a one-long array. It's a tradeoff.

I do think that having a simple way to get one payload string is important. Among other things, it would be callable from VBScript / JScript. In fact, I wouldn't bother with the multiple string and binary payloads from those scripts. Just a single string seems enough for the simple cases they are likely to deal with.

A different approach to covering the bases would be to make the object stateful (to borrow J2EE terminology). Make the event, device, payload array, and binary payload properties. Then have just one method with no args to send.



Dim gobj as New GirderEvent
gobj.event = "Event-Name"
gobj.device = 18
gobj.payload = strarr
gobj.binaryPayload = binarr
gobj.Send

or even


Dim gobj as New GirderEvent
gobj.event = "Event-Name"
gobj.device = 18
gobj.payload&#40;0&#41; = "Payload 1"
gobj.payload&#40;1&#41; = "Payload 2"
gobj.binaryPayload = binarr
gobj.Send

Ron
November 16th, 2002, 01:52 AM
Good idea Mike.

Here is the updated implementation. I decided not to support the binary payload for the statefull approach just yet. Nobody actually uses it anyway.



Private Sub Girder_Test&#40;&#41;

Dim GirderEventLib As GIRDERLib.GirderEvent
Dim a&#40;2&#41; As String
Dim b&#40;0 To 1&#41; As Byte

a&#40;0&#41; = "Payload 1"
a&#40;1&#41; = "Payload 2"
a&#40;2&#41; = "Payload 3"
b&#40;0&#41; = 5
b&#40;1&#41; = 25

Set GirderEventLib = New GirderEvent

On Error GoTo ErrLabel&#58;

' 4 ways to send an event to Girder 3.2.6+ or 4.x

GirderEventLib.SendEventSimple "Event1-Simple", 18
GirderEventLib.SendEvent "Event2-Normal", 18, a
GirderEventLib.SendEventFull "Event3-Full", 18, a, b

' Statefull Sending
GirderEventLib.Device = 2002
GirderEventLib.EventString = "you!"
GirderEventLib.Payload&#40;1&#41; = "Payload1"
GirderEventLib.Payload&#40;3&#41; = "Payload3" ' payloads do not have to be consecutive.
GirderEventLib.Send

' the state can be reset to the default values with "Reset"
GirderEventLib.Reset
GirderEventLib.EventString = "after reset"
GirderEventLib.Send

Exit Sub

ErrLabel&#58;

Select Case Err.Number

Case -2147483647 ' input devices not enabled

Debug.Print Err.Description


Case -2147483648# ' girder not running

Debug.Print Err.Description

Case -2147483646# ' Eventstring not set.

Debug.Print Err.Description

Case -2147483645# ' Payload out of range

Debug.Print Err.Description


Case Else

Err.Raise Err.Number, Err.Source, Err.Description, _
Err.HelpFile, Err.HelpContext

End Select

End Sub


If someone could try out VBScript or JScript that would be great.

JimHugh
November 16th, 2002, 08:03 AM
In VB, without Girder running, it did not generate an error.

Reset did not reset the last device used, maybe that's a feature? <g>

Changing the VB code to use CreateObject instead of New

'Set GirderEventLib = New GirderEvent
Set GirderEventLib = CreateObject("GIRDERLib.GirderEvent")

I receive error 429, ActiveX Component Can't Create Object, poked around in the registry and saw an entry for Girder.GirderEvent.1, I then used that instead in VB and then it worked.

In VBScript, I 424 Get Object required...

' save following as a file with a .VBS extension i.e. Girder_Test.VBS
' and execute from a command line with Girder_Test.VBS
' or Cscript Girder_Test.VBS
' All variables are variants and not explicity dimmed
' goto error label not supported

Call Girder_Test

Private Sub Girder_Test()
Dim GirderEventLib ' As GIRDERLib.GirderEvent
Dim a(2) ' As String
Dim b(1) ' As Byte

a(0) = "Payload 1"
a(1) = "Payload 2"
a(2) = "Payload 3"
b(0) = 5
b(1) = 25

Set GirderEventLib = CreateObject("Girder.GirderEvent")

On Error Resume Next' GoTo ErrLabel:

' 4 ways to send an event to Girder 3.2.6+ or 4.x

GirderEventLib.SendEventSimple "Event1-Simple", 18
GirderEventLib.SendEvent "Event2-Normal", 18, a
GirderEventLib.SendEventFull "Event3-Full", 18, a, b

' Statefull Sending
GirderEventLib.Device = 2002
GirderEventLib.EventString = "you!"
GirderEventLib.Payload(1) = "Payload1"
GirderEventLib.Payload(3) = "Payload3"
GirderEventLib.Send
if err then Call ErrorReport(Err.Number, Err.Description)

' the state can be reset to the default values with "Reset"

GirderEventLib.Reset
GirderEventLib.EventString = "after reset"
GirderEventLib.Send
if err then Call ErrorReport(Err.Number, Err.Description)

Exit Sub

End Sub

' ErrLabel:
Sub ErrorReport(en, ed)
Select Case en

Case -2147483647 ' input devices not enabled
Wscript.Echo ed
Case -2147483648 ' girder not running
Wscript.Echo ed
Case -2147483646 ' Eventstring not set.
Wscript.Echo ed
Case -2147483645 ' Payload out of range
Wscript.Echo ed
Case Else
Wscript.Echo en, ed ' Err.Source, Err.Description, Err.HelpFile, Err.HelpContext
End Select

End Sub

Ron
November 16th, 2002, 10:05 AM
Why change to CreateObject ?

JimHugh
November 16th, 2002, 10:09 AM
Scripting does not have the New operator, Objects can only be instantiated by using CreateObject or from an object factory of an another object.

In the VB code, I was trying to determine if CreateObject would work so that I could get the right object name for Scripting.

Ron
November 16th, 2002, 10:09 AM
In VB, without Girder running, it did not generate an error.


VBA does generate an error. Don't know why VB fails.

Ron
November 16th, 2002, 10:14 AM
Anyone know how to fix the stupid CreateObject problem ? I don't want to have to specify a name with .1 appended,.. there must be another way.

[edit] Seems that this is a standard way to do this ?? How strange.

MMcM
November 16th, 2002, 10:24 AM
Doesn't the generated GirderEvent.rgs file have entries for both GirderEvent and GirderEvent.1? It ought to and usually does when I use the app wizard.

IGirderEvent isn't dual. It needs to be to be usable from VBScript. I thought that this was the default in Insert ATL Object. When it says Object required, it means that GirderEventLib is bound to an Unknown as opposed to an Object (meaning IDispatch -- a COM automation object).

Ron
November 16th, 2002, 10:28 AM
yes dual is default, but default doesn't work... I can't quite remember what it was but it didn't work. I had to set it to custom.

I'll restart again :( Man this COM stuff is boring.

MMcM
November 16th, 2002, 10:34 AM
It's a fundamental problem with wizards that you find yourself cutting and pasting all the non-generated code back into a new generated skeleton because you had to change one of the wizard options. It's a bit faster than doing it without the wizard, though, since there are so many places that know the same thing. .Net claims to fix that, but I haven't used it enough to validate the claim.

Ron
November 16th, 2002, 11:27 AM
okay,.. here is the com library with the dual interface. I also added a connectionpoint interface to be able to send events back to the caller, though nothing is implemented yet. Need to find docs about this.

JimHugh
November 16th, 2002, 12:02 PM
I just tried it, still works under VB, but not in VBScript.

I didn't see the ConnectionPoint interface in the VB Object Browser.

BTW, sorry about reporting VB not seeing the error handler, it does. My only excuse is that it was 7am on Saturday, I had just gotten up and had no coffee yet!

Ron
November 16th, 2002, 12:17 PM
Are you sure you are using the new girder.dll ? I had to restart my computer to get it to work under VBA. :-? Could I embed this com object into a HTML page in IE ? I assume its possible,.. anyone an idea how ? So I can test the VBScript thing.

about the ConnectionPoint interface, I'm not sure you would see it if it doesn't have any functions,..


BTW, sorry about reporting VB not seeing the error handler, it does.
Don't worry about it.

JimHugh
November 16th, 2002, 12:22 PM
No, I did not reboot.

I did unregister the dll and copy over and register the new one.

You don't have to use IE to run VBScript.

Windows Scripting Host wscript.exe is installed automatically under Windows 2000. Any text file with a VBS extension is executable.

I posted the full script I was using for testing earlier in this thread.

Ron
November 16th, 2002, 12:32 PM
Right!

Indeed,.. SendEventSimple works just fine, but SendEvent and SendEventFull complain about Type mismatch,.. as Mike (MMcM) predicted. That is why he suggested to make the 'statefull' approach. And on my system that works like a charm.

Was that the bug you where talking about ?

JimHugh
November 16th, 2002, 12:42 PM
I can't even get the object created in VBScript, so I don't have the type mismatch probem yet.

I did find this article http://www.microsoft.com/mind/0100/Basics/Basics0100.asp that discusses what is necessary to create a C++ COM component that is callable from a scripting language... Maybe it will help get you get back into the meat of Girder and out of this COM rut I've got you in... 8)

Ron
November 16th, 2002, 12:48 PM
Jim, it works here with VBA and VBS... what can I say. :-) I think it has something to do with your system. I noticed that windows got very confused by all my different GirderEvent Com libraries with the different IDs.

Lets see the uuid that should work are :

GirderEvent Class
EAFAA938-51EA-4C1B-9489-88EE8C7C162B

GirderEvent Events Interface ( not much here )
64636420-6D01-4A01-BB76-4A84169A25B0

Girder Type Library
621436EB-5507-4495-AE67-0D693E08D126

IGirderEvent Interface
D2CAA27D-733C-474B-806B-35F80D3982F2

[edit] All of the stuff in that article was automatically taken care of by the ATL Com library wizard. So I do not have to worry about that.

JimHugh
November 16th, 2002, 12:58 PM
Here is the script wrapped in HTML. Since it has to be on the same machine anyway, I used the HTA extension to prevent the ActiveX security warning

Ron
November 16th, 2002, 01:04 PM
It works on my system. You don't indicate that in your last post, but was it, or was it not working on your system ?

( I did have to uncomment the SendEvent* functions as they are not supported in VB.. as per previous argument )


Girder.dll : 32768 bytes

JimHugh
November 16th, 2002, 01:19 PM
No, still not working under VBScript.

Directory of D:\Program Files\Girder\*.dll

11/16/2002 10:32 32,768 Girder.dll
11/15/2002 10:59 28,672 girevent.dll
11/10/2002 12:29 28,672 GVMS.dll
06/07/2002 05:13 40,960 Logger.dll
10/23/2002 16:29 180,224 LUA.dll
10/25/2002 23:30 49,152 watch.dll

I did unregister, reboot, and reregister Girder.dll and GirEvent.dll

I searched for all of the UUID's you posted earlier, I don't have any of them. This is what I have:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Girder.GirderE vent]
@="GirderEvent Class"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Girder.GirderE vent\CLSID]
@="{CB9DBCCD-4766-40B6-926E-D0D7A688BB3F}"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Girder.GirderE vent\CurVer]
@="Girder.GirderEvent.1"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Girder.GirderE vent.1]
@="GirderEvent Class"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Girder.GirderE vent.1\CLSID]
@="{CB9DBCCD-4766-40B6-926E-D0D7A688BB3F}"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Girevent.Girde rEvent]
@="GirderEvent Class"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Girevent.Girde rEvent\CLSID]
@="{606F80BE-DB0C-4306-B6AC-27D4DB10DE41}"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Girevent.Girde rEvent\CurVer]
@="Girevent.GirderEvent.1"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Girevent.Girde rEvent.1]
@="GirderEvent Class"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Girevent.Girde rEvent.1\CLSID]
@="{606F80BE-DB0C-4306-B6AC-27D4DB10DE41}"

Ron
November 16th, 2002, 01:24 PM
Okay,.. so the incorrect file is registered on your system. At least we found that out now...

Now how to fix this. I have also seen that some of these libs are a little hard to register for some reason. It took me several tries before the old Lib was gone and the new was registered. I think a reboot finally did it for me. But you tried that already....

well just to be sure you got the correct girder.dll (and I upload the correct one ;-) ) here is the dll again

http://www.girder.nl/temp/GirderSURE.zip

Try installing this dll file in a different directory. In powerpoint I can see the path of the com object, then you could check if the path is pointing to the correct girder.dll.

JimHugh
November 16th, 2002, 01:33 PM
SUCCESS! :D

Thanks for your persistence and patience on this one Ron!

I'll drink one for you at our local SudWerk brewery!

Ron
November 16th, 2002, 01:46 PM
GREAT!! 8)
Aaah California,... have a New Castle on me,... I remember those beers being very popular over in Santa Barabara ;-) Just 2.5 more months before I'm back in town!!

Ron
November 17th, 2002, 02:16 AM
Can anyone tell me how to sink an event in VB / VBS ?

I've prepared a Com dll that has a connectionpoint called gireventa it doesn't do much usefull stuff yet but I'm learning ;-) The event is triggered when you call "send".

http://www.girder.nl/temp/GirderComWithEvent.zip

MMcM
November 17th, 2002, 07:39 AM
In VBA, you use Dim WithEvents. The handler has to be an object in its own right for the attachment lifecycle to work out. So, create a Class Module


Dim WithEvents GirderEventLib As GirderEvent

Sub GirderEventLib_gireventa&#40;ByVal Device As Long&#41;
MsgBox "Dev = " & Device
End Sub

Sub test&#40;&#41;
Set GirderEventLib = CreateObject&#40;"Girder.GirderEvent.1"&#41;
GirderEventLib.Device = 2002
GirderEventLib.EventString = "event"
GirderEventLib.Payload&#40;1&#41; = "Payload"
GirderEventLib.Send
End Sub


and a regular Module


Sub Main&#40;&#41;
Dim x As New Class1
x.test
End Sub


and run that one.

MMcM
December 1st, 2002, 08:10 AM
Is this COM server due to become part of the normal distribution?

Ron
December 1st, 2002, 08:45 AM
Yes it is, sadly I simply didn't have any time to finish it. Between Girder 4 and graduating there is just not that much time left.

Ron
December 1st, 2002, 01:27 PM
I've uploaded the sources of the library. If anyone feels like hacking on them,.. go right ahead.

http://www.girder.nl/developer.php?Link=451

vbich
January 14th, 2003, 10:49 PM
Just out of curiosity, do events from Grirder to the VBS scripts work?

Thanks!

Ron
January 15th, 2003, 07:12 AM
Yep from VB to Girder works ( the other way around not yet)