Here is a quick example :
#include <windows.h>
#include <stdio.h>
int main(int argc,char *argv[])
{
HMODULE hModule;
// define the function pointer to call the function #2
int __stdcall (*Sum)(int,int);
hModule=LoadLibrary("DllDemo.dll");
// Get the address of the function identified by ordinal number 2
Sum=(void *)GetProcAddress(hModule,MAKEINTRESOURCE(2));
// Simple test
printf("90 + 10 = %d",Sum(90,10));
FreeLibrary(hModule);
return 0;
}
DllDemo.def :
LIBRARY DllDemo
EXPORTS
Difference @1 NONAME
Sum @2 NONAME
Multiply @3 NONAME
Square @4 NONAME
Thank you Erol for the instructive example. Will that work with other compilers, too?
Gunther
Hi Gunther,
Second version built with Microsoft Visual C++ Toolkit 2003 and Server 2003 R2 PSDK. The only difference is the declaration of the function pointer :
int (__stdcall *Sum)(int,int);
:t Is clear now.
Gunther
After changing the function declaration and renaming dllmain.c to dlldemo.c, and building with the VC++ Toolkit 2003 compiler and this batch file:
set PATH=C:\Program Files\Microsoft Visual C++ Toolkit 2003\bin;%PATH%
set INCLUDE=C:\Program Files\Microsoft Platform SDK\include;C:\Program Files\Microsoft Visual C++ Toolkit 2003\include;%INCLUDE%
set LIB=C:\Program Files\Microsoft Platform SDK\lib;C:\Program Files\Microsoft Visual C++ Toolkit 2003\lib;C:\masm32\lib;%LIB%
cl /W3 /FA /c dlldemo.c
pause
link /DLL /DEF:dlldemo.def dlldemo.obj
pause
cl /W3 /FA CallByOrdinal.c DllDemo.lib
pause
The assembly output shows that the exported functions are using cdecl:
; Listing generated by Microsoft (R) Optimizing Compiler Version 13.10.3077
TITLE dlldemo.c
.386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS ENDS
$$SYMBOLS SEGMENT BYTE USE32 'DEBSYM'
$$SYMBOLS ENDS
_TLS SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS ENDS
FLAT GROUP _DATA, CONST, _BSS
ASSUME CS: FLAT, DS: FLAT, SS: FLAT
endif
INCLUDELIB LIBC
INCLUDELIB OLDNAMES
PUBLIC _DllMain@12
; Function compile flags: /Odt
_TEXT SEGMENT
_hInstDLL$ = 8 ; size = 4
_fdwReason$ = 12 ; size = 4
_lpvReserved$ = 16 ; size = 4
_DllMain@12 PROC NEAR
; File c:\program files\microsoft visual c++ toolkit 2003\my\vortex\callbyordinal\dlldemo.c
; Line 5
push ebp
mov ebp, esp
; Line 6
mov eax, 1
; Line 7
pop ebp
ret 12 ; 0000000cH
_DllMain@12 ENDP
_TEXT ENDS
PUBLIC _Sum
; Function compile flags: /Odt
_TEXT SEGMENT
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_Sum PROC NEAR
; Line 10
push ebp
mov ebp, esp
; Line 11
mov eax, DWORD PTR _a$[ebp]
add eax, DWORD PTR _b$[ebp]
; Line 12
pop ebp
ret 0
_Sum ENDP
_TEXT ENDS
PUBLIC _Difference
; Function compile flags: /Odt
_TEXT SEGMENT
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_Difference PROC NEAR
; Line 15
push ebp
mov ebp, esp
; Line 16
mov eax, DWORD PTR _a$[ebp]
sub eax, DWORD PTR _b$[ebp]
; Line 17
pop ebp
ret 0
_Difference ENDP
_TEXT ENDS
PUBLIC _Multiply
; Function compile flags: /Odt
_TEXT SEGMENT
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_Multiply PROC NEAR
; Line 20
push ebp
mov ebp, esp
; Line 21
mov eax, DWORD PTR _a$[ebp]
imul eax, DWORD PTR _b$[ebp]
; Line 22
pop ebp
ret 0
_Multiply ENDP
_TEXT ENDS
PUBLIC _Square
; Function compile flags: /Odt
_TEXT SEGMENT
_a$ = 8 ; size = 4
_Square PROC NEAR
; Line 25
push ebp
mov ebp, esp
; Line 26
mov eax, DWORD PTR _a$[ebp]
imul eax, DWORD PTR _a$[ebp]
; Line 27
pop ebp
ret 0
_Square ENDP
_TEXT ENDS
PUBLIC _func
; Function compile flags: /Odt
_TEXT SEGMENT
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_func PROC NEAR
; Line 30
push ebp
mov ebp, esp
; Line 31
mov eax, DWORD PTR _a$[ebp]
mov ecx, DWORD PTR _b$[ebp]
lea eax, DWORD PTR [ecx+eax*2]
; Line 32
pop ebp
ret 0
_func ENDP
_TEXT ENDS
END
Is there a way to link with the import library and call a function by ordinal, without GetProcAddress?
Nice example, Erol :t
Here is the assembler equivalent - requires version 7 June or later (http://masm32.com/board/index.php?topic=94.0) ;)
include \masm32\MasmBasic\MasmBasic.inc
Init
Dll "DllDemo.dll"
Declare #2=TheSum, 2
Inkey Str$("90+10=%i", TheSum(90, 10))
Exit
end start(actually, when trying this, it choked; the VB style ordinal option has been included a long time ago, but I've never used it, and a regression crept in :(... but now it works)
Note you can use any alias name, like MySum etc; if you try TheSum(90, 10, 123) or The Sum(90), the macro will throw an assembly time error message explaining that TheSum expects exactly 2 parameters.
Quote from: MichaelW on June 07, 2014, 09:41:10 PM
The assembly output shows that the exported functions are using cdecl
The DemoDll.dll in Erol's attachment uses stdcall. If it was cdecl, the syntax above would change to Declare #2=TheSum,
C:2
Hi Jochen,
Thanks for your kind words. By the way, my fault was not specify the correct calling convention __stdcall. I corrected this:
#ifndef WINAPI
#define WINAPI __stdcall
#endif
.
.
.
int WINAPI Sum(int a, int b)
{
return a+b;
}
No need of GetProcAddress now :
extern int __stdcall Sum(int x,int y);
int main(int argc,char *argv[])
{
printf("90 + 10 = %d",Sum(90,10));
return 0;
}
New upload at the top.