En esta sección de Código Fuente en Delphi vamos a explicar cómo podemos saber si nuestra aplicación hecha para sistemas Windows, se está ejecutando en un sistema Unix/Linux bajo Wine.
Para ello, he escrito esta pequeña app de ejemplo.
Wine inicialmente fue un acrónimo para WINdows Emulator. Wine permite que programas diseñados para funcionar en MS-DOS, o en Windows se puedan ejecutar en Sistemas Operativos basados en Unix, (como cualquier versión de Linux) sin tener que modificar su código.
Wine provee de un cargador de programas que permite que muchas aplicaciones, diseñadas en principio para funcionar en Windows (2.0/3.x/9X/ME/NT/2000/XP/Vista/7/8 y 10), se ejecuten (sin modificarse) en varios sistemas operativos unix y unix-like como GNU/Linux, BSD, Solaris y Mac OS X
La pregunta que nos concierne a nosotros es ¿cómo puedo saber si mi programa (que está diseñado para funcionar en Windows) se está ejecutando realmente en una versión de Windows, o se está ejecutando en otro sistema operativo con la ayuda de Wine?
Tener la respuesta a esta pregunta puede servirnos, por ejemplo, para que nuestra app pueda abrir una página web en el navegador por defecto del sistema operativo en el que esté funcionando, y tener la certeza de que funcionará
Para ello tenemos las dos funciones que se muestran en el siguiente código: GetWineAvail y OpenURL
La función GetWineAvail no tiene parámetros y devuelve un valor verdadero/falso según estemos o no bajo el control de Wine (verdadero=> Wine)
Lo que hace esta función para saber si está presente Wine es comprobar si las funciones "wine_get_version" o "wine_nt_to_unix_file_name" están en la librería de enlace dinámico "ntdll.dll", en caso afirmativo es que nos encontramos bajo Wine.
La otra función (OpenURL) es muy simple, pero puede sernos útil para que los enlaces a páginas web desde nuestra app funcionen correctamente incluso ejecutandose en Linux nuestra App.
En la siguiente imagen puedes ver un ejemplo de uso de esta app.
A continuación, puedes ver el código completo de la app, y si lo deseas puedes descargarlo todo (código y app) en un archivo "zip".
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TForm1 = class(TForm) Label1: TLabel; Label2: TLabel; Panel1: TPanel; RadioGroup1: TRadioGroup; procedure Label1Click(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} uses shellapi; function GetWineAvail: boolean; type TWineGetVersion = function: PAnsiChar; {$IFDEF Win32}stdcall; {$ENDIF} TWineNTToUnixFileName = procedure(P1: Pointer; P2: Pointer); {$IFDEF Win32}stdcall; {$ENDIF} var LHandle: THandle; LWineGetVersion: TWineGetVersion; LWineNTToUnixFileName: TWineNTToUnixFileName; begin Result := False; LHandle := LoadLibrary('ntdll.dll'); if LHandle > HINSTANCE_ERROR then begin LWineGetVersion := GetProcAddress(LHandle, 'wine_get_version'); LWineNTToUnixFileName := GetProcAddress(LHandle, 'wine_nt_to_unix_file_name'); Result := Assigned(LWineGetVersion) or Assigned(LWineNTToUnixFileName); FreeLibrary(LHandle); end; // if LHandle > HINSTANCE_ERROR then begin end; procedure OpenUrl(url: string); begin ShellExecute(Application.Handle, 'open', PChar(url), nil, nil, SW_SHOWMAXIMIZED); end; procedure TForm1.FormCreate(Sender: TObject); begin if GetWineAvail then begin Label2.Caption := 'Estamos en un sistema Linux'; RadioGroup1.ItemIndex := 1; end else begin Label2.Caption := 'Estamos en un sistema Windows'; RadioGroup1.ItemIndex := 0; end; end; procedure TForm1.Label1Click(Sender: TObject); begin OpenUrl((Sender as TLabel).Caption); end; end.