Створення бібліотеки за допомогою MASM
;бібліотечний файл mydll_asm.asm
; DLL містить функцію для перекодування числа в текст
.386
.model flat
; Оголошуємо власну API функцію використовуючи узгодження stdcall.
; Всі API функції використовують узгодження stdcall
public _num2txt@4
.data
; Змінна mystr містить буфер для конвертованого рядку тексту
mystr db 2 dup(0)
.code
; DLL файл має точку входу, яка приймає три 4 байтні параметри:
; 1) ідентифікатор; 2) причину виклику; 3) зарезервований параметр.
; Ми їх не використовуємо, тому просто повертаємо ненульове значення через регістр EAX
; і очищуємо стек.
_start@12:
mov eax,1
ret 12
; наша процедура
_num2txt@4 proc
; виймаємо з стеку і зберігаємо точку повернення в есх
pop ecx
; виймаємо з стеку і зберігаємо єдиний параметр функції в edx
pop edx
; повертаємо в стек точку повернення з есх
push ecx

; здійснюємо приведення значення десяткового числа до його еквіваленту в форматі ASCII
add edx,48
; зберігаємо результат в змінній mystr попередньо занісши її адресу в eax
mov eax, offset mystr
mov [eax],dl
; оскільки параметр функції вже вийняли зі стеку, то очищати стек не потрібно
ret
_num2txt@4 endp

end _start@12
----------------------------------------------------------------------------------------------------------
; в файлі mydll.def треба написати всі назви функцій, що є в dll
LIBRARY mydll_asm
EXPORTS num2txt
-----------------------------------------------------------------------------------------------------------
; bat файл, що здійснюватиме створення dll: makeit_dll.bat
@echo off
if exist mydll_asm.obj del mydll_asm.obj
if exist mydll_asm.dll del mydll_asm.dll
\masm32\bin\ml /c /coff mydll_asm.asm
\masm32\bin\Link /SUBSYSTEM:WINDOWS /DLL /DEF: mydll_asm.def mydll_asm.obj
;del mydll_asm.obj
;del mydll_asm.exp
dir mydll_asm.*
pause
Програма, що викликає функцію з створеної бібліотеки (MASM)
; Програма для тестування calldll.asm. Використовується неявне зв’язування.
.386
.model flat
; Додаємо необхідні бібліотеки, в тому числі і створену власноруч.
; В процесі компіляції з використанням неявного зв’язування
; наявність dll файла не є необхідною,
; але є необхідною при виконанні програми.
; Це стосується програм написаних на С, С++ і асемблері
includelib mydll_asm.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
; Оголошуємо функції, які використовуємо
; в фотрматі:
; ключове слово extrn
; префікс __imp_
; назва функції _num2txt
; кількість даних, які передаються в стек у байтах @4 (1 параметр в даному випадку)
; :dword
extrn __imp__num2txt@4:dword
; Оголошуємо API функцію MessageBoxA, що приймає параметри в кодуванні ASCII
extrn __imp__MessageBoxA@16:dword
MessageBox equ __imp__MessageBoxA@16
; Оголошуємо API функцію ExitProcess, що завершує виконання прграми
extrn __imp__ExitProcess@4:dword
ExitProcess equ __imp__ExitProcess@4
.data
mess_title db 'Number to string',0
.code
_start:
; Конвертуємо число 2 в строку викликавши функцію _num2txt з dll
push 2
call __imp__num2txt@4

; Виводимо результат конвертації
push 40h
push offset mess_title
push eax
push 0
call MessageBox

; Завершуємо виконання програми
push 0
call ExitProcess
end _start
------------------------------------------------------------------------------------------------------------
; bat файл, що здійснюватиме створення тестової програми makeit_exe.bat
@echo off
if exist calldll.obj del calldll.obj
if exist calldll.exe del calldll.exe
\masm32\bin\ml /c /coff calldll.asm
\masm32\bin\Link /SUBSYSTEM:WINDOWS calldll.obj
del calldll.obj
dir mydll.*
pause
--------------------------------------------------------------------

Рис.1. Результат виконання програми.
Створення бібліотеки за допомогою MSVS 2005
// Для створення dll вибрати тип проекту “DLL”
// Файл my_dll.h. Містить прототип функції бібліотеки
char mystr[2] = {0};

// Необхідно експортувати С інтерфейс
extern "C" __declspec(dllexport) char* num2txt(int n);
--------------------------------------------------------------------------------------------------------
// Файл my_dll.cpp. Містить функцію бібліотеки
#include "my_dll.h"
extern "C" __declspec(dllexport) char* num2txt(int n)
{
mystr[0] = n + 48;
return mystr;
}
/*
використання __declspec(dllexport) дозволяє нам не створювати файл mydll.def, оскільки вмістиме цього файлу включається в бібліотеку. __declspec(dllexport) створює файли в форматі «С++». Якщо такий формат не є бажаним, то необхідно створити файл *.def самостійно, або використати extern "C" в оголошені функції.
*/
Програма, що викликає функцію з створеної бібліотеки (MSVS).
Неявне зв’язування
// Використовується тип проекту “Windows Application”
// Файл my_dll.h. Містить прототип функції бібліотеки
char mystr[2] = {0};

// Необхідно експортувати С інтерфейс
extern "C" __declspec(dllexport) char* num2txt(int n);
-----------------------------------------------------------------------------------------------------
// Файл neyavno.cpp.
#include <Windows.h>
#include "my_dll.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR lpCmdLine, int nCmdShow)
{
char mess_title[] = "Number to string";
char * pszStr;
pszStr = num2txt(2);
MessageBoxA(0, pszStr, mess_title, 0x40);
ExitProcess(0);
}
--------------------------------------------------------------------
Програма, що викликає функцію з створеної бібліотеки (MSVS)
Неявне зв’язування. Використання __declspec( dllimport )
#include <Windows.h>
extern "C" __declspec(dllimport) char* num2txt(int n);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR lpCmdLine, int nCmdShow)
{
char mess_title[] = "Number to string";
char * pszStr;
pszStr = num2txt(2);
MessageBoxA(0, pszStr, mess_title, 0x40);
ExitProcess(0);
}
--------------------------------------------------------------------
__declspec( dllimport )
__declspec( dllimport ) використовується лише разом з функціями і вказує на те, що дана функція оголошена в бібліотеці. Таке оголошення дозволяє не генерувати thunk "перехідник" (невелику секцію коду, що виконує перетворення (наприклад, типів) чи забезпечує виклик 32-розрядного коду з 16-розрядного і навпаки). При цьому відбувається пришвидшення виконання програми (див. MSDN). __declspec( dllimport ) заборонено використовувати при створенні функції в бібліотеці, використовується лише при її виклику.
Без __declspec( dllimport ) компілятор генерує код:
int main(void)
{
func1();
}
наступним чином:
call func1
і лінкер генерує такий код:
call 0x4000000 ; Адреса 'func1'

Якщо лінкер не знає адреси функції, яка є в dll, тоді генерується помилка. В 32 розрядному середовищі лінкер згенерує наступний «перехідник» для виклику функції:
0x40000000: jmp DWORD PTR __imp_func1
З використанням __declspec( dllimport ) компілятор генерує код:
__declspec(dllimport) void func1(void);
int main(void)
{
func1();
}
наступним чином:
call DWORD PTR __imp_func1
В цьому коді відсутній «перехідник», що дозволяє пришвидшити виконання програми
Програма, що викликає функцію з створеної бібліотеки (MSVS)
Явне зв’язування.
/*
Програма здійснює виклик функції num2txt, що знаходиться в бібліотеках, що створені в MASM і MSVS2005. Код, що працює з написаним в MASM має суфікс _asm.
*/
#include <Windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR lpCmdLine, int nCmdShow)
{
//оголошення вказівників на функції
// функція написана в MSVS використовує узгодження __cdecl
char* (__cdecl* num2txt)(int);
// функція написана в MASM використовує узгодження __stdcall або WINAPI
// WINAPI має таке оголошення в windef.h
// #define WINAPI __stdcall
char* (WINAPI* num2txt_asm)(int);
char mess_title[] = "Number to string";
char * pszStr;
//завантажити бібліотеку
HINSTANCE hLib=LoadLibrary("my_dll.DLL");
HINSTANCE hLib_asm=LoadLibrary("mydll_asm.DLL");
//якщо бібліотека не завантажена, то вивести повідомлення і вийти
if(!hLib || !hLib_asm)
{
MessageBoxA(0, "Cannot load dll", "Error", 0x40);
ExitProcess(0);
}
// завантажити адресу функції з іменем "num2txt"
num2txt = (char *(__cdecl*)(int))GetProcAddress((HMODULE)hLib, "num2txt");
num2txt_asm = (char *(__stdcall*)(int))GetProcAddress((HMODULE)hLib_asm, "num2txt");
// перевірити чи функції завантажено
if (num2txt)
{
pszStr = num2txt(5);
MessageBoxA(0, pszStr, mess_title, 0x40);
}
else
MessageBoxA(0,"Error loading function", "Error", MB_OK);
if (num2txt_asm)
{
pszStr = num2txt(3);
MessageBoxA(0, pszStr, mess_title, 0x40);
}
else
MessageBoxA(0,"Error loading function", "Error", MB_OK);

// вивантажити бібліотеки
FreeLibrary((HMODULE)hLib);
FreeLibrary((HMODULE)hLib_asm);
//завершити виконання
ExitProcess(0);
}