source: trunk/src/peldr/pe.cpp@ 5956

Last change on this file since 5956 was 5956, checked in by sandervl, 24 years ago

Launch win16 loader for NE apps

File size: 13.0 KB
Line 
1/* $Id: pe.cpp,v 1.28 2001-06-10 22:00:04 sandervl Exp $ */
2
3/*
4 * PELDR main exe loader code
5 *
6 * Copyright 1998-2001 Sander van Leeuwen (sandervl@xs4all.nl)
7 *
8 * Command line options:
9 * /OPT:[x1=y,x2=z,..]
10 * x = CURDIR -> set current directory to y
11 * (not other options available at this time)
12 *
13 * Project Odin Software License can be found in LICENSE.TXT
14 *
15 */
16#define INCL_DOSFILEMGR /* File Manager values */
17#define INCL_DOSERRORS /* DOS Error values */
18#define INCL_DOSPROCESS /* DOS Process values */
19#define INCL_DOSMISC /* DOS Miscellanous values */
20#define INCL_DOSMODULEMGR
21#define INCL_DOSSESMGR
22#define INCL_WIN
23#include <os2.h>
24#include <bseord.h>
25#include <stdio.h>
26#include <string.h>
27#include <stdlib.h>
28#include <string.h>
29#include <assert.h>
30#include <win32type.h>
31#include <misc.h>
32#include <wprocess.h>
33#include <win\peexe.h>
34#include "pe.h"
35
36char INFO_BANNER[] = "Usage: PE winexe commandline";
37char szErrorTitle[] = "Odin";
38char szLoadErrorMsg[] = "Can't load executable";
39char szFileErrorMsg[] = "File IO error";
40char szPEErrorMsg[] = "Not a valid win32 exe. (perhaps 16 bits windows)";
41char szCPUErrorMsg[] = "Executable doesn't run on x86 machines";
42char szExeErrorMsg[] = "File isn't an executable";
43char szInteralErrorMsg[]= "Internal Error";
44char szNoKernel32Msg[] = "Can't load/find kernel32.dll (rc=%d, module %s)";
45char szDosInfoBlocks[] = "DosInfoBlocks failed!";
46char szErrDosStartSession[] = "Failed to start win16 session (rc=%d)";
47
48char fullpath[CCHMAXPATH];
49
50typedef HAB (* APIENTRY WININITIALIZEPROC)(ULONG flOptions);
51typedef BOOL (* APIENTRY WINTERMINATEPROC)(HAB hab);
52typedef HMQ (* APIENTRY WINCREATEMSGQUEUEPROC) (HAB hab, LONG cmsg);
53typedef BOOL (* APIENTRY WINDESTROYMSGQUEUEPROC) (HMQ hmq);
54typedef ULONG (* APIENTRY WINMESSAGEBOXPROC) (HWND hwndParent,
55 HWND hwndOwner,
56 PCSZ pszText,
57 PCSZ pszCaption,
58 ULONG idWindow,
59 ULONG flStyle);
60typedef void (* KRNL32EXCEPTPROC) (void *exceptframe);
61
62WININITIALIZEPROC MyWinInitialize = 0;
63WINTERMINATEPROC MyWinTerminate = 0;
64WINCREATEMSGQUEUEPROC MyWinCreateMsgQueue = 0;
65WINDESTROYMSGQUEUEPROC MyWinDestroyMsgQueue = 0;
66WINMESSAGEBOXPROC MyWinMessageBox = 0;
67KRNL32EXCEPTPROC Krnl32SetExceptionHandler = 0;
68KRNL32EXCEPTPROC Krnl32UnsetExceptionHandler = 0;
69
70//should be the same as in ..\kernel32\winexepeldr.h
71typedef BOOL (* WIN32API WIN32CTOR)(char *, char *, char *, ULONG, BOOL, BOOL);
72
73WIN32CTOR CreateWin32Exe = 0;
74ULONG reservedMemory = 0;
75BOOL fConsoleApp = FALSE;
76
77BOOL AllocateExeMem(char *filename, BOOL *fNEExe);
78
79//******************************************************************************
80//******************************************************************************
81int main(int argc, char *argv[])
82{
83 HAB hab = 0; /* PM anchor block handle */
84 HMQ hmq = 0; /* Message queue handle */
85 char exeName[CCHMAXPATH];
86 char fullpath[CCHMAXPATH];
87 char errorMod[CCHMAXPATH];
88 char *pszErrorMsg = NULL;
89 APIRET rc;
90 HMODULE hmodPMWin = 0, hmodKernel32 = 0;
91 PTIB ptib;
92 PPIB ppib;
93 char *cmdline, *win32cmdline, *peoptions, *newcmdline;
94 BOOL fQuote = FALSE, fVioConsole, fIsNEExe;
95 int nrTries = 1;
96
97 if(argc >= 2) {
98 if(DosGetInfoBlocks(&ptib, &ppib) == 0) {
99tryagain:
100 cmdline = ppib->pib_pchcmd;
101 cmdline += strlen(cmdline)+1; //skip pe.exe
102 peoptions = strstr(cmdline, "/OPT:[");
103 if(peoptions) {
104 newcmdline = strchr(peoptions, ']');
105 if(newcmdline) {
106 cmdline = newcmdline+1;
107 }
108#ifdef DEBUG
109 else _interrupt(3); //should not happen!
110#endif
111 }
112 while(*cmdline == ' ') cmdline++; //skip leading space
113 if(*cmdline == '"') {
114 cmdline++;
115 fQuote = TRUE;
116 }
117 win32cmdline = cmdline;
118
119 strncpy(exeName, cmdline, sizeof(exeName)-1);
120 exeName[sizeof(exeName)-1] = 0;
121 char *p = exeName;
122 if(fQuote) {
123 while(*p != '"' && *p != 0) p++;
124 }
125 else {
126 for(int i=0;i<nrTries;i++) {
127 while(*p != ' ' && *p != 0) p++;
128 if(*p == 0) break;
129 if(i != nrTries-1) {
130 while(*p == ' ' && *p != 0) p++;
131 }
132 }
133 }
134 *p = 0;
135 strupr(exeName);
136 cmdline = strstr(exeName, ".EXE");
137 if(cmdline) {
138 cmdline[4] = 0;
139 win32cmdline += ((ULONG)cmdline - (ULONG)exeName) + 4;
140 }
141 else {
142 win32cmdline += strlen(exeName);
143 if(strstr(exeName, ".") == NULL) {
144 strcat(exeName, ".EXE");
145 }
146 }
147 if(fQuote) win32cmdline++;
148 while(*win32cmdline == ' ') win32cmdline++; //skip spaces
149
150 cmdline = exeName + strlen(exeName) - 1;
151 while(*cmdline == ' ') cmdline--;
152 cmdline[1] = 0;
153 if(DosQueryPathInfo(exeName, FIL_QUERYFULLNAME, (PVOID)fullpath, sizeof(fullpath)) == 0) {
154 strcpy(exeName, fullpath);
155 }
156 FILESTATUS3 fstat3;
157 if(DosQueryPathInfo(exeName, FIL_STANDARD, (PVOID)&fstat3, sizeof(fstat3)))
158 {
159 nrTries++;
160 if(*win32cmdline != NULL && !fQuote) {
161 goto tryagain;
162 }
163 }
164 }
165 else {//should never happen!
166filenotfound:
167 pszErrorMsg = szDosInfoBlocks;
168 goto failerror;
169 }
170 AllocateExeMem(exeName, &fIsNEExe);
171 if(fIsNEExe) {
172 STARTDATA sdata = {0};
173 ULONG idSession;
174 PID pid;
175 sdata.Length = sizeof(sdata);
176 sdata.PgmName = "w16odin.exe";
177 strcpy(fullpath, exeName);
178 strcat(fullpath, " ");
179 strcat(fullpath, win32cmdline);
180 sdata.PgmInputs = fullpath;
181 sdata.SessionType = SSF_TYPE_WINDOWEDVDM;
182 rc = DosStartSession(&sdata, &idSession, &pid);
183 if(rc) {
184 sprintf(fullpath, szErrDosStartSession, rc);
185 pszErrorMsg = fullpath;
186 goto failerror;
187 }
188 return 0;
189 }
190 }
191
192#ifdef COMMAND_LINE_VERSION
193 if(DosGetInfoBlocks(&ptib, &ppib) == 0) {
194 //switch process type to PM so the command line app can create PM
195 //windows
196 ppib->pib_ultype = 3;
197 }
198#endif
199
200 rc = DosLoadModule(exeName, sizeof(exeName), "PMWIN.DLL", &hmodPMWin);
201 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32INITIALIZE, NULL, (PFN *)&MyWinInitialize);
202 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32TERMINATE, NULL, (PFN *)&MyWinTerminate);
203 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32CREATEMSGQUEUE, NULL, (PFN *)&MyWinCreateMsgQueue);
204 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32DESTROYMSGQUEUE, NULL, (PFN *)&MyWinDestroyMsgQueue);
205 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32MESSAGEBOX, NULL, (PFN *)&MyWinMessageBox);
206
207 if ((hab = MyWinInitialize(0)) == 0L) /* Initialize PM */
208 goto fail;
209
210 hmq = MyWinCreateMsgQueue(hab, 0);
211
212 if(argc < 2) {
213 MyWinMessageBox(HWND_DESKTOP, NULL, INFO_BANNER, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
214 goto fail;
215 }
216
217 errorMod[0] = 0;
218 rc = DosLoadModule(errorMod, sizeof(errorMod), "KERNEL32.DLL", &hmodKernel32);
219 if(rc) {
220 sprintf(fullpath, szNoKernel32Msg, rc, errorMod);
221 MyWinMessageBox(HWND_DESKTOP, NULL, fullpath, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
222 goto fail;
223 }
224 rc = DosQueryProcAddr(hmodKernel32, 0, "_CreateWin32PeLdrExe@24", (PFN *)&CreateWin32Exe);
225
226#ifdef COMMAND_LINE_VERSION
227 fVioConsole = TRUE;
228#else
229 fVioConsole = FALSE;
230#endif
231 if(CreateWin32Exe(exeName, win32cmdline, peoptions, reservedMemory, fConsoleApp, fVioConsole) == FALSE) {
232 goto fail;
233 }
234
235 if(hmq) MyWinDestroyMsgQueue( hmq ); /* Tidy up... */
236 MyWinTerminate( hab ); /* Terminate the application */
237
238 DosFreeModule(hmodPMWin);
239 DosFreeModule(hmodKernel32);
240 return 0;
241
242fail:
243 if(hmq) MyWinDestroyMsgQueue( hmq ); /* Tidy up... */
244 if(hab) MyWinTerminate( hab ); /* Terminate the application */
245
246 if(hmodPMWin) DosFreeModule(hmodPMWin);
247 if(hmodKernel32) DosFreeModule(hmodKernel32);
248 return(1);
249
250failerror:
251 rc = DosLoadModule(exeName, sizeof(exeName), "PMWIN.DLL", &hmodPMWin);
252 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32INITIALIZE, NULL, (PFN *)&MyWinInitialize);
253 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32TERMINATE, NULL, (PFN *)&MyWinTerminate);
254 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32CREATEMSGQUEUE, NULL, (PFN *)&MyWinCreateMsgQueue);
255 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32DESTROYMSGQUEUE, NULL, (PFN *)&MyWinDestroyMsgQueue);
256 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32MESSAGEBOX, NULL, (PFN *)&MyWinMessageBox);
257 if(rc == 0) {
258 if ((hab = MyWinInitialize(0)) == 0L) /* Initialize PM */
259 goto fail;
260
261 hmq = MyWinCreateMsgQueue(hab, 0);
262
263 MyWinMessageBox(HWND_DESKTOP, NULL, pszErrorMsg, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
264 }
265 if(hmq) MyWinDestroyMsgQueue( hmq ); /* Tidy up... */
266 if(hab) MyWinTerminate( hab ); /* Terminate the application */
267 if(hmodPMWin) DosFreeModule(hmodPMWin);
268 return 1;
269}
270//******************************************************************************
271//SvL: Reserve memory for win32 exes without fixups
272// This is done before any Odin or PMWIN dll is loaded, so we'll get
273// a very low virtual address. (which is exactly what we want)
274//******************************************************************************
275BOOL AllocateExeMem(char *filename, BOOL *fNEExe)
276{
277 HFILE dllfile = 0;
278 char szFileName[CCHMAXPATH], *tmp;
279 char szResult[CCHMAXPATH];
280 ULONG action, ulRead, signature;
281 APIRET rc;
282 IMAGE_DOS_HEADER doshdr;
283 IMAGE_OPTIONAL_HEADER oh;
284 IMAGE_FILE_HEADER fh;
285 ULONG address = 0;
286 ULONG *memallocs;
287 ULONG alloccnt = 0;
288 ULONG diff, i, baseAddress;
289 ULONG ulSysinfo, flAllocMem = 0;
290 BOOL ret = FALSE;
291
292 *fNEExe = FALSE;
293 strcpy(szFileName, filename);
294
295 rc = DosOpen(szFileName, &dllfile, &action, 0, FILE_READONLY, OPEN_ACTION_OPEN_IF_EXISTS|OPEN_ACTION_FAIL_IF_NEW, OPEN_SHARE_DENYNONE|OPEN_ACCESS_READONLY, NULL);
296 if(rc != 0) {
297 if(!strstr(szFileName, ".EXE")) {
298 strcat(szFileName,".EXE");
299 }
300 }
301 else DosClose(dllfile);
302
303 rc = DosOpen(szFileName, &dllfile, &action, 0, FILE_READONLY, OPEN_ACTION_OPEN_IF_EXISTS|OPEN_ACTION_FAIL_IF_NEW, OPEN_SHARE_DENYNONE|OPEN_ACCESS_READONLY, NULL);
304 if(rc) {
305 if(DosSearchPath(SEARCH_IGNORENETERRS|SEARCH_ENVIRONMENT, "PATH",
306 szFileName, szResult, sizeof(szResult)) != 0) {
307 goto end; //oops
308 }
309 rc = DosOpen(szResult, &dllfile, &action, 0, FILE_READONLY, OPEN_ACTION_OPEN_IF_EXISTS|OPEN_ACTION_FAIL_IF_NEW, OPEN_SHARE_DENYNONE|OPEN_ACCESS_READONLY, NULL);
310 if(rc) {
311 goto end; //oops
312 }
313 }
314
315 //read dos header
316 if(DosRead(dllfile, (LPVOID)&doshdr, sizeof(doshdr), &ulRead)) {
317 goto end;
318 }
319 if(DosSetFilePtr(dllfile, doshdr.e_lfanew, FILE_BEGIN, &ulRead)) {
320 goto end;
321 }
322 //read signature dword
323 if(DosRead(dllfile, (LPVOID)&signature, sizeof(signature), &ulRead)) {
324 goto end;
325 }
326 //read pe header
327 if(DosRead(dllfile, (LPVOID)&fh, sizeof(fh), &ulRead)) {
328 goto end;
329 }
330 //read optional header
331 if(DosRead(dllfile, (LPVOID)&oh, sizeof(oh), &ulRead)) {
332 goto end;
333 }
334 if(doshdr.e_magic != IMAGE_DOS_SIGNATURE || signature != IMAGE_NT_SIGNATURE) {
335 if(LOWORD(signature) == IMAGE_OS2_SIGNATURE) {
336 *fNEExe = TRUE;
337 }
338 goto end;
339 }
340 fConsoleApp = (oh.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI);
341
342 // check for high memory support
343 rc = DosQuerySysInfo(QSV_VIRTUALADDRESSLIMIT, QSV_VIRTUALADDRESSLIMIT, &ulSysinfo, sizeof(ulSysinfo));
344 if (rc == 0 && ulSysinfo > 512) //VirtualAddresslimit is in MB
345 {
346 flAllocMem = PAG_ANY; // high memory support. Let's use it!
347 }
348
349 //Reserve enough space to store 4096 pointers to 1MB memory chunks
350 memallocs = (ULONG *)alloca(4096*sizeof(ULONG *));
351 if(memallocs == NULL) {
352 goto end; //oops
353 }
354
355 if(oh.ImageBase < 512*1024*1024) {
356 flAllocMem = 0;
357 }
358 else {
359 if(flAllocMem == 0) {
360 goto end; //no support for > 512 MB
361 }
362 }
363 while(TRUE) {
364 rc = DosAllocMem((PPVOID)&address, FALLOC_SIZE, PAG_READ | flAllocMem);
365 if(rc) break;
366
367 if(address + FALLOC_SIZE >= oh.ImageBase) {
368 if(address > oh.ImageBase) {//we've passed it!
369 DosFreeMem((PVOID)address);
370 break;
371 }
372 //found the right address
373 DosFreeMem((PVOID)address);
374
375 diff = oh.ImageBase - address;
376 if(diff) {
377 rc = DosAllocMem((PPVOID)&address, diff, PAG_READ | flAllocMem);
378 if(rc) break;
379 }
380 rc = DosAllocMem((PPVOID)&baseAddress, oh.SizeOfImage, PAG_READ | PAG_WRITE | flAllocMem);
381 if(rc) break;
382
383 if(diff) DosFreeMem((PVOID)address);
384
385 reservedMemory = baseAddress;
386 break;
387 }
388 memallocs[alloccnt++] = address;
389 }
390 for(i=0;i<alloccnt;i++) {
391 DosFreeMem((PVOID)memallocs[i]);
392 }
393 ret = TRUE;
394end:
395 if(dllfile) DosClose(dllfile);
396 return ret;
397}
398//******************************************************************************
399//******************************************************************************
Note: See TracBrowser for help on using the repository browser.