File "exe2unix.inc"

Path: /exe2unix/inc/exe2unix.inc
File size: 11.53 KB
MIME-type:
Charset: utf-8

'--------------------------------------------------------------------------------
' 'exe2unix.inc' v0.4 for PBWin9 - Facilitates the usage of Windows .exe in Linux
'--------------------------------------------------------------------------------
DECLARE FUNCTION Exe2Unix(BYVAL src AS STRING, BYVAL showInAppMenu AS LONG, _
                          OPTIONAL BYVAL dkpName AS STRING) AS LONG
' - extract exe icon, convert it to png, copy it to ~/.local/share/icons
' - create a .desktop entry in ~/.local/share/applications to show icon in dock
' - if 'showInAppMenu' is true, add the program in the XDG Desktop Menu
' - use 'gio set' to apply the icon to the exe in the Linux file explorer
DECLARE SUB Me2Unix(BYVAL askConfirmation AS LONG, BYVAL showInAppMenu AS LONG, _
                    OPTIONAL BYVAL dkpName AS STRING)
' - exact same as Exe2Unix() but applied to ourselves when compiled into an exe
DECLARE FUNCTION Exe2UnixConfirm(BYVAL src AS STRING) AS LONG
' - ask user confirmation to register the exe in the Linux App Menu,
'   result is either %IDYES or %IDNO
DECLARE FUNCTION IcoStrip2Unix(BYVAL src AS STRING) AS STRING
' - extract an exe icon, convert it to png, copy it to ~/.local/share/icons
DECLARE SUB FileIco2Unix(BYVAL src AS STRING, BYVAL png AS STRING)
' - apply an icon (png) to a file in the Linux file explorer
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
#INCLUDE ONCE "Gdiplus.inc"      ' from JoseRoca includes
#INCLUDE ONCE "GdipUtils.inc"    ' from JoseRoca includes
#INCLUDE ONCE "inc/icostrip.inc"
#INCLUDE ONCE "inc/unix.inc"
'--------------------------------------------------------------------------------
MACRO UNIX_SHARE = UNIX_HOME + ".local\share\"
'--------------------------------------------------------------------------------
MACRO UNIX_XPATH = UnixPath(LTRIM$(EXE.PATH$, "\"))
'--------------------------------------------------------------------------------
MACRO UNIX_DESKTOP(x) = UNIX_SHARE+"applications\wine-"+UnixSafeName(x)+".desktop"
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
FUNCTION Exe2Unix(BYVAL src AS STRING, BYVAL showInAppMenu AS LONG, _
                  OPTIONAL BYVAL dkpName AS STRING) AS LONG
' Register a windows executable as a Linux App:
' - extract its icon, convert it to png, copy it to ~/.local/share/icons
' - create a .desktop entry in ~/.local/share/applications to show and launch
'   the program from the XDG Desktop Menu
' - customize the .exe itself to display its icon in Linux file explorer
  LOCAL ff AS LONG
  LOCAL lRes AS LONG
  LOCAL png AS STRING
  LOCAL wmc AS STRING
  LOCAL xec AS STRING
  LOCAL dkp AS STRING

  FUNCTION = 0 ' by default

  ' Extract exe icon and convert to png in ~/.local/share/icons
  png = IcoStrip2Unix(src)

  ' Set the program icon to the executable itself in Linux file explorer
  FileIco2Unix src, png

  ' Create the .desktop fields
  IF LEN(dkpName) THEN
    dkp = UNIX_DESKTOP(dkpName)
  ELSE
    dkp = UNIX_DESKTOP(src)
  END IF
  wmc = LCASE$(PATHNAME$(NAMEX, src))
  xec  = "env WINEPREFIX=" + $DQ
  xec += "/home/" + ENVIRON$("USERNAME")
  xec += "/.wine" + $DQ + " wine "
  xec += UnixProtect(src)

  ' Create .desktop file for the exe in ~/.local/share/applications
  ff = FREEFILE
  OPEN dkp FOR OUTPUT AS #ff
  PRINT #ff, "[Desktop Entry]"
  PRINT #ff, "Name=" + PATHNAME$(NAME, src)
  PRINT #ff, "StartupWMClass=" + wmc
  IF ISTRUE showInAppMenu THEN
    PRINT #ff, "Exec=" + xec
  ELSE
    PRINT #ff, "NoDisplay=true"
  END IF
  PRINT #ff, "Type=Application"
  PRINT #ff, "Terminal=false"
  PRINT #ff, "StartupNotify=true"
  PRINT #ff, "Icon=" + PATHNAME$(NAME, png)
  CLOSE #ff

  ' Set the program icon to the .desktop file too, for user friendliness
  FileIco2Unix dkp, png

  ' Done!
  FUNCTION = 1

END FUNCTION
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
SUB Me2Unix(BYVAL askConfirmation AS LONG, BYVAL showInAppMenu AS LONG, _
            OPTIONAL BYVAL dkpName AS STRING)
    LOCAL ff, lRes AS LONG
    LOCAL xPath AS STRING
    LOCAL dPath AS STRING
    LOCAL zText AS ASCIIZ * 255

    ' No need to go further if we're not on Unix
    IF NOT IsOnUnix() THEN EXIT SUB

    ' In any case, reveal the exe icon in Nautilus
    FileIco2Unix EXE.FULL$, IcoStrip2Unix(EXE.FULL$)

    ' Check any existing .dekstop file
    IF LEN(dkpName) THEN
        dPath = UNIX_DESKTOP(dkpName)
    ELSE
        dPath = UNIX_DESKTOP(EXE.FULL$)
    END IF
    IF EXISTS(dPath) THEN EXIT SUB

    ' Ask user confirmation if needed
    xPath = EXE.FULL$
    IF ISTRUE askConfirmation THEN
        lRes = MyMsgBox(0, "Do you want to register this program as a Linux App?" + $CRLF _
               + "(it will be listed in the XDG Desktop Menu for quick access)" _
               , EXE.NAME$, %MB_ICONQUESTION + %MB_YESNO)
        IF lRes = %IDNO THEN EXIT SUB

        IF LCASE$(EXE.PATH$) <> "c:\apps\" THEN
            lRes = MyMsgBox(0, "We recommend to have Windows executables stored in the " _
                   + "'~/.wine/drive_c/Apps' folder. Would you like to move this " _
                   + "program there, or do you prefer to launch it from " _
                   + "'" + UNIX_XPATH + "' ?" + $CR _
                   + "(beware that in this case, moving it in the future will break " _
                   + "the Linux App shortcut in the Desktop Menu)." + $CR + $CR _
                   + "- Click Yes to move to '~/.wine/drive_c/Apps'" + $CR + $CR _
                   + "- Click No to keep in '" + UNIX_XPATH + "'" + $CR + $CR _
                   + "- Click Cancel to abandon registration as a Linux App." _
                   , EXE.NAME$, %MB_ICONQUESTION + %MB_YESNOCANCEL)
            IF lRes = %IDCANCEL THEN EXIT SUB
            IF lRes = %IDYES THEN
                MKDIR "C:\Apps"
                FILECOPY EXE.FULL$, "C:\Apps\" + EXE.NAMEX$
                xPath = "C:\Apps\" + EXE.NAMEX$
            END IF
        END IF
    END IF

    ' Register!
    lRes = Exe2Unix(xPath, showInAppMenu, dkpName)
    IF askConfirmation AND lRes <= 0 THEN
        MyMsgBox(0, "An error occured." + $CRLF _
        +"Registration failed." + $CRLF + $CRLF _
        +"Click OK to continue the program." _
        , EXE.NAME$, %MB_ICONWARNING)
        EXIT SUB
    END IF

    ' Special case: exe moved, create batch file to delete old exe and restart in C:\Apps
    IF askConfirmation AND xPath <> EXE.FULL$ THEN
        ff = FREEFILE
        OPEN ENVIRON$("TEMP") + "\" + EXE.NAME$ + ".bat" FOR OUTPUT AS #ff
            PRINT #ff, "TimeOut 1"
            PRINT #ff, "del " + $DQ + EXE.FULL$ + $DQ
            PRINT #ff, "start " + $DQ+$DQ + $SPC + $DQ+xPath+$DQ
        CLOSE #ff
        ff = SHELL(ENVIRON$("TEMP") + "\" + EXE.NAME$ + ".bat", 0)
        ExitProcess(12345) ' Close ourselves
    END IF

END SUB
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
FUNCTION Exe2UnixConfirm(BYVAL src AS STRING) AS LONG
' Ask user confirmation to register the exe in the Linux App Menu
' Result is either %IDYES or %IDNO
  LOCAL lRes AS LONG
  lRes = MyMsgBox(0, "Would you like to register " _
       + $DQ + PATHNAME$(NAMEX,src) + $DQ _
       + " as a Linux App and launch it from " _
       + PATHNAME$(PATH,src) + " ?", EXE.NAME$ _
       , %MB_ICONQUESTION + %MB_YESNO)
  FUNCTION = lRes
END FUNCTION
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
FUNCTION IcoStrip2Unix(BYVAL src AS STRING) AS STRING
' - extract an exe icon, convert it to png, copy it to ~/.local/share/icons
  LOCAL ico AS STRING
  LOCAL png AS STRING
  LOCAL hIcon AS DWORD
  LOCAL pImage AS DWORD
  LOCAL i, j AS LONG

  ' Does the executable icon in png format already exist in ~/.local/share/icons?
  ico = UNIX_SHARE + "icons\" + UnixSafeName(src) + ".ico"
  png = LEFT$(ico, -4) + ".png"
  IF EXISTS(png) THEN FUNCTION = png : EXIT FUNCTION

  ' If not, extract exe's main icon
  IF NOT EXISTS(ico) THEN
    IF IcoStrip(src, 1, ico) <= 0 THEN ' extraction failed
      FUNCTION = ""
      EXIT FUNCTION
    END IF
  END IF

  ' Convert executable icon to png
'  UnixShell "convert " _
'    + "~/.local/share/icons/"+UnixSafeName(src)+".ico " _
'    + "~/.local/share/icons/"+UnixSafeName(src)+".png"
  hIcon = LoadImage(0, BYVAL STRPTR(ico), %IMAGE_ICON, gsIcoRes, gsIcoRes, %LR_LOADFROMFILE)
  GdipCreateBitmapFromHICON hIcon, pImage
  GdipConvertToPng pImage, png

  ' Conversion to png worked (single resolution icon)
  IF EXISTS(png) THEN FUNCTION = png : EXIT FUNCTION

  ' Conversion produced several resolution png's
  IF EXISTS(LEFT$(png,-4)+"-0.png") THEN
    DO
      INCR i
    LOOP UNTIL NOT EXISTS(LEFT$(png,-4)+"-"+FORMAT$(i)+".png")
    DECR i ' final index for highest resolution png
    NAME LEFT$(png,-4)+"-"+FORMAT$(i)+".png" _
      AS LEFT$(png,-4)+".png"
    FOR j = 0 TO i-1
      KILL LEFT$(png,-4)+"-"+FORMAT$(j)+".png"
    NEXT
    FUNCTION = png
    EXIT FUNCTION
  END IF

  ' Conversion didn't produce any png > use ico instead
  FUNCTION = ico

END FUNCTION
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
SUB FileIco2Unix(BYVAL src AS STRING, BYVAL png AS STRING)
' - customize a file in Linux file explorer to display an icon (png)
  LOCAL xec AS STRING

  xec  = "gio set -t 'string' '" + UnixPath(src) + "' "
  xec += "'metadata::custom-icon' "
  xec += "'file://" + UnixPath(png) + "'"
  UnixShell xec
END SUB
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
#IF NOT %DEF(%FN_EXISTS)
%FN_EXISTS = -1
FUNCTION EXISTS(BYVAL f AS STRING) AS LONG
 LOCAL i AS LONG
 i = GETATTR(f)
 FUNCTION = (ERRCLEAR = 0)
END FUNCTION
#ENDIF
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
FUNCTION UnixSafeName(BYVAL xpath AS STRING) AS STRING
' Define a safe filename for a windows executable, for use in unix
    LOCAL r AS STRING
    r = PATHNAME$(NAME, xpath)
    r = LCASE$(REMOVE$(r, " "))
    FUNCTION = r
END FUNCTION
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
FUNCTION UnixProtect(BYVAL str AS STRING) AS STRING
    LOCAL r AS STRING
    r = str
    REPLACE "\" WITH "\\\\" IN r
    REPLACE " " WITH "\\ " IN r
    FUNCTION = r
END FUNCTION
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
SUB GdipConvertToPng(BYVAL pImage AS DWORD, BYVAL srcImg AS STRING)
   LOCAL hStatus AS LONG
   LOCAL token AS DWORD
   LOCAL StartupInput AS GdiplusStartupInput

   ' Initialize GDI+
   StartupInput.GdiplusVersion = 1
   hStatus = GdiplusStartup(token, StartupInput, BYVAL %NULL)
   IF hStatus THEN
'      ?"Error initializing GDI+",%MB_ICONERROR,EXE.NAME$
      EXIT SUB
   END IF

   ' Call conversion function
   GdiPlusSaveImageToPng pImage, srcImg

   ' Shutdown GDI+
   GdiplusShutdown token
END SUB
'--------------------------------------------------------------------------------