hello eveyrbody

i make a dll in asm and use it in vb. but vb gives errors like "bad dll calling convention" how to solve this. i tried lot but no work.

thank

salad.dressing
Posted on 2003-11-25 18:00:36 by salad.dressing
Hi salad.dressing :)
Without more information there's not much I can do, but IMHO the problem could be either that:
1) You're not specifying that the function is in a DLL.
2) You're not using ByVal when needed.
since this are the two most common problems, it seems.
I have not tried it yet (don't have at VB home) but something like this might work:
Private Declare Function MyMasmFunction Lib "MyMasmLibrary.dll" (ByVal FirstParam As Single) 

As Single
Private Declare Sub MyMasmSub Lib "MyMasmLibrary.dll" (ByVal ThisIsAValue As Single, ThisIsAPointer As Single)

I have assumed parameters of type "Single", I think this is the same as REAL4 under MASM. (I didn't recall the names of the other types :grin: ).
Hope it helps! ;)

PS: You might want to ask Ranma_at, he surely knows better than me.
Posted on 2003-11-25 18:15:50 by QvasiModo
hi

ok here some more info

a sample func in asm is GetWindowsVersion to make job easi in vb

it not paramaeters and rets dword

be4 i tri to use art's info decoratin to export funcs and can call from other asms, but gives me vb that error.

i dclare it both try but no work



Private Declare Function GetWindowsVersion Lib "mydll.dll" Alias "_GetWindowsVersion@0" () As Long

or

Private Declare Function GetWindowsVersion Lib "mydll.dll" () As Long


what wrong with it, i new to vb too.

salad
Posted on 2003-11-26 01:53:07 by salad.dressing
what tha

how can vb call stuff from asm
i never knew that

cooooooooollll

:grin:
blabla
Posted on 2003-11-26 03:54:27 by dickhead
well i got some c++ stuff for you if you care

from somewhere on the web:


Purpose
Use VC++ to create a DLL file. Use the DLL functions from Visual Basic.

Method

I have found 2 methods to do this. The first makes the VC++ easier and
the Visual Basic messier. The second makes the VC++ harder and the Visual
Basic easier.

Method 1
1. Use the menus: New\Projects\Win32 Dynamic-Link Library. Enter the directory
where you want the VC++ project and the project name (MyFuncsProject in the
example).

2. New\Files\C++ Source File. Check the Add To Project box. Enter the file name
(MyFuncs.cpp in the example).

3. Enter the function's source code. Use __declspec to export the function's
symbol. Use 'extern "C"' to minimize name mangling by VC++.

// Define DllExport to declare exported symbols.
#define DllExport __declspec( dllexport )

// Prototype the function.
// Use 'extern "C"' to minimize name mangling.
extern "C" DllExport long MyCFunc(long x);

// Define the function.
extern "C" DllExport long MyCFunc(long x)
{
return x * x;
}

4. Set project options using Project\Settings. On the C/C++ tab, select the
Code Generation category. Then change Calling Convention to __stdcall.

5. Select Build\Set Active Configuration. Select the Release configuration.
Repeat step 4 to make the options apply to the release configuration in addition
to the debug configuration. Use Build\Set Active Configuration to reselect the
debug configuration if desired.

6. Build the project (press F7 or use the Build menu). This creates the
DLL file.

7. In your Visual Basic program, declare the DLL function using the DLL file's
full path name. The function's name in the DLL file has been slightly mangled by
VC++. The name is an underscore, followed by the name you gave it, followed by
"@", followed by the number of bytes in the function's argument list. In this
example the name is _MyCFunc@4 because the function takes one 4 byte argument
(a long integer).

Private Declare Function MyCFunc Lib _
"C:\VBHelper\VcDll\Method1\Release\MyFuncsProject.dll" _
Alias "_MyCFunc@4" _
(ByVal x As Long) As Long

Private Sub Command1_Click()
Dim x As Long
Dim y As Long

x = CInt(Text1.Text)
y = MyCFunc(x)
Label1.Caption = Str$(y)
End Sub

*** HINT: To quickly determine the mangled name of the function, find the DLL
file in Windows Explorer. Right click on the file and select the "Quick View"
command. This presents an editor showing information about the DLL. Page down 2
or 3 pages and you will find a list of exported symbols available in the DLL.
One of these will be the mangled function name.

8. Run the program.

Method 2

1-5. Same as in Method 1.

6. New\Text File. Check the Add To Project box. Enter the file name. Give it
a .DEF extension (MyFuncs.def in the example).

7. Enter definition file information that tells VC++ to export the function with
the mangled name using the name you want it to have.

EXPORTS
MyCFunc=_MyCFunc@4

This makes the exported name MyCFunc equivalent to _MyCFunc@4.

8. Build the project (press F7 or use the Build menu). This creates the
DLL file.

*** HINT: Use Quick View to verify the exported names. Find the DLL file in
Windows Explorer. Right click on the file and select the "Quick View" command.
Page down 2 or 3 pages and you will find a list of exported symbols available
in the DLL. This includes both the mangled name and the name you specified in
the .DEF file.

9. In your Visual Basic program, declare the DLL function using the DLL file's
full path name. Use the name you placed in the .DEF file not the mangled name.

Private Declare Function MyCFunc Lib _
"C:\VBHelper\VcDll\Method2\Release\MyFuncsProject.dll" _
(ByVal x As Long) As Long

Private Sub Command1_Click()
Dim x As Long
Dim y As Long

x = CInt(Text1.Text)
y = MyCFunc(x)
Label1.Caption = Str$(y)
End Sub


:grin:
blabla
Posted on 2003-11-26 06:16:30 by dickhead
You need to create a def file when you compile your dll. MASM by default decorates (mangles) all exported function names, making it difficult to call them from VB. Also, you need to pass your parameters correctly, otherwise you will cause GPFs.
For more information on passing parameters from VB to asm, check my posts in this thread.
Posted on 2003-11-26 06:23:14 by sluggy
None of these replies have anything to do with your problem.

I do the same and have been for many years - the problem is Windows uses the ESI , EDI , EDX , EBI registers.
If you use these registers without saving the original values Windows gets upset when you return to VB and hence the Bad DLL Calling Convention.

Push the registers you use at the beginning of the DLL routine and just before the Ret pop them all - that will cure your problem.
Posted on 2003-11-26 18:51:45 by s1cjet

None of these replies have anything to do with your problem.

:o we're ASM people here, not VB... :grin:

I do the same and have been for many years - the problem is Windows uses the ESI , EDI , EDX , EBI registers.
If you use these registers without saving the original values Windows gets upset when you return to VB and hence the Bad DLL Calling Convention.

Push the registers you use at the beginning of the DLL routine and just before the Ret pop them all - that will cure your problem.

Good to know. :)
Might also be worth mentioning that this is the equivalent to pushing/popping:
MyFunc proc uses ebx esi edi MyParam:dword   ;etc...
Posted on 2003-11-26 19:07:33 by QvasiModo
In my previous message I mentioned the EBI register it should have read the EBX register.
If you can write assy DLLs' why don't you throw your VB in the bin and start writing win32 apps in Assy. It's not as difficult as it looks - you just need to be more organised with your programming.

If anyone is interested i'm starting to develop a Visual Assembler type app. and am looking for people who are interested in testing and giving me their feed back - naturally the project will be a freeware application. The project is well underway and I have looked at other programs of this nature (there are very few). The intention is to write an app that is open ended so that even after I have completed it users can still add to via DLL, Libraries etc etc.

If you are interested get in touch.
Posted on 2003-11-26 19:27:10 by s1cjet
hi salad.dressing,

s1cjet is right here. you need to save those registers to the stack as QuasiModo's done above.

s1cjet:
sure, let me know when you need help, i'm often available.

Regards,
Art
Posted on 2003-11-26 19:37:46 by art_sands
To automatically save registers to the stack when calling a routine do the following:

My_Subroutine PROC USES ESI EDI EDX EBX {list of parameters if any}

assy code in here

RET
My_Subroutine ENDP

When the RET is encountered the registers are automatically popped from the stack.
Posted on 2003-11-26 19:52:14 by s1cjet
there's another thing which i was tinkering with and may not be as useful to you. but i just wanted to share it.

you can export functions from dlls without using .def files.

use this as a template:



MyFunc PROC [export] [uses ...] [params]
; code goes here.
ret
MyFunc ENDP


This allows users of your dll to determine the number of parameters that your function needs without any need for documentation. of course, thats only if you use DWORDs as params.

But that also adds some overhead to VB code.

You'll have to declare functions and subs including the mangled names like this:



; for
int MyFunc( int );
Private Declare Function MyFunc Lib "mydll.dll" Alias "_MyFunc@4" () As Long


But don't worry there's another way for users to avoid that. While you can export functions from asm, you can also use alternate definitions by including a .def file with definitions like:



LIBRARY mydll
EXPORTS
MyFunc=_MyFunc@4


Dump this and you'll find both MyFunc and _MyFunc@4 being exported as separate entities but pointing to the same thing.

Regards,
Art
Posted on 2003-11-26 20:01:35 by art_sands
Isn't this thread a great candidate to be in the FAQ? :grin:
Posted on 2003-11-26 20:15:28 by QvasiModo
yeah QvasiModo

actually, i plan on adding this to the wiki book.

Regards,
Art
Posted on 2003-11-26 20:19:13 by art_sands
wov

so nany result. i m happy. that solv my problem. thank you.

salad.dressing
Posted on 2003-11-27 03:15:08 by salad.dressing

None of these replies have anything to do with your problem.

I do the same and have been for many years - the problem is Windows uses the ESI , EDI , EDX , EBI registers.
If you use these registers without saving the original values Windows gets upset when you return to VB and hence the Bad DLL Calling Convention.

Push the registers you use at the beginning of the DLL routine and just before the Ret pop them all - that will cure your problem.

<polite cough>Bullshit!</polite cough>
ESI, EDI and EDX do not need to be preserved when calling asm from VB (trust me, i have software that i wrote operating in large firms that proves this). And not preserving EBX does NOT give you a Bad DLL calling convention, that error message is caused by having the VB declares incompatible with the asm function signature.

s1cjet, you obviously have not been programming with VB for very long.

Everybody else:
this subject has been discussed thoroughly well before now, try doing a search to find those threads like the one i mentioned in my previous post. In one of them i go into quite some detail on what happens when you pass parameters from VB (which is based on COM) to asm.
Posted on 2003-11-27 07:05:33 by sluggy
<polite cough>Bullshit!</polite cough> ESI, EDI and EDX do not need to be preserved when calling asm from VB (trust me, i have software that i wrote operating in large firms that proves this). And not preserving EBX does NOT give you a Bad DLL calling convention, that error message is caused by having the VB declares incompatible with the asm function signature. s1cjet, you obviously have not been programming with VB for very long. Everybody else: this subject has been discussed thoroughly well before now, try doing a search to find those threads like the one i mentioned in my previous post. In one of them i go into quite some detail on what happens when you pass parameters from VB (which is based on COM) to asm.


Well, hi there sluggy,

s1cjet is correct. I was havin the same problem some time back, and i accidentally came to know about this. I've tested this on my pc, and posted only after verifying it correctly. The material you've written is excellent though hope to learn from it too.

Use this



GetWindowsVersion PROC uses esi edx edi
; edx = dwVersion
; esi = dwMajorVersion
; edi = dwMinorVersion

invoke GetVersion
mov edx, eax
invoke _loword, eax
mov edi, eax
invoke _lobyte, eax
mov esi, eax
invoke _hibyte, edi
mov edi, eax


.IF edx < 80000000h
; Microsoft Windows NT family
.IF esi == 3
mov eax, WVER_WINNT351
.ELSEIF esi == 4
mov eax, WVER_WINNT4
.ELSEIF esi == 5 && edi == 0
mov eax, WVER_WIN2000
.ELSEIF esi == 5 && edi == 1
mov eax, WVER_WINXP
.ELSEIF esi == 5 && edi == 2
mov eax, WVER_WINSERVER2003
.ENDIF
.ELSEIF esi < 4
; Microsoft Win32s
mov eax, WVER_WIN32s
.ELSEIF esi == 4
; Microsoft Windows 95/98/Me
.IF edi == 0
mov eax, WVER_WIN95
.ELSEIF edi == 10
mov eax, WVER_WIN98
.ELSEIF edi == 90
mov eax, WVER_WINME
.ENDIF

.ELSE

; Unknown
mov eax, WVER_UNKNOWN
.ENDIF
ret
GetWindowsVersion ENDP


in a dll and call it from vb it should work.


But this:



GetWindowsVersion PROC
; edx = dwVersion
; esi = dwMajorVersion
; edi = dwMinorVersion

invoke GetVersion
mov edx, eax
invoke _loword, eax
mov edi, eax
invoke _lobyte, eax
mov esi, eax
invoke _hibyte, edi
mov edi, eax


.IF edx < 80000000h
; Microsoft Windows NT family
.IF esi == 3
mov eax, WVER_WINNT351
.ELSEIF esi == 4
mov eax, WVER_WINNT4
.ELSEIF esi == 5 && edi == 0
mov eax, WVER_WIN2000
.ELSEIF esi == 5 && edi == 1
mov eax, WVER_WINXP
.ELSEIF esi == 5 && edi == 2
mov eax, WVER_WINSERVER2003
.ENDIF
.ELSEIF esi < 4
; Microsoft Win32s
mov eax, WVER_WIN32s
.ELSEIF esi == 4
; Microsoft Windows 95/98/Me
.IF edi == 0
mov eax, WVER_WIN95
.ELSEIF edi == 10
mov eax, WVER_WIN98
.ELSEIF edi == 90
mov eax, WVER_WINME
.ENDIF

.ELSE

; Unknown
mov eax, WVER_UNKNOWN
.ENDIF
ret
GetWindowsVersion ENDP


doesn't surprisingly.
Regards,
Art
Posted on 2003-11-27 07:13:02 by art_sands
Sluggy,
i've been writing software for 20 years - started when i was 16 am now 36 and i've been writing commercial software for the UKs oldest and greatest software house all that time - please don't assume you know my lifes history just from one message.

before you go around telling people something is wrong please ask a few others - Windows DOES use the following registers ESI EDI EBP EBX - it doesn't matter if you are writing an EXE, DLL, Library , COM, Object or something you would like inserted up your rectum it still uses those registers. There are plenty of tutorials around which describe fairly well what I - and everyone who wrote the last few messages - already seem to know about this.
I'm starting to wonder if you know what assy or VB is !!!
Posted on 2003-11-27 07:18:10 by s1cjet
Those registers should be preserved because windows uses them...

But I think that the Bad Calling convention it's about the parameter passing method.

__stdcall vs __cdecl

My two cents.



:alright:
Posted on 2003-11-27 11:10:39 by Eternal Idol Birmingham
It is better to use the TLB files when calling dll functions from VB. This method removes the overhead otherwise associated with VB when dll functions are explicitly declared. This method directly calls the function without any error checking. I have given sample below. Use the midl.exe tool to compile the .idl file to TLB file.
[ 

uuid(79AA19C1-212F-11d8-8CEE-E40CB528DE05),
helpstring("My Test Dll")
]

library DllLib
{
typedef struct MyDllStruct {
long param1;
long param2;
long param3;
long param4;
} MyDllStruct;


[dllname("Mydll.dll")]
module MyDllTest
{
[helpstring("Function1"), entry("TestFunction")] HRESULT TestFunction([in] long val1,[in] long val2 ,[in] MyDllStruct *pStruct);
};
}


More information can be found in MSDN.
Posted on 2003-11-27 11:30:11 by Pradeepan