Ticket #677: 677-win32-launcher-2.patch
| File 677-win32-launcher-2.patch, 14.2 KB (added by dolmen, 3 years ago) |
|---|
-
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
1 1 README for padre.exe 2 2 3 3 This is Padre's win32 launcher. It does the following: 4 * Tries to find wperl.exe in the executable path. If it fails, it exits5 with a message.6 * Tries to find padre script in the executable path. If it fails, it exits7 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. 9 9 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. 10 Padre.exe is dynamically linked to the perl<xxx>.dll on which it was built, so 11 it is safer to build it at install time on a user machine. 12 13 To compile it, simply 'perl Makefile.PL' or 'cpan .' in the parent folder. 14 You'll of course need Strawberry Perl as it has gcc and windres out of the box. -
win32/padre.c
1 1 /** 2 * Padre Minimal Win32 Executable Launcher 3 * @author Ahmad M. Zawawi <ahmad.zawawi@gmail.com> 2 * Padre Win32 executable Launcher 4 3 * @author Olivier Mengué <dolmen@cpan.org> 5 4 */ 6 5 #define WIN32_LEAN_AND_MEAN 7 6 #define STRICT 7 8 #define _WIN32_WINNT 0x0501 8 9 #include <windows.h> 9 10 #include <tchar.h> 10 11 12 13 #include <EXTERN.h> /* from the Perl distribution */ 14 #include <perl.h> /* from the Perl distribution */ 15 11 16 #include "padre-rc.h" 12 17 18 13 19 static void LocalizedMessageBox(LPCTSTR lpMessage, LPCTSTR lpTitle, DWORD dwFlags) 14 20 { 15 21 HMODULE hModule; … … 34 40 return (att != INVALID_FILE_ATTRIBUTES); //&& (att & (FILE_ATTRIBUTE_DEVICE|FILE_ATTRIBUTE_DIRECTORY) == 0); 35 41 } 36 42 43 static int GetDirectory(LPTSTR lpDir, LPCTSTR lpFilename, int iBufSize) 44 { 45 int len, len2; 46 LPCTSTR p; 47 LPTSTR q; 37 48 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 82 EXTERN_C void boot_DynaLoader (pTHX_ CV* cv); 83 84 static void 85 xs_init(pTHX) 49 86 { 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 98 int main(int argc, char **argv, char **env) 99 { 50 100 // Padre.exe path 51 101 TCHAR szExePath[MAX_PATH]; 52 // WPerl.exe path53 TCHAR szWPerl[MAX_PATH];54 102 // Padre script path 55 103 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; 62 107 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; 64 113 65 114 hModule = GetModuleHandle(NULL); 66 // Find the the executable's path115 // Find the the executable's path 67 116 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 }74 117 75 #if 076 lstrcpy(szWPerl, _T("C:\\strawberry\\perl\\bin\\wperl.exe"));77 #else78 lstrcpy(szWPerl, szExePath);79 lstrcpy(&szWPerl[dwLength+1], _T("wperl.exe"));80 #endif81 118 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); 89 123 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; 95 128 } 96 129 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; 97 140 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] 101 143 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; 106 160 } 107 161 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 124 171 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; 142 183 } 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); 144 191 } 192 PERL_SYS_TERM(); 145 193 146 // The application's return value 147 ExitProcess(0); 194 #endif 195 196 HeapFree(hHeap, 0, new_argv); 197 return exitcode; 148 198 } 149 199 /** 150 200 # 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 <assemblyIdentity5 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 <assemblyIdentity16 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:requestedExecutionLevel31 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
2 2 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 3 3 4 4 <assemblyIdentity 5 version=" 5.0.0.0"5 version="0.58.0.0" 6 6 processorArchitecture="x86" 7 name=" wperl.exe"7 name="Padre" 8 8 type="win32" 9 9 /> 10 <description> wperl</description>10 <description>Padre - The Perl IDE</description> 11 11 12 12 <!-- Enable XP/Vista-style themes --> 13 13 <dependency> … … 33 33 </ms_asmv2:security> 34 34 </ms_asmv2:trustInfo> 35 35 36 </assembly> 37 No newline at end of file 36 </assembly> -
win32/padre-rc.rc
12 12 13 13 IDI_APP ICON DISCARDABLE "padre.ico" 14 14 15 // Embed the manifest in the exe 16 // http://msdn.microsoft.com/fr-fr/library/bb773175%28en-us,VS.85%29.aspx 17 CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "padre.exe.manifest" 15 18 19 16 20 // Languages list: 17 21 // http://msdn.microsoft.com/en-us/library/dd318693%28VS.85%29.aspx 18 22 … … 20 24 LANGUAGE LANG_FRENCH, SUBLANG_FRENCH 21 25 BEGIN 22 26 IDS_APP_TITLE, "Padre" 23 IDS_ERR_WPERL, " Fichier« WPerl.exe » introuvable !"27 IDS_ERR_WPERL, "Programme « WPerl.exe » introuvable !" 24 28 IDS_ERR_SCRIPT, "Script « padre » introuvable !" 25 29 IDS_ERR_RUN, "Echec du lancement du script avec « padre » avec « WPerl.exe » !" 26 30 END -
privinc/Module/Install/PRIVATE/Padre.pm
8 8 use FindBin (); 9 9 use File::Find (); 10 10 11 # For building the Win32 launcher 12 use Config; 13 use ExtUtils::Embed; 14 11 15 our $VERSION = '0.26'; 12 16 use base qw{ Module::Install::Base }; 13 17 … … 245 249 # Create the blib/bin folder 246 250 system $^X , qw[-MExtUtils::Command -e mkpath --], $bin; 247 251 252 # TODO update the version number in win32/padre.exe.manifest 253 248 254 # 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); 250 257 251 258 # 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]; 253 260 254 # Step 3: Build padre.exe using gcc255 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); 256 263 257 # Step 4: Remove temporary files258 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; 259 266 260 # Step 5: Install XP manifest to get a themed Padre261 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); 262 269 } 263 270 264 271 1;
