views:

63

answers:

2

I've recently fixed a bug in a VB6 application, but I'm not sure, what exactly went wrong.

The offending part was a wrong API declaration of CreateEvent. This is, what API Viewer generated:

Declare Function CreateEvent Lib "kernel32" Alias "CreateEventA" 
(lpEventAttributes As SECURITY_ATTRIBUTES, ...) As Long

The next one is the wrong declare, obviously someone didn't want to import the SECURITY_ATTRIBUTES structure...

Declare Function CreateEvent Lib "kernel32" Alias "CreateEventA" 
(lpEventAttributes As Any, ...) As Long

The call was:

Event = CreateEvent(Nothing, 0, 0, "MyEventName")

This call worked always in the IDE, but never from the compiled .exe. (CreateEvent always returned 0)

I changed the declaration to:

Declare Function CreateEvent Lib "kernel32" Alias "CreateEventA" 
(ByVal lpEventAttributes As Any, ...) As Long

... and it worked.

Now I'm a little bit puzzled:

  • Why is the parameter ByRef when using SECURITY_ATTRIBUTES but must be ByVal when using Any?
  • Why did the wrong declare always work in the IDE?
+3  A: 

If you use an unqualified As Any parameter, you have to be explicit in the Call. This should have fixed the problem:

Event = CreateEvent(ByVal 0&, 0, 0, "MyEventName")

I can't see why you'd use Nothing here, since that's an Object reference and the call is expecting a pointer. What ByVal 0& does is pass a null pointer -- since it's null it doesn't matter what it's (not) pointing to. But passing Nothing ByVal probably forces ByVal 0&, which is why it worked.

As to why it worked in the IDE, well, the IDE does tend to be more forgiving about things like this.

Jim Mack
A: 

The parameter is ByRef for SECURITY_ATTRIBUTES as it is a memory pointer to a structure (block) of memory containing data. Passing a structure ByVal to an API from VB is not possible (see here). The As Any parameter declaration is really a VB cludge enabling multiple types of data to be passed using a single API declaration. Really multiple API definition 'aliases' should be declared, with the correct parameter type. i.e.

Declare Function CreateEventAsStruct Lib "kernel32" Alias "CreateEventA"  
(lpEventAttributes As SECURITY_ATTRIBUTES, ...) As Long

Declare Function CreateEventAsLong Lib "kernel32" Alias "CreateEventA"  
(lpEventAttributes As Long, ...) As Long

The 'As SECURITY_ATTRIBUTES' would be used to pass the structure, and the 'As Long' would be used to pass a null-pointer (0&).

Paul Williams