Installation de paquets spécifiques
On va essayer de créer un programme qui n'est pas pour Linux, ni pour Windows, mais pour Wine.
Winegcc, ce n'est pas Wine, et ce n'est pas gcc.
C'est une chaine de compilation spéciale pour wine, qui utilise gcc.
Il faut installer ces deux paquets:
le développement de Wine
sudo dnf install wine-develet l'extension c++ de gcc
sudo dnf install gcc-c++
Le fichier dll: dll.c
Il contient le code de 3 fonctions:
fun(), qui imprime "Hello from dll!".
calc(), qui calcule a*b.
et GetSystemPowerStatus(), qui contrôle l'état de la batterie.
NtPowerInformation() ne semble pas être une fonction Windows, mais une fonction du noyau, dont le code source se trouve dans dlls/ntdll/unix/system.c de Wine
#include <stdio.h> #include <stdarg.h> #include <ntstatus.h> #define WIN32_NO_STATUS #include <windef.h> #include <winbase.h> #include <winternl.h> #include <wine/debug.h> void fun(void) { printf("Hello from dll!\n"); } int calc(int a, int b) { return a*b ; } /*********************************************************************** * GetSystemPowerStatus (KERNEL32.@) */ BOOL WINAPI GetSystemPowerStatus(LPSYSTEM_POWER_STATUS ps) { SYSTEM_BATTERY_STATE bs; NTSTATUS status; //TRACE("(%p)\n", ps); ps->ACLineStatus = AC_LINE_UNKNOWN; ps->BatteryFlag = BATTERY_FLAG_UNKNOWN; ps->BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN; ps->SystemStatusFlag = 0; ps->BatteryLifeTime = BATTERY_LIFE_UNKNOWN; ps->BatteryFullLifeTime = BATTERY_LIFE_UNKNOWN; status = NtPowerInformation(SystemBatteryState, NULL, 0, &bs, sizeof(bs)); if (status == STATUS_NOT_IMPLEMENTED) return TRUE; if (FAILED(status)) return FALSE; ps->ACLineStatus = bs.AcOnLine; if (bs.BatteryPresent) { ps->BatteryLifePercent = bs.MaxCapacity ? 100 * bs.RemainingCapacity / bs.MaxCapacity : 100; ps->BatteryLifeTime = bs.EstimatedTime; if (!bs.Charging && (LONG)bs.Rate < 0) ps->BatteryFullLifeTime = 3600 * bs.MaxCapacity / -(LONG)bs.Rate; ps->BatteryFlag = 0; if (bs.Charging) ps->BatteryFlag |= BATTERY_FLAG_CHARGING; if (ps->BatteryLifePercent > 66) ps->BatteryFlag |= BATTERY_FLAG_HIGH; if (ps->BatteryLifePercent < 33) ps->BatteryFlag |= BATTERY_FLAG_LOW; if (ps->BatteryLifePercent < 5) ps->BatteryFlag |= BATTERY_FLAG_CRITICAL; } else { ps->BatteryFlag = BATTERY_FLAG_NO_BATTERY; } return TRUE; }
Le fichier spec: dll.spec
@ cdecl fun() @ cdecl calc(long long) @ cdecl GetSystemPowerStatus(ptr)
Le fichier d'appel de la dll: exec.c
#include <stdio.h> #include <windows.h> #include <ntstatus.h> #define WIN32_NO_STATUS #include <windef.h> #include <winbase.h> #include <winternl.h> int main() { printf("Hello from exe!\n") ; typedef void fptr(void) ; typedef int calcptr(int a, int b) ; typedef BOOL WINAPI getpwstatusptr(LPSYSTEM_POWER_STATUS ps) ; HMODULE lib = LoadLibraryA("dll.dll.so") ; if (NULL == lib) { lib = LoadLibraryA("linuxhost.dll") ; } if (lib) { fptr* f = (fptr*)GetProcAddress(lib, "fun") ; if (f != NULL) { f() ; } else { printf("No fun found :(\n") ; } calcptr* c = (calcptr*)GetProcAddress(lib, "calc") ; if (c != NULL) { int a = 2, b=3 ; a = c(a, b) ; printf("2*3=%ld\n", a) ; } getpwstatusptr* gps = (getpwstatusptr*)GetProcAddress(lib, "GetSystemPowerStatus") ; if (NULL != gps) { SYSTEM_POWER_STATUS pw, *pwptr ; pwptr = &pw ; BOOL toto = gps(&pw) ; printf("toto = %ld\n", toto) ; if (toto) { // 0=Offline, 1=OnLine else Unknown printf("ACLineStatus %ld\n", pwptr->ACLineStatus) ; // 1 High, more than 66% // 2 Low, less than 33% // 4 Critical, less than 5% // 8 Charging // 128 No Battery printf("BatteryFlag %ld\n", pwptr->BatteryFlag ) ; // 255 or percent printf("BatteryLifePercent %ld\n", pwptr->BatteryLifePercent) ; // 0 Battery saver is off. // 1 Battery saver on. Save energy where possible. printf("SystemStatus %ld\n", pwptr->SystemStatusFlag) ; // -1 or something printf("BatteryLifeTime %ld\n", pwptr->BatteryLifeTime) ; // -1 or something printf("BatteryFullLifeTime %ld\n", pwptr->BatteryFullLifeTime) ; if (pwptr->ACLineStatus != 255) { if (pwptr->ACLineStatus == 0) printf("OffLine\n") ; if (pwptr->ACLineStatus == 1) printf("OnLine\n") ; } if (pwptr->BatteryLifePercent != 255) { printf("%ld %%\n", pwptr->BatteryLifePercent) ; } if (pwptr->BatteryFlag != 255) { if (pwptr->BatteryFlag & 1) printf("more than 66%\n") ; if (pwptr->BatteryFlag & 2) printf("less than 33%\n") ; if (pwptr->BatteryFlag & 4) printf("less than 5%\n") ; if (pwptr->BatteryFlag & 8) printf("charging\n") ; if (pwptr->BatteryFlag & 128) printf("No battery\n") ; } } } } else { printf("No library found\n") ; } }
Le fichier makefile
target: dll exec dll: dll.c dll.spec winegcc -shared dll.c dll.spec -o dll exec : exec.c winegcc exec.c -o exec
Le lancement de la compilation
Créer un répertoire n'importe où dans l'espace utilisateur.
Copier les fichiers dll.c, dll.spec, exec.c et makefile.
Se positionner dans le répertoire, très simple, clic droit et "Ouvrir dans un terminal".
Une fois le terminal ouvert, taper make.
La compilation devrait se lancer et se dérouler sans erreur.
Le lancement du programme
Pour lancer le programme, il ne faut pas oublier de dire que l'on veut un programme du répertoire courant, pas un programme du shell.
./exec.exe
Après quelques lignes, nous rappelant que ce que l'on fait est un peu hors norme, on retrouve la sortie de notre programme d'appel à la dll.
Conclusion
Vite, la suite ! On a vu Wine, WinUAE, on va jouer avec les deux...