Ticket #677: 677-win32-launcher.patch

File 677-win32-launcher.patch, 12.5 KB (added by dolmen, 4 years ago)

Patch with the great new Padre launcher ($X issue fixed, build improved)

  • win32/padre.c

    Issue 677: improved Win32 launcher
    - New launcher which embed Perl, so the Padre process appears as Padre.exe
      instead of wperl.exe
    - Manifest file is now embeded as a resource in the executable
      (padre.exe.manifest replaces wperl.exe.manifest), so less impact of other
      applications using wperl.exe
    - The executable is now built using the same flags as Perl.exe using
      ExtUtils::Embed
    
    
     
    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 
     172 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 
    249255    unlink "$src/padre-rc.o" if -f "$src/padre-rc.o"; 
    250256 
    251257    # Step 2: Build Padre's win32 resource using windres 
    252     system qq[cd $src && windres padre-rc.rc padre-rc.o]; 
     258    system qq[cd $src && windres --input padre-rc.rc --output padre-rc.res --output-format=coff]; 
    253259 
    254260    # 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    system "cd $src && $Config{cc} -mwin32 -mwindows -Wl,-s padre.c padre-rc.res -o ../$bin/padre.exe ".ccopts.ldopts; 
    256262 
    257263    # Step 4: Remove temporary files 
    258     unlink "$src/padre-rc.o" if -f "$src/padre-rc.o"; 
    259  
    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"; 
     264    unlink "$src/padre-rc.res" if -f "$src/padre-rc.res"; 
    262265} 
    263266 
    2642671;