The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

I must be doing something silly (DLL Declare in VB)

Hi All,

I am attempting to Declare a function call in VB to a Microsoft DLL and keep running into problems with a "Bad DLL calling convention" error. The Function is identified in the C Header file as

__in DELTA_FILE_TYPE FileTypeSet,
__in DELTA_FLAG_TYPE SetFlags,
__in DELTA_FLAG_TYPE ResetFlags,
__in LPCSTR lpSourceName,
__in LPCSTR lpTargetName,
__in_opt LPCSTR lpSourceOptionsName,
__in_opt LPCSTR lpTargetOptionsName,
__in DELTA_INPUT GlobalOptions,
__in_opt const FILETIME *lpTargetFileTime,
__in ALG_ID HashAlgId,
__in LPCSTR lpDeltaName

/** Type for input memory blocks. */
typedef struct _DELTA_INPUT
/** Start of memory block, if it is not Editable. */
LPCVOID lpcStart;

/** Start of memory block, if it is Editable. */
LPVOID lpStart;

/** Size of memory block in bytes. */
SIZE_T uSize;

BOOL Editable;


I have declared the function in VB as:

Public Declare Function CreateDeltaA Lib "msdelta.dll" (ByVal FileTypeSet As Currency, ByVal SetFlags As Currency, _
ByVal ResetFlags As Currency, ByVal lpSourceName As String, ByVal lpTargetName As String, _
ByVal lpSourceOptionsName As String, ByVal lpTargetOptionsName As String, _
ByRef GlobalOptions As DELTA_INPUT, ByRef lpTargetFileTime As Long, _
ByVal HashAlgId As Integer, ByVal lpDeltaName As String) As Long

and the struct as:

' Type for input memory blocks. */
lpcStart As Long

' Size of memory block in bytes. */
uSize As Long

Editable As Long
End Type

I am not sure where I am making the mistake. I have tired a lot of permutations, like changing ByRef's to ByVal's, string pointers to Long, etc.)

I can make a C program that calls this function fine. I can also call a similar function in VB that only has the Currency and String data types, which makes me believe it has to do with the struct or the pointer.

Any help would be appreciated.
Nick Koranda Send private email
Tuesday, September 12, 2006
I believe that the issue is the DELTA_INPUT structure is being passed by value and not by a pointer.  VB cannot pass a structure by value.

Can someone who knows C better then I do confirm that the decleration for passing of the DELTA_INPUT struct is by value.  What I mean is that the whole structure (three variables) would be placed on the stack versus a pointer to the structure placed on the stack before the function is executed.
Nick Koranda Send private email
Tuesday, September 12, 2006
Yes, it is.
Mike S. Send private email
Tuesday, September 12, 2006
Are you sure those routines are compiled with the stdcall convention instead of the cdecl call that Classic VB can't make?
Artad Gobeski
Tuesday, September 12, 2006
Never mind, now I see the WINAPI that almost certainly expands to STDCALL.
Artad Gobeski
Tuesday, September 12, 2006
What's with the Currency type?
Almost H. Anonymous Send private email
Tuesday, September 12, 2006
Yeah the WINAPI is derived from the stdcall.

The Currency type is a 64 bit integer variable.  It is "equivalent" to the ___int64 data type.

I believe I found a way to pass a structure as a value in VB.  I have expanded the function declerations so that the struct being passed is now split into three parameters:

ByVal GlobalOptions As Long, ByVal GlobalOptions2 As Long, ByVal GlobalOptions3 As Long

That way the same number of bytes is being passed to the function.  If my infinite wisdom serves me right, then the function will  just place the additional parameters onto the stack before the function code is executed, just like an equivalent C call would.

Of course, I am still not successfully calling this function...I press on.
Nick Koranda Send private email
Tuesday, September 12, 2006
If I remember correctly from my past experience, you have to declare Byte array with the same size as the C structure, copy the bytes from the VB Type in and pass the address of the first byte in place of the structure.

Something like:

Dim arrStruct() as Byte
Redim arrStruct(LenB(VBType))'Must be same size as the C struct

CopyMemory arrStruct(0), VBType
DllCall -//-, -//-, ByVal arrStruct(0), -//-
CopyMemory VBType, arrStruct(0)

Now, I was doing this successfully in the past, but it has been awhile and I just typed the code inplace, so probably I am wrong. I think that the function Declare statement should use ByRef for the structure but you should specificaly use ByVal in the actual call (or other way arround?!).

I suggest you save your VB work before any debug session, because you can get frequent crashes from VB DEV environment.
g Send private email
Wednesday, September 13, 2006

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
Powered by FogBugz