Ticket #677: 677-win32-launcher-2.patch

File 677-win32-launcher-2.patch, 14.2 KB (added by dolmen, 5 years ago)

Updated patch : fixed manifest res id, improved build, added README update

  • win32/README

    Issue 677: improved Win32 launcher
    - New launcher which embed Perl, so the Padre process appears as Padre.exe
      instead of wperl.exe in the Task Manager (see README for details)
    - Manifest file is now embeded as a resource in the executable
      (padre.exe.manifest replaces wperl.exe.manifest), so remove impact on other
      applications using wperl.exe.
      Verified on Windows 7.
    - The executable is now built using the same flags as Perl.exe using
      ExtUtils::Embed
    - resource file (padre-rc.rc) is now compiled as a COFF file which is a step
      towards compatibility with MSVC
    
     
    11README for padre.exe 
    22 
    33This is Padre's win32 launcher. It does the following: 
    4     * Tries to find wperl.exe in the executable path. If it fails, it exits  
    5         with a message. 
    6     * Tries to find padre script in the executable path. If it fails, it exits  
    7         with a message. 
    8     * Runs %padre_exe_path%\wperl.exe %padre_exe_path%\padre. 
     4    * Tries to find the padre script in the same directory as padre.exe 
     5          If it fails, it exits with a message box. 
     6    * Tries to find wperl.exe in the executable path. 
     7      If it succeed, it will set $^X to this path. 
     8    * Creates a Perl interpreter and run the padre script. 
    99 
    10 To compile it, simply 'perl Makefile.PL' or 'cpan .' in the parent folder. You'll 
    11 ofcourse need Strawberry Perl as it has gcc and windres out of the box. 
     10Padre.exe is dynamically linked to the perl<xxx>.dll on which it was built, so 
     11it is safer to build it at install time on a user machine. 
     12 
     13To compile it, simply 'perl Makefile.PL' or 'cpan .' in the parent folder. 
     14You'll of course need Strawberry Perl as it has gcc and windres out of the box. 
  • win32/padre.c

     
    11/** 
    2  * Padre Minimal Win32 Executable Launcher 
    3  * @author Ahmad M. Zawawi <ahmad.zawawi@gmail.com> 
     2 * Padre Win32 executable Launcher 
    43 * @author Olivier Mengué <dolmen@cpan.org> 
    54 */ 
    65#define WIN32_LEAN_AND_MEAN 
    76#define STRICT 
     7 
     8#define _WIN32_WINNT 0x0501 
    89#include <windows.h> 
    910#include <tchar.h> 
    1011 
     12 
     13#include <EXTERN.h>               /* from the Perl distribution     */ 
     14#include <perl.h>                 /* from the Perl distribution     */ 
     15 
    1116#include "padre-rc.h" 
    1217 
     18 
    1319static void LocalizedMessageBox(LPCTSTR lpMessage, LPCTSTR lpTitle, DWORD dwFlags) 
    1420{ 
    1521    HMODULE hModule; 
     
    3440    return (att != INVALID_FILE_ATTRIBUTES); //&& (att & (FILE_ATTRIBUTE_DEVICE|FILE_ATTRIBUTE_DIRECTORY) == 0); 
    3541} 
    3642 
     43static int GetDirectory(LPTSTR lpDir, LPCTSTR lpFilename, int iBufSize) 
     44{ 
     45    int len, len2; 
     46    LPCTSTR p; 
     47    LPTSTR q; 
    3748 
    38 /** 
    39  * When called by windows, we simply launch Padre from here 
    40  */ 
    41 #ifdef Mini1 
    42 VOID WINAPI __main(VOID) 
    43 #elif defined(Mini2) 
    44 VOID WINAPI WinMainCRTStartup(VOID) 
    45 #else 
    46 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, 
    47     LPSTR lpCmdLineArgs, int nCmdShow) 
    48 #endif 
     49    len = lstrlen(lpFilename); 
     50    if (len == 0) { 
     51        lpDir[0] = _T('\0'); 
     52        return 0; 
     53    } 
     54    p = lpFilename + len; 
     55    while (--p > lpFilename) { 
     56        if (*p == _T('\\') || *p == _T('/')) 
     57            break; 
     58    }; 
     59    len = p - lpFilename; 
     60    if (lpDir == lpFilename) { 
     61        *(LPTSTR)p = _T('\0'); 
     62    } else { 
     63        if (len+1 > iBufSize) { 
     64            lpDir[0] = _T('\0'); 
     65            return 0; 
     66        } 
     67        p = lpFilename; 
     68        q = lpDir; 
     69        len2 = len; 
     70        while (len2--) 
     71            *q++ = *p++; 
     72        *q = _T('\0'); 
     73    } 
     74    return len; 
     75} 
     76 
     77 
     78 
     79/* From win32/perllib.c  - begin */ 
     80// This the special part that is not documented in perlembed 
     81 
     82EXTERN_C void boot_DynaLoader (pTHX_ CV* cv); 
     83 
     84static void 
     85xs_init(pTHX) 
    4986{ 
     87    char *file = __FILE__; 
     88    dXSUB_SYS; 
     89    newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); 
     90} 
     91/* From win32/perllib.c  - end */ 
     92 
     93 
     94 
     95 
     96 
     97 
     98int main(int argc, char **argv, char **env) 
     99{ 
    50100    // Padre.exe path 
    51101    TCHAR szExePath[MAX_PATH]; 
    52     // WPerl.exe path 
    53     TCHAR szWPerl[MAX_PATH]; 
    54102    // Padre script path 
    55103    TCHAR szPadre[MAX_PATH]; 
    56     // WPerl Command line 
    57     TCHAR szCmdLine[1024+1]; 
    58     HMODULE hModule; 
    59     STARTUPINFO si; 
    60     PROCESS_INFORMATION pi; 
    61     BOOL bSuccess; 
     104    // wperl.exe path 
     105    TCHAR szWPerlExePath[MAX_PATH]; 
     106    HMODULE hModule, hModulePerlDll; 
    62107    DWORD dwLength; 
    63     LPCTSTR lpArgs; 
     108    HANDLE hHeap; 
     109    char **new_argv; 
     110    PerlInterpreter *my_perl;  /***    The Perl interpreter    ***/ 
     111    int i; 
     112    int exitcode; 
    64113 
    65114    hModule = GetModuleHandle(NULL); 
    66     //Find the the executable's path 
     115    // Find the the executable's path 
    67116    dwLength = GetModuleFileName(hModule, szExePath, sizeof(szExePath)/sizeof(szExePath[0])); 
    68     if (dwLength) { 
    69         while (dwLength && szExePath[ dwLength ] != '\\' && szExePath[ dwLength ] != '/') { 
    70             dwLength--; 
    71         } 
    72         szExePath[ dwLength + 1 ] = '\0'; 
    73     } 
    74117 
    75 #if 0 
    76     lstrcpy(szWPerl, _T("C:\\strawberry\\perl\\bin\\wperl.exe")); 
    77 #else 
    78     lstrcpy(szWPerl, szExePath); 
    79     lstrcpy(&szWPerl[dwLength+1], _T("wperl.exe")); 
    80 #endif 
    81118 
    82     //At this point we should check if wperl.exe exists or not 
    83     if (! FileExists(szWPerl)) { 
    84         //if it does not exist, let us try to find it 
    85         //in ..\..\bin (to support vendor perl) 
    86         //see ticket #837 
    87         lstrcpy(szWPerl, szExePath); 
    88         lstrcpy(szWPerl, _T("..\\..\\bin\\wperl.exe") ); 
     119    // Build the 'padre' script path 
     120    dwLength = GetDirectory(szPadre, szExePath, sizeof(szPadre)/sizeof(szPadre[0])); 
     121    lstrcpy(szPadre+dwLength, _T("\\padre")); 
     122    //MessageBox(NULL, szPadre, "Padre", MB_OK|MB_ICONINFORMATION); 
    89123 
    90         //Display an error message if wperl.exe is not found 
    91         if (! FileExists(szWPerl)) { 
    92             LocalizedMessageBox(MAKEINTRESOURCE(IDS_ERR_WPERL), MAKEINTRESOURCE(IDS_APP_TITLE), MB_OK|MB_ICONERROR); 
    93             ExitProcess(1); 
    94         } 
     124    // At this point we should check if padre script exists or not 
     125    if (! FileExists(szPadre)) { 
     126        LocalizedMessageBox(MAKEINTRESOURCE(IDS_ERR_SCRIPT), MAKEINTRESOURCE(IDS_APP_TITLE), MB_OK|MB_ICONERROR); 
     127        return 1; 
    95128    } 
    96129 
     130    // Rewrite the command line to insert the padre script 
     131    hHeap = GetProcessHeap(); 
     132    new_argv = HeapAlloc(hHeap, 0, (argc+2)*sizeof(new_argv[0])); 
     133    new_argv[0] = argv[0]; 
     134    new_argv[1] = "--"; 
     135    new_argv[2] = szPadre; 
     136    for(i=1; i<argc; i++) 
     137        new_argv[i+2] = argv[i]; 
     138    argc += 2; 
     139    argv = new_argv; 
    97140 
    98     // Build the 'padre' script path 
    99     lstrcpy(szPadre, szExePath); 
    100     lstrcpy(&szPadre[dwLength+1], _T("padre")); 
     141    // We must set $^X to wperl.exe 
     142    // We do that by changing argv[0] 
    101143 
    102     //At this point we should check if padre script exists or not 
    103     if (! FileExists(szPadre)) { 
    104         LocalizedMessageBox(MAKEINTRESOURCE(IDS_ERR_SCRIPT), MAKEINTRESOURCE(IDS_APP_TITLE), MB_OK|MB_ICONERROR); 
    105         ExitProcess(1); 
     144    // Get the module of the Perl DLL to which we have been linked 
     145    // as this is where wperl.exe is. 
     146    if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 
     147                        | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, 
     148                        (LPCTSTR)RunPerl, &hModulePerlDll) 
     149            && hModulePerlDll != hModule) { 
     150        // If hModulePerlDll == hModule, we have to for another function 
     151 
     152        dwLength = GetModuleFileName(hModulePerlDll, szWPerlExePath, 
     153                    sizeof(szWPerlExePath)/sizeof(szWPerlExePath[0])); 
     154        //MessageBox(NULL, szWPerlExePath, "Padre", MB_OK|MB_ICONINFORMATION); 
     155        dwLength = GetDirectory(szWPerlExePath, szWPerlExePath, 
     156                    sizeof(szWPerlExePath)/sizeof(szWPerlExePath[0])); 
     157        lstrcpy(szWPerlExePath+dwLength, _T("\\wperl.exe")); 
     158        if (FileExists(szWPerlExePath)) 
     159            argv[0] = szWPerlExePath; 
    106160    } 
    107161 
    108     lpArgs = GetCommandLine(); 
    109     //LocalizedMessageBox(lpArgs, MAKEINTRESOURCE(IDS_APP_TITLE), MB_OK|MB_ICONINFORMATION); 
    110     do { 
    111         while (*lpArgs == _T(' ') || *lpArgs == _T('\t')) lpArgs++; 
    112         if (!*lpArgs) break; 
    113         if (*lpArgs == _T('"')) { 
    114             lpArgs++; 
    115             while (*lpArgs && *lpArgs != _T('"')) lpArgs++; 
    116             if (*lpArgs == _T('"')) lpArgs++; 
    117         } else { 
    118             while (*lpArgs && *lpArgs != _T(' ') && *lpArgs != _T('\t')) lpArgs++; 
    119         } 
    120     } while (0); 
    121     // Build the command line 
    122     wsprintf(szCmdLine, "\"%s\" \"%s\"%s", szWPerl, szPadre, lpArgs); 
    123     szCmdLine[(sizeof(szCmdLine)/sizeof(szCmdLine[0]))-1] = '\0'; 
     162    //MessageBox(NULL, argv[0], "Padre", MB_OK|MB_ICONINFORMATION); 
     163     
     164#if 0 
     165    /* 
     166     * Unfortunately it seems RunPerl() ignores the changed argv[0] and 
     167     * overrides argv[0] so that $^X is still Padre.exe 
     168     */ 
     169    exitcode = RunPerl(argc, argv, env); 
     170#else 
    124171 
    125     ZeroMemory( &pi, sizeof(pi) ); 
    126     GetStartupInfo(&si); 
    127     //LocalizedMessageBox(szCmdLine, MAKEINTRESOURCE(IDS_APP_TITLE), MB_OK|MB_ICONINFORMATION); 
    128     bSuccess = CreateProcess(szWPerl, 
    129                              szCmdLine, 
    130                              NULL, 
    131                              NULL, 
    132                              TRUE, 
    133                              GetPriorityClass(hModule), 
    134                              GetEnvironmentStrings(), 
    135                              NULL, 
    136                              &si, 
    137                              &pi); 
    138     if (bSuccess) { 
    139         //WaitForSingleObject( pi.hProcess, INFINITE ); 
    140         CloseHandle(pi.hProcess); 
    141         CloseHandle(pi.hThread); 
     172#if defined(TOP_CLONE) && defined(USE_ITHREADS) 
     173    // See the RunPerl source 
     174    MessageBox(NULL, "FIXME: ithreads support not implemented in Padre.exe launcher!", "Padre", MB_OK|MB_ICONERROR); 
     175#endif 
     176 
     177    /* This is derived from the source of RunPerl() */ 
     178 
     179    PERL_SYS_INIT3(&argc, &argv, &env); 
     180    if (!(my_perl = perl_alloc())) { 
     181        MessageBox(NULL, "Can't allocate Perl interpreter!", "Padre", MB_OK|MB_ICONERROR); 
     182        exitcode = 1; 
    142183    } else { 
    143         LocalizedMessageBox(MAKEINTRESOURCE(IDS_ERR_RUN), MAKEINTRESOURCE(IDS_APP_TITLE), MB_OK|MB_ICONERROR); 
     184        perl_construct(my_perl); 
     185        PL_exit_flags |= PERL_EXIT_DESTRUCT_END; 
     186        PL_perl_destruct_level = 0; 
     187        exitcode = perl_parse(my_perl, xs_init, argc, argv, env) 
     188                || perl_run(my_perl); 
     189        perl_destruct(my_perl); 
     190        perl_free(my_perl); 
    144191    } 
     192    PERL_SYS_TERM(); 
    145193 
    146     // The application's return value 
    147     ExitProcess(0); 
     194#endif 
     195 
     196    HeapFree(hHeap, 0, new_argv); 
     197    return exitcode; 
    148198} 
    149199/** 
    150200# Copyright 2008-2010 The Padre development team as listed in Padre.pm. 
  • win32/wperl.exe.manifest

     
    1 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
    2 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
    3  
    4     <assemblyIdentity 
    5         version="5.0.0.0" 
    6         processorArchitecture="x86" 
    7         name="wperl.exe" 
    8         type="win32" 
    9     /> 
    10     <description>wperl</description> 
    11  
    12     <!-- Enable XP/Vista-style themes --> 
    13     <dependency> 
    14         <dependentAssembly> 
    15             <assemblyIdentity 
    16                 type="win32" 
    17                 name="Microsoft.Windows.Common-Controls" 
    18                 version="6.0.0.0" 
    19                 processorArchitecture="X86" 
    20                 publicKeyToken="6595b64144ccf1df" 
    21                 language="*" 
    22             /> 
    23         </dependentAssembly> 
    24     </dependency> 
    25  
    26     <!-- Identify the application security requirements. --> 
    27     <ms_asmv2:trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2"> 
    28         <ms_asmv2:security> 
    29             <ms_asmv2:requestedPrivileges> 
    30                 <ms_asmv2:requestedExecutionLevel 
    31                     level="asInvoker" uiAccess="false"/> 
    32             </ms_asmv2:requestedPrivileges> 
    33         </ms_asmv2:security> 
    34     </ms_asmv2:trustInfo> 
    35  
    36 </assembly> 
    37  No newline at end of file 
  • win32/padre.exe.manifest

     
    22<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
    33 
    44    <assemblyIdentity 
    5         version="5.0.0.0" 
     5        version="0.58.0.0" 
    66        processorArchitecture="x86" 
    7         name="wperl.exe" 
     7        name="Padre" 
    88        type="win32" 
    99    /> 
    10     <description>wperl</description> 
     10    <description>Padre - The Perl IDE</description> 
    1111 
    1212    <!-- Enable XP/Vista-style themes --> 
    1313    <dependency> 
     
    3333        </ms_asmv2:security> 
    3434    </ms_asmv2:trustInfo> 
    3535 
    36 </assembly> 
    37  No newline at end of file 
     36</assembly> 
  • win32/padre-rc.rc

     
    1212 
    1313IDI_APP ICON DISCARDABLE "padre.ico" 
    1414 
     15// Embed the manifest in the exe 
     16// http://msdn.microsoft.com/fr-fr/library/bb773175%28en-us,VS.85%29.aspx 
     17CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "padre.exe.manifest" 
    1518 
     19 
    1620// Languages list: 
    1721// http://msdn.microsoft.com/en-us/library/dd318693%28VS.85%29.aspx 
    1822 
     
    2024LANGUAGE LANG_FRENCH, SUBLANG_FRENCH 
    2125BEGIN 
    2226   IDS_APP_TITLE,  "Padre" 
    23    IDS_ERR_WPERL,  "Fichier « WPerl.exe » introuvable !" 
     27   IDS_ERR_WPERL,  "Programme « WPerl.exe » introuvable !" 
    2428   IDS_ERR_SCRIPT, "Script « padre » introuvable !" 
    2529   IDS_ERR_RUN,    "Echec du lancement du script avec « padre » avec « WPerl.exe » !" 
    2630END 
  • privinc/Module/Install/PRIVATE/Padre.pm

     
    88use FindBin    (); 
    99use File::Find (); 
    1010 
     11# For building the Win32 launcher 
     12use Config; 
     13use ExtUtils::Embed; 
     14 
    1115our $VERSION = '0.26'; 
    1216use base qw{ Module::Install::Base }; 
    1317 
     
    245249    # Create the blib/bin folder 
    246250    system $^X , qw[-MExtUtils::Command -e mkpath --], $bin; 
    247251 
     252    # TODO update the version number in win32/padre.exe.manifest 
     253 
    248254    # Step 1: Make sure we do not have old files 
    249     unlink "$src/padre-rc.o" if -f "$src/padre-rc.o"; 
     255    my @temp_files = map {"$src/$_"} qw[ padre-rc.res perlxsi.c ]; 
     256    map { unlink } (grep { -f } @temp_files); 
    250257 
    251258    # Step 2: Build Padre's win32 resource using windres 
    252     system qq[cd $src && windres padre-rc.rc padre-rc.o]; 
     259    system qq[cd $src && windres --input padre-rc.rc --output padre-rc.res --output-format=coff]; 
    253260 
    254     # Step 3: Build padre.exe using gcc 
    255     system "cd $src && gcc -Wall -Os -mwin32 -mwindows -Wl,-s padre.c padre-rc.o -o ../$bin/padre.exe"; 
     261    # Step 3: Generate xs_init() function for static libraries 
     262    xsinit("$src/perlxsi.c", 0); 
    256263 
    257     # Step 4: Remove temporary files 
    258     unlink "$src/padre-rc.o" if -f "$src/padre-rc.o"; 
     264    # Step 4: Build padre.exe using $Config{cc} 
     265    system "cd $src && $Config{cc} -mwin32 -mwindows -Wl,-s padre.c perlxsi.c padre-rc.res -o ../$bin/padre.exe ".ccopts.ldopts; 
    259266 
    260     # Step 5: Install XP manifest to get a themed Padre 
    261     system $^X , qw[-MExtUtils::Command -e cp --], "$src/wperl.exe.manifest", "$bin/wperl.exe.manifest"; 
     267    # Step 5: Remove temporary files 
     268    map { unlink } (grep { -f } @temp_files); 
    262269} 
    263270 
    2642711;