|
Introduction - Qu'est-ce que TCC ?
TCC - Tiny C Compiler est un compilateur C extrêmement petit (moins de 1 Mo), mais très rapide en compilation (plus d'un million de lignes par seconde). TCC est simpliste, mais a le gros avantage de permettre une programmation directe. Pas d'installation, il suffit de copier un dossier. Pour écrire un programme, un éditeur de texte suffit, et la mise en route est immédiate, pour une programmation quasi-instantanée. Pas de projet à définir, pas de dépendances, pas de foisonnement d'outils variés et différents, pas d'atomisation du code-source.
Historique. Au départ, Fabrice Bellard a créé OTCC pour concourir à l'IOCCC (http://fr.wikipedia.org/wiki/International_Obfuscated_C_Code_Contest), qu'il a gagné en 2002. Il a ensuite "dé-obsfucated" OTCC, ce qui a donné TCC.
Quelques liens :
Mon intérêt à TCC est très limité, car je ne connais pas le langage C. J'en sais juste assez pour comprendre ce que j'ai fait. Mais, cela a un avantage : ce ne sont que des trucs simples.
Le but de cette page sur TCC est de retransmettre les quelques trouvailles que j'ai faites avec TCC sous Windows, afin d'éviter à d'autres de perdre du temps en investigations pas troujours très faciles. Des façons de faire, pour créer des DLL ou utiliser des ressources Windows, ne sont pas toujours simples à trouver.
Les exemples sont bruts, presque sans commentaires, mais assez simples à comprendre pour être utilisables par tout programmeur qui connait un minimum Windows.

1er programme - comment compiler
Voici le code-source (fichier p1.c) :
#include <stdio.h>
void main() { printf("Bonjour, Monde !\n"); }
Pour le compiler, utiliser cette commande :
tcc -o p1.exe p1.c
Vous obtiendrez le fichier p1.exe, parfaitement exécutable. Voilà, vous avez créé votre premier programme avec TCC.

Ligne de commande - retrouver les arguments
Voici le code-source (fichier p2.c) :
#include <stdio.h>
void main(int argc, char*argv[]) { int i; printf("Nb: %d\n",argc); for(i=0 ; i<argc ; i++){ printf("Arg.num.%d : %s \n", i, argv[i]); } }
Le compiler avec cette commande :
tcc -o p2.exe p2.c
Lancer ensuite p2.exe aaa 123 "ABC ZZZ" ; vous devriez voir les paramètres récupérés par le programme.

Windows
Notre première fenêtre sous Windows (fichier p3.c) :
#include <windows.h>
const char g_szClassName[] = "maclasswin";
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CLOSE: MessageBox(NULL,"Demande de fermeture de la fenêtre.","Message Windows",MB_ICONEXCLAMATION | MB_OK); DestroyWindow(hwnd); break;
case WM_DESTROY: PostQuitMessage(0); break;
default: return DefWindowProc(hwnd, msg, wParam, lParam); break; //à cause de certains antivirus... } return 0; }
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wc; HWND hwnd; MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = NULL; wc.lpszClassName = g_szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if(!RegisterClassEx(&wc)) { MessageBox(NULL, "Pb d'enregistrement de la fenêtre", "Erreur", MB_ICONEXCLAMATION | MB_OK); return 0; }
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, g_szClassName, "Ma première fenêtre", //titre WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 320, //largeur 200, //hauteur NULL, NULL, hInstance, NULL);
if(hwnd == NULL) { MessageBox(NULL, "Pb de création de la fenêtre", "Erreur", MB_ICONEXCLAMATION | MB_OK); return 0; }
ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd);
while(GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); }
return Msg.wParam; }
Compiler avec cette commande :
tcc -o p3.exe p3.c
Alors, non seulement ce programme crée une fenêtre, mais il intercepte aussi la fermeture de la fenêtre (un message est affiché).

Ressources
Je n'ai jamais apprécié l'histoire des ressources, avec des fichiers séparés. Cela se traduit par une atomisation des code-sources, et une multiplicité des traitements péri-compilation (compilation de ressources, éditeur de liens, intégration des ressources à l'exécutable, etc.). De plus TCC s'intègre très mal avec les éditeurs et compilateurs de ressources classiques, comme ceux de Microsoft ou de Borland.
Heureusement, il existe une possibilité, que nous allons mettre en oeuvre dans un exemple. Il s'agit d'utiliser le compilateur de ressources de MinGW. Pour cela, il faut récupérer, dans une installation MinGW, les programmes (fichiers) suivants :
- cc1.exe
- gcc.exe
- windres.exe
Nous allons définir (utiliser) les ressources suivantes :
- Un icone, fichier "ponx.ico", qui DOIT être présent dans le dossier en cours.
- Un menu, organisé comme ça :
Fichier Terminer Divers Aller Aller ailleurs (ligne grisée) 3ème ligne
L'ensemble des codes-source est composé de trois fichiers : p4.h p4.rc p4.c :
(fichier p4.h) Il contient les constantes identifiant les éléments des ressources :
#define ID_MONICON 201 #define ID_MONMENU 101 #define ID_TERMINER 9001 #define ID_ALLER 9002 #define ID_3 9003
(fichier p4.rc) Il contient la définition des ressources :
#include "p4.h"
ID_MONMENU MENU BEGIN POPUP "&Fichier" BEGIN MENUITEM "&Terminer", ID_TERMINER END
POPUP "&Divers" BEGIN MENUITEM "&Aller", ID_ALLER MENUITEM "A&ller ailleurs", 0, GRAYED MENUITEM "3ème ligne", ID_3 END END
ID_MONICON ICON "ponx.ico"
Le fichier source en langage C (fichier p4.c) :
#include <windows.h> #include "p4.h"
const char g_szClassName[] = "maClasseWin";
HBITMAP g_hbmBall = NULL;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_COMMAND: switch(LOWORD(wParam)) { case ID_TERMINER: MessageBox(hwnd, "la ligne de menu 'Terminer'", "Vous avez sélectionné", MB_OK | MB_ICONINFORMATION); DestroyWindow(hwnd); break;
case ID_ALLER: MessageBox(hwnd, "la ligne de menu 'Aller'", "Vous avez sélectionné", MB_OK | MB_ICONINFORMATION); break;
case ID_3: MessageBox(hwnd, "la ligne de menu '3ème ligne'", "Vous avez sélectionné", MB_OK | MB_ICONINFORMATION); break; } break;
case WM_LBUTTONDOWN: { char szFileName[MAX_PATH]; HINSTANCE hInstance = GetModuleHandle(NULL);
GetModuleFileName(hInstance, szFileName, MAX_PATH); MessageBox(hwnd, szFileName, "Clic gauche dans :", MB_OK | MB_ICONINFORMATION); } break;
case WM_RBUTTONDOWN: { char szFileName[MAX_PATH]; HINSTANCE hInstance = GetModuleHandle(NULL);
GetModuleFileName(hInstance, szFileName, MAX_PATH); MessageBox(hwnd, szFileName, "Clic droit dans :", MB_OK | MB_ICONINFORMATION); } break;
case WM_CLOSE: DestroyWindow(hwnd); break;
case WM_DESTROY: DeleteObject(g_hbmBall); PostQuitMessage(0); break;
default: return DefWindowProc(hwnd, msg, wParam, lParam); break; } return 0; }
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wc; HWND hwnd; MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(ID_MONICON)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = MAKEINTRESOURCE(ID_MONMENU); wc.lpszClassName = g_szClassName; wc.hIconSm = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(ID_MONICON), IMAGE_ICON, 16, 16, 0); if(!RegisterClassEx(&wc)) { MessageBox(NULL, "Pb d'enregistrement de la fenêtre", "Erreur", MB_ICONEXCLAMATION | MB_OK); return 0; }
hwnd = CreateWindowEx( WS_EX_CLIENTEDGE, g_szClassName, "Fenêtre avec un icône et un menu (voir aussi les clics droit et gauche)", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 600, //largeur 280, //hauteur NULL, NULL, hInstance, NULL ); if(hwnd == NULL) { MessageBox(NULL, "Pb de création de la fenêtre", "Erreur", MB_ICONEXCLAMATION | MB_OK); return 0; }
ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd);
while(GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return Msg.wParam; }
Avant de compiler, il faut traiter les ressources. Pour cela, nous allons utiliser la commande :
windres.exe -O coff p4.rc -o p4.o
La compilation elle-même :
tcc p4.c p4.o -o p4.exe
Le programme p4.exe ouvre une fenêtre, avec l'icone associé (qui est maintenant intégré dans le fichier exécutable), et avec le menu prévu. Lorsqu'un utilisateur va sélectionner (cliquer) sur une entrée du menu, l'action sera interceptée, et un message affiché. En supplément gratuit, le programme va aussi intercepter les clics gauches et droits sur la fenêtre. Ceci ne concerne pas les ressources, mais rend l'exemple plus attractif ;-)

Image & GDI
Cet exemple ouvre une fenêtre, charge une image, à partir d'un fichier au format .BMP, et affiche trois textes, de tailles, couleurs et emplacements différents.
Voici le code-source (fichier p5.c) :
#include <windows.h>
const char g_szClassName[] = "maClasseWin"; HBITMAP g_hBMP = NULL; char *pWindowText;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) {
case WM_CREATE: g_hBMP = (HBITMAP)LoadImage(NULL, "tintin.bmp", // nom du fichier IMAGE_BITMAP, // type = bitmap 0, 0, // 0,0 = taille d'origine LR_LOADFROMFILE);
if(g_hBMP == NULL) MessageBox(hwnd, "Pb pour lire tintin.bmp", "Erreur", MB_OK | MB_ICONEXCLAMATION); break;
case WM_PAINT: { PAINTSTRUCT pst; RECT rct; HDC hdc = BeginPaint(hwnd, &pst);
BITMAP bm; HDC hdcMem = CreateCompatibleDC(hdc); HBITMAP hOld = SelectObject(hdcMem, g_hBMP); GetObject(g_hBMP, sizeof(bm), &bm); BitBlt(hdc, 100, 100, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY); SelectObject(hdcMem, hOld); DeleteDC(hdcMem);
//le 36, c'est la taille de la police HFONT hFont = CreateFont (36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, TEXT ("Arial")); hFont = (HFONT) SelectObject (hdc, hFont); GetClientRect(hwnd, &rct); SetTextColor(hdc, RGB(0,0,0)); SetBkColor(hdc, RGB(255,255,255)); // TRANSPARENT); //OPAQUE //TextOut écrit en X,Y char *texte = "Attention !"; TextOut(hdc, 315, 145, texte, strlen(texte)); char *texte = "TCC est"; TextOut(hdc, 330, 190, texte, strlen(texte)); char *texte = "super !"; TextOut(hdc, 345, 230, texte, strlen(texte));
char *texte = "AAAA éè €€ Hello, Monde !"; //le 24, c'est la taille de la police hFont = CreateFont (24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, TEXT ("Arial")); hFont = (HFONT) SelectObject (hdc, hFont); SetTextColor(hdc, RGB(0,20,120)); SetBkColor(hdc, RGB(200,244,244)); //DrawText écrit à patir du début de la fenêtre DrawText(hdc, texte, -1, &rct, 0); //DT_WORDBREAK DT_CENTER|DT_SINGLELINE|DT_VCENTER);
HFONT hFont = CreateFont (24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, TEXT ("Arial")); hFont = (HFONT) SelectObject (hdc, hFont); GetClientRect(hwnd, &rct); SetTextColor(hdc, RGB(180,0,20)); SetBkColor(hdc, RGB(255,200,255)); // TRANSPARENT); //OPAQUE char *texte = " {Echap} pour quitter "; TextOut(hdc, 190, 50, texte, strlen(texte));
EndPaint(hwnd, &pst); } break;
case WM_KEYDOWN: switch(wParam) { case VK_ESCAPE: MessageBox(hwnd, "On quitte", "Echap", MB_OK | MB_ICONINFORMATION); DestroyWindow(hwnd); break; } break;
case WM_CLOSE: DestroyWindow(hwnd); break;
case WM_DESTROY: DeleteObject(g_hBMP); PostQuitMessage(0); break;
default: return DefWindowProc(hwnd, msg, wParam, lParam); break; } return 0; }
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wc; HWND hwnd; MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = NULL; wc.lpszClassName = g_szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if(!RegisterClassEx(&wc)) { MessageBox(NULL, "Pb d'enregistrement de la fenêtre", "Erreur", MB_ICONEXCLAMATION | MB_OK); return 0; }
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, g_szClassName, "Fenêtre avec image (bmp) et textes.", //titre WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, //largeur 580, //hauteur NULL, NULL, hInstance, NULL); if(hwnd == NULL) { MessageBox(NULL, "Pb de création de la fenêtre", "Erreur", MB_ICONEXCLAMATION | MB_OK); return 0; }
ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd);
while(GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return Msg.wParam; }
Pour le compiler, utiliser la commande :
tcc -o p5.exe p5.c
Attention, le fichier tintin.bmp DOIT être présent dans le dossier courant.

Win32API - Utiliser les API de Windows
Si de nombreuses fonctions des API de Windows sont définies en standard (dans Windows.h), certaines font partie de Shell32.DLL (ou d'autres DLL). Et, pour pouvoir utiliser (les fonctions de) cette DLL, il faut se servir de l'outil tiny_impdef.exe. Il permet d'extraire les définitions des fonctions publiques d'une DLL, dans un fichier .def
On l'utilise de cette façon : tiny_impdef.exe C:\Windows\System32\shell32.dll le fichier shell32.def est alors créé (c'est un simple fichier texte). Nous l'utiliserons lors de la compilation.
L'exemple ci-dessous effectue la séquence de traitements suivante :
- Lance le bloc-notes
- Attend 2 secondes
- Lance la calculatrice
- Attend 2 secondes
- Met le bloc-notes au premier-plan
- Déplace la fenêtre (et change la taille)
- Déplace la fenêtre (et change la taille)
- Cache la fenêtre du bloc-notes
- Ré-affiche la fenêtre du bloc-notes
- Change le titre de la fenêtre
- Simule quelques touches du clavier, dans le bloc-notes
- Ouvre le menu "Fichier"
- Envoie "Q" (Quitter)
- Envoie "R" (ne pas enRegistrer)
- Déplace la calculatrice
- Déplace la calculatrice
- Ferme la calculatrice
Voici le code-source (fichier p6.c) :
#include <windows.h> #include <stdio.h>
void t(char tch) { keybd_event((CHAR)(SHORT)VkKeyScan(tch), 0, 0, 0); }
void tcode(int cod) { keybd_event((CHAR)(SHORT)cod, 0, 0, 0); }
void ts(char tch) { //touche avec shift keybd_event( 0x10, 0, KEYEVENTF_EXTENDEDKEY | 0, 0); keybd_event((CHAR)(SHORT)VkKeyScan(tch), 0, 0, 0); keybd_event( 0x10, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); }
void tc(char tch) { //touche avec ctrl keybd_event( 0x11, 0, KEYEVENTF_EXTENDEDKEY | 0, 0); keybd_event((CHAR)(SHORT)VkKeyScan(tch), 0, 0, 0); keybd_event( 0x11, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); }
void ta(char tch) { //touche avec alt keybd_event( 0xA4, 0, KEYEVENTF_EXTENDEDKEY | 0, 0); keybd_event((CHAR)(SHORT)VkKeyScan(tch), 0, 0, 0); keybd_event( 0xA4, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); }
void tacode(int cod) { //code-touche avec alt keybd_event( 0xA4, 0, KEYEVENTF_EXTENDEDKEY | 0, 0); keybd_event((CHAR)(SHORT)cod, 0, 0, 0); keybd_event( 0xA4, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); }
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
// on lance NotePad // la méthode ci-dessous fonctionne, mais pas très bien. // int rh = (int) ShellExecuteA(0,"open","notepad.exe",""," system("start \"\" C:\\Windows\\notepad.exe"); Sleep(2000); // on attend deux secondes
//int rh = (int) ShellExecuteA(0,"open","calc.exe","","",SW_SHOWDEFAULT); system("start \"\" C:\\Windows\\system32\\calc.exe"); Sleep(2000); // on attend deux secondes
HWND hc = FindWindow("Notepad",NULL);
//ShowWindow(hc,SW_SHOWNORMAL); SetForegroundWindow(hc); Sleep(250); MoveWindow(hc, 120, 120, 800, 500, FALSE); Sleep(1000); MoveWindow(hc, 20, 20, 600, 300, FALSE); Sleep(100);
char *texte; texte="Titre modifié"; SetWindowText(hc, texte); //on change le titre de la fenêtre
Sleep(1000); SetFocus(hc); Sleep(250); ShowWindow( hc, SW_HIDE); ShowWindow( hc, SW_HIDE); Sleep(1000); ShowWindow( hc, SW_SHOW); Sleep(500);
t('a'); t('b'); t('c'); t('d'); t('e'); t('a'); t('b'); t('c'); t('d'); t('e'); t('a'); t('b'); t('c'); t('d'); t('e'); tc('m'); // {Ctrl}{M} équivaut à {Entrée} et à 0x0D
t('a'); t('b'); t('c'); t('d'); t('e'); t('a'); t('b'); t('c'); t('d'); t('e'); t('a'); t('b'); t('c'); t('d'); t('e'); tcode(0x0D); // {Entrée}
t('x'); t('y'); t('z');
tcode(0x09); // {TAB} ts('e'); // Shift => E majuscule ts('e'); ts('e'); ts('e'); ts('e');
Sleep(2000); ta('F'); // {Alt}{F} Sleep(800); t('q'); Sleep(1000); t('r');
Sleep(500); HWND hc = FindWindow("CalcFrame",NULL); RECT r; GetWindowRect(hc, &r); MoveWindow(hc, 400, 200, r.right-r.left, r.bottom-r.top, TRUE); Sleep(1000); GetWindowRect(hc, &r); MoveWindow(hc, 20, 20, r.right-r.left, r.bottom-r.top, TRUE); Sleep(500); PostMessage(hc, WM_CLOSE, 0, 0); Sleep(50);
return 1; }
Compilation avec cette commande :
tcc -o p6.exe p6.c shell32.def
Notez l'utilisation shell32.def pour rendre disponibles les fonctions de Shell32.dll Détail, le fichier p6.exe, ne pèse que 4 ko.

Python26.dll - Python par utilisation d'une DLL
Utiliser Python depuis TCC est assez simple. Il suffit d'utiliser python26.dll. Pour cela, comme dans l'exemple précédent, on se sert de la commande : tiny_impdef.exe C:\Windows\System32\python26.dll
Le code-source (fichier p7.c) est assez simple :
#include <stdio.h>
int main(int argc, char*argv[]) { Py_Initialize();
PyRun_SimpleString("f=open('bbb.txt','w')\n f.write('111111\\r\\n222222')\n f.close()");
PyRun_SimpleString("import ctypes\n ctypes.windll.user32.MessageBoxW(0, u'par Python + ctypes', u'Message affiché ', 0)\n");
Py_Finalize(); return 0; }
On compile avec la commande :
tcc -o p7.exe p7.c python26.def
À l'exécution, le fichier p7.exe, va faire deux choses (deux petits scripts en Python) :
- créer un fichier texte, bbb.txt contenant 111111\n222222
- Afficher un petit message, via ctypes
Notez aussi l'utilisation de scripts Python multi-lignes.

Créer une DLL - ammap.dll
La DLL que nous allons créer dans cet exemple est utile (ce n'est pas seulement un exemple). Elle offre un accès, en lecture et écriture à deux mmap. Rappel : les mmap sont des fichiers mappés en mémoire, accessibles depuis plusieurs processus simultanément, sans aucun contrôle ou verrou. Les fonctions mmap existent en standard dans de nombreux langages (non MS), comme Python, Ruby, Perl, Haskell, etc. et sont très utiles pour faire de l' IPC (Inter-Processus-Communication, ou échange de données entre différents processus).
Voici le code-source (fichier p8.c) :
#include <windows.h> #include <memory.h> #include <string.h>
#define DLL_EXPORT __declspec(dllexport)
#define SHMEMSIZE 32767
static LPVOID lpvMem = NULL; // pointeur pour mémoire partagée static HANDLE hMapObject = NULL; // handle pour mmap
static LPVOID lpvMem2 = NULL; static HANDLE hMapObject2 = NULL;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
BOOL fInit, fIgnore;
switch (fdwReason) { // chargement de la DLL case DLL_PROCESS_ATTACH: break; // attachement d'un processus case DLL_THREAD_ATTACH: break; // détachement d'un processus case DLL_THREAD_DETACH: break; // déchargement de la DLL case DLL_PROCESS_DETACH: // unmap la mémoire partagée et ferme le mmap1 fIgnore = UnmapViewOfFile(lpvMem); fIgnore = CloseHandle(hMapObject);
// unmap la mémoire partagée et ferme le mmap2 fIgnore = UnmapViewOfFile(lpvMem2); fIgnore = CloseHandle(hMapObject2); break; default: break; } return TRUE; UNREFERENCED_PARAMETER(hinstDLL); UNREFERENCED_PARAMETER(lpvReserved); }
// ------ 1 ----------------------------------------------------------------------
// Ouverture du mmap DLL_EXPORT VOID __stdcall Open(char *nom) {
BOOL fInit;
// Create a named file mapping object hMapObject = CreateFileMapping( INVALID_HANDLE_VALUE, // handle null NULL, // attributs de sécurité PAGE_READWRITE, // accès read/write 0, // taille: high 32-bits SHMEMSIZE, // taille: low 32-bits nom // nom de l'objet mappé ); if (hMapObject == NULL) return;
// est-ce que le mmap existe déjà ? fInit = (GetLastError() != ERROR_ALREADY_EXISTS); // obtient le pointeur sur le mmap lpvMem = MapViewOfFile( hMapObject, // handle FILE_MAP_WRITE, // accès read/write 0, // taille: high 32-bits 0, // taille: low 32-bits 0 // default: map entire file ); if(lpvMem == NULL) return; // si ERREUR ERREUR ERREUR ERREUR // si le mmap n'existait pas déjà, on initialise la mémoire if(fInit) { memset(lpvMem, '\0', SHMEMSIZE); return; } return; }
// Fermeture du mmap DLL_EXPORT VOID __stdcall Close(){ BOOL fInit, fIgnore; fIgnore = UnmapViewOfFile(lpvMem); // ferme le mmap fIgnore = CloseHandle(hMapObject); }
// Ecriture dans le mmap DLL_EXPORT VOID __stdcall SetSharedMem(char *str) { char *lpszTmp; lpszTmp = (char *) lpvMem; strncpy(lpszTmp,str,SHMEMSIZE); }
// Lecture dans le mmap DLL_EXPORT VOID __stdcall GetSharedMem(char *str, int size) { char *lpszTmp; lpszTmp = (char *) lpvMem; strncpy(str,lpszTmp,size); }
// ------ 2 ----------------------------------------------------------------------
DLL_EXPORT VOID __stdcall Open2(char *nom) { BOOL fInit;
hMapObject2 = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, SHMEMSIZE, nom ); if (hMapObject2 == NULL) return;
fInit = (GetLastError() != ERROR_ALREADY_EXISTS); lpvMem2 = MapViewOfFile( hMapObject2, FILE_MAP_WRITE, 0, 0, 0 ); if(lpvMem2 == NULL) return; // si ERREUR ERREUR ERREUR ERREUR if(fInit) { memset(lpvMem2, '\0', SHMEMSIZE); return; } return; }
DLL_EXPORT VOID __stdcall Close2() { BOOL fInit, fIgnore; fIgnore = UnmapViewOfFile(lpvMem2); fIgnore = CloseHandle(hMapObject2); }
DLL_EXPORT VOID __stdcall SetSharedMem2(char *str) { char *lpszTmp; lpszTmp = (char *) lpvMem2; strncpy(lpszTmp,str,SHMEMSIZE); }
DLL_EXPORT VOID __stdcall GetSharedMem2(char *str, int size) { char *lpszTmp; lpszTmp = (char *) lpvMem2; strncpy(str,lpszTmp,size); }
Pour le compiler, et créer la DLL, on utilisera cette commande :
tcc -shared -o p8.dll p8.c
Notez que, en plus du fichier p8.dll, il y a création d'un fichier P8.def.

Téléchargements
Pour éviter aux lecteurs de chercher (longuement) sur le Net, je vous propose quelques téléchargements dans cette page :



C'est tout !



|