Link to home
Start Free TrialLog in
Avatar of mairouka
mairouka

asked on

calling dll from vb6 with struct argument

Hi!
I'm trying to pass a struct from vb6 to a c dll and write it over an existing struct in the dll
I've written the code below:
in vb----------------------------------------------

Option Explicit
    Private Declare Sub func Lib "c:\StrSamp.dll" _
           (s As mpa)

Private Type mpa
    a As Integer
    b As Integer
    c As String
End Type

Dim m As mpa

Private Sub Form_Load()
m.a = 2
m.b = 4
m.c = "xexe"

func m

End Sub


and in c dll------------------------------------------
in a header file m , i have stored the struct
m.h
typedef struct __S{
     int m;
     int n;
     char *o;
}S;

and in the cpp file of the dll i have the following code:

#include <windows.h>
#include "m.h"

    void __stdcall func(S d)
            {
         MessageBox(NULL,"ok struct!","progress",MB_OK);
         MessageBox(NULL,d.o,"member_of_struct",MB_OK);
            }

------------------------------------------------
it doesn't work properly.after it prints message_box "xexe",i get an
error message:
" Run-time error 149'
  Bad DLL calling convention "

how can this program work?
please,help!
:o(
Avatar of vbPhil
vbPhil

This is kind of off the cuff... but I'm half thinking that you shouldn't have dynamic strings in your structs when passing between VB and C.


Your code has several improvements/bugs:

1- Pass structure by reference

2- char* is not the same than a string. VB strings and C strings are completely different.

3- Better use longs instead of ints

Your code working

VB Code:

Option Explicit
   Private Declare Sub func Lib "c:\StrSamp.dll" _
          (ByVal s As Long)

Private Type mpa
   a As Long
   b As Long
   c(1 To 50) As Byte
End Type

Dim m As mpa

Sub VBStrToCharP(strIn As String, strOUT() As Byte)

    Dim n As Long
    For n = 1 To Len(strIn)
        strOUT(n) = Asc(Mid(strIn, n, 1))
    Next
   
    'strings in C are zero ended
    strOUT(n) = 0
   
End Sub

Private Sub Form_Load()

    m.a = 2
    m.b = 4
    StrToCharP "xexe", m.c
   
    func VarPtr(m)

End Sub


C Code:

typedef struct __S{
    long a;
    long b;
    char c[50];
}S;


   void _stdcall func(S* d)
   {

        char Dummy[500];

        MessageBox(NULL,"ok struct!","progress",MB_OK);

        sprintf(Dummy,"a=%d",d->a);
        MessageBox(NULL,Dummy,"member_of_struct",MB_OK);
       
        sprintf(Dummy,"b=%d",d->b);
        MessageBox(NULL,Dummy,"member_of_struct",MB_OK);

        MessageBox(NULL,d->c,"member_of_struct",MB_OK);

   }

Regards
sorry

line StrToCharP "xexe", m.c

should be

line VBStrToCharP "xexe", m.c

When you pass a user defined struct from VB to a C or C++ or Windows API you should declare the function as Any.
that is the function declration should be

Private Declare Sub func Lib "c:\StrSamp.dll" _
          (BYVAL s As Any)

The second option is

Declare the function with the member variables of the structure itself that is

Private Declare Sub func Lib "c:\StrSamp.dll" _
              (Byval m as Integer,Byval n as integer, Byval o as string)

Vb will automatically pass the correct structure when you call the function

I hope it will work
     

Avatar of mairouka

ASKER

thank you! it really worked!
but what if, i write " unsigned char c " instead of " char c[50] " in struct S in my c code?
Doing so,i come up to problems again....!
i intend to use types unsigned char and unsigned short in my c code,as i want it to be compatible with a code i've already written.
is there any advise?
thanx again!
thank you! it really worked!
but what if, i write " unsigned char c " instead of " char c[50] " in struct S in my c code?
Doing so,i come up to problems again....!
i intend to use types unsigned char and unsigned short in my c code,as i want it to be compatible with a code i've already written.
is there any advise?
thanx again!
Struct in C and type in VB must be the same. What means the same?

Each member of struct in two languages must have same lenght in bytes if you want to directly handle this struct.

Each data type has its own lenght and in VB for example, an string has dynamic lenght. Then this data type is not suitable to use in VB types to pass structures to C. This don't mean that a VB string can't be passed to C, only is not suitable. As a single parameter can be easily passed to C, and inside an structure can be handled in C with some code, but what we want here is to directy handle structure.

To make things harder, not only must have same lenght in bytes it must have same bit convention, i.e. signed/unsigned and order of bytes. Remember we are always talking to DIRECTLY handle structs.

Take a look here to see C types

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccelng/htm/reftable_1.asp

and here to VB types

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbenlr98/html/vagrpDataType.asp


Be very carefully when writing in struct within C code not to pass struct bounds. If you do it, results are unpredictible, VB IDE can crash,....

Hope this clarifies things a bit.

Cheers
sorry but with unsigned char and unsigned short types the same programm doesn't work and the site didn't help me much.....any example? any idea?
i would appreciated it,if somebody could give me a hint!
Please, can you give further details about what you intend to do?
I write the interface(in vb) of a network device. i have the code of the protocol the device uses , in c and writting now the interface in vb. From vb i call the routines of the protocol with the form of dll's. I want now to pass a struct from vb in a dll so that after tha call the fields of the vb struct are written over the fields of the struct used in c. The c struct has types of form unsigned char and unsigned short,so i have to use in my vb application some matching types to these . I have tried and haven't done anything much....! I can't change the types in the c code....so.....!
Ok you have problems with unsigned char and unsigned short in C, but from which VB types are you trying to translate??

Post VB type you actually have and C struct that you cannot change and I'll give you code to translate it...
because the struct has too many fields i gine you a sub_struct of the original one:

in the c code the struct is:
typedef struct __communityId {
     char name[3];
     int  n;    
     int o;
}communityId;
typedef struct __M {
     unsigned char     a[6];
     unsigned char     b[4];
     unsigned char     c[4];
     unsigned char     d[4];      
     unsigned char  e;                    
     unsigned char   f;                
     unsigned char g[32];          
      unsigned char     h;
     unsigned char     i[4][13];    
       unsigned char     j[6];
     unsigned char  k;
     unsigned char   l[4];    

     communityId communities[3];
     unsigned char  m[16];

}M;

in the vb code the struct is:
Type x
    onoma As String
    n As Integer
    o As Integer
End Type
Type m
    a(1 To 6) As Variant
    b(1 To 4) As Variant
    c(1 To 4) As Variant
    d(1 To 4) As Variant
    e As String
    f As Variant
    g  As Variant
    h As Variant
    i(1 To 4, 1 To 13) As Variant
    j(1 To 6) As Variant
    k As Variant
    l(1 To 4) As Variant
   
    community(1 To 3) As x
    m As Variant

End Type

the vb struct m fills it's fields from text boxes,combo,check boxes etc. from user inserted values.
for this struct some possible values would be

 0x0 0x1 0x2 0x3 0x4 0x5                  // a
  10 170 254 1                                // b
  255 255 255 255                 // c
  0 0 0 0                         // d
  0                            // e
  0                           // f
  "company"                      // g[32]
  0                          //h
  0 0 0 0 0 0 0 0 0 0 0 0 0  // i1
  0 0 0 0 0 0 0 0 0 0 0 0 0   // i2
  0 0 0 0 0 0 0 0 0 0 0 0 0  // i3
  0 0 0 0 0 0 0 0 0 0 0 0 0  // i4
  0 0 0 0 0 0                      // j[6]
  0                          // k
  0x82 0x84 0x8b 0x96            //l[4]
  "one"                       //community member 1
  0
  6
 "two"                       //community member 2
  0
  6
 "three"                    //community member 3
  0
  6
  "A"                         //m



from vb i call
Private Declare Function Initialization Lib "C:\func.dll" (ByVal s As Any) As Integer

and somewhere in the code when the m struct is filles
func VarPtr(m)

and in the c code:
somewhere in a header there is:
extern M x
and in the code where the func is

extern "C" __declspec(dllexport) int func (M* x)
{
  // code lines
}

waiting for your reply!!! :)
ASKER CERTIFIED SOLUTION
Avatar of Smallint
Smallint

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
mairouka:
This old question needs to be finalized -- accept an answer, split points, or get a refund.  For information on your options, please click here-> http:/help/closing.jsp#1 
EXPERTS:
Post your closing recommendations!  No comment means you don't care.
with your help people , i finally solved my problem...... thanx for the advice!
:) :) :) :)
little_mg is mairouka ! i have changed my nick_name! ;-)
No Comment has been added lately, so it's time clean to up this TA.
I will leave a recommendation in the CleanUp topic area:
[Accept Smallint's comment as answer]
Please leave any comments here within the next seven days.

Visit the URL if u require help on closing the question.
https://www.experts-exchange.com/help/closing.jsp

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

srimanth
EE CV