Changeset 3160 for trunk/src/kernel32/wprocess.cpp
- Timestamp:
- Mar 18, 2000, 8:49:44 PM (25 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kernel32/wprocess.cpp
r3140 r3160 1 /* $Id: wprocess.cpp,v 1.7 4 2000-03-17 16:08:40sandervl Exp $ */1 /* $Id: wprocess.cpp,v 1.75 2000-03-18 19:49:44 sandervl Exp $ */ 2 2 3 3 /* … … 42 42 #include "mmap.h" 43 43 44 #define DBG_LOCALLOG 44 #define DBG_LOCALLOG DBG_wprocess 45 45 #include "dbglocal.h" 46 46 … … 65 65 TEB *WIN32API GetThreadTEB() 66 66 { 67 if(TIBFlatPtr == NULL)68 return 0;69 70 return (TEB *)*TIBFlatPtr;67 if(TIBFlatPtr == NULL) 68 return 0; 69 70 return (TEB *)*TIBFlatPtr; 71 71 } 72 72 //****************************************************************************** … … 77 77 THDB *thdb; 78 78 79 if(TIBFlatPtr == NULL)80 return 0;81 82 winteb = (TEB *)*TIBFlatPtr;83 if(winteb == NULL) {84 return NULL;85 }86 thdb = (THDB *)(winteb+1);87 88 return thdb;79 if(TIBFlatPtr == NULL) 80 return 0; 81 82 winteb = (TEB *)*TIBFlatPtr; 83 if(winteb == NULL) { 84 return NULL; 85 } 86 thdb = (THDB *)(winteb+1); 87 88 return thdb; 89 89 } 90 90 //****************************************************************************** … … 94 94 THDB *thdb = threadList; 95 95 96 threadListMutex.enter();97 while(thdb) {98 99 100 101 102 }103 threadListMutex.leave();104 return thdb;96 threadListMutex.enter(); 97 while(thdb) { 98 if(thdb->threadId == threadId) { 99 break; 100 } 101 thdb = thdb->next; 102 } 103 threadListMutex.leave(); 104 return thdb; 105 105 } 106 106 //****************************************************************************** … … 110 110 THDB *thdb = threadList; 111 111 112 threadListMutex.enter();113 while(thdb) {114 115 116 117 118 }119 threadListMutex.leave();120 return thdb;112 threadListMutex.enter(); 113 while(thdb) { 114 if(thdb->hThread == hThread) { 115 break; 116 } 117 thdb = thdb->next; 118 } 119 threadListMutex.leave(); 120 return thdb; 121 121 } 122 122 //****************************************************************************** … … 130 130 USHORT tibsel; 131 131 132 //Allocate one dword to store the flat address of our TEB133 if(fMainThread) {134 135 136 137 138 139 132 //Allocate one dword to store the flat address of our TEB 133 if(fMainThread) { 134 TIBFlatPtr = (DWORD *)OSLibAllocThreadLocalMemory(1); 135 if(TIBFlatPtr == 0) { 136 dprintf(("InitializeTIB: local thread memory alloc failed!!")); 137 DebugInt3(); 138 return NULL; 139 } 140 140 //SvL: This doesn't really create a thread, but only sets up the 141 141 // handle of thread 0 142 143 }144 if(OSLibAllocSel(PAGE_SIZE, &tibsel) == FALSE)145 {146 147 148 149 }150 winteb = (TEB *)OSLibSelToFlat(tibsel);151 if(winteb == NULL)152 {153 154 155 156 }157 memset(winteb, 0, PAGE_SIZE);158 thdb = (THDB *)(winteb+1);159 *TIBFlatPtr = (DWORD)winteb;160 161 winteb->except = (PVOID)-1; /* 00 Head of exception handling chain */162 winteb->stack_top = (PVOID)OSLibGetTIB(TIB_STACKTOP); /* 04 Top of thread stack */163 winteb->stack_low = (PVOID)OSLibGetTIB(TIB_STACKLOW); /* 08 Stack low-water mark */164 winteb->htask16 = (USHORT)OSLibGetPIB(PIB_TASKHNDL); /* 0c Win16 task handle */165 winteb->stack_sel = getSS(); /* 0e 16-bit stack selector */166 winteb->self = winteb; /* 18 Pointer to this structure */167 winteb->flags = TEBF_WIN32; /* 1c Flags */168 winteb->queue = 0; /* 28 Message queue */169 winteb->tls_ptr = &thdb->tls_array[0]; /* 2c Pointer to TLS array */170 winteb->process = &ProcessPDB; /* 30 owning process (used by NT3.51 applets)*/171 172 memcpy(&thdb->teb, winteb, sizeof(TEB));173 thdb->process = &ProcessPDB;174 thdb->exit_code = 0x103; /* STILL_ACTIVE */175 thdb->teb_sel = tibsel;176 thdb->OrgTIBSel = GetFS();177 thdb->pWsockData = NULL;178 thdb->threadId = GetCurrentThreadId();179 if(fMainThread) {180 181 }182 else thdb->hThread = GetCurrentThread();183 184 threadListMutex.enter();185 THDB *thdblast = threadList;186 if(!thdblast) {187 188 }189 else {190 191 192 193 194 }195 thdb->next = NULL;196 threadListMutex.leave();197 198 if(OSLibGetPIB(PIB_TASKTYPE) == TASKTYPE_PM)199 {200 201 }202 else thdb->flags = 0; //todo textmode203 204 if(fMainThread)205 {206 //todo initialize PDB during process creation142 hThreadMain = HMCreateThread(NULL, 0, 0, 0, 0, 0, TRUE); 143 } 144 if(OSLibAllocSel(PAGE_SIZE, &tibsel) == FALSE) 145 { 146 dprintf(("InitializeTIB: selector alloc failed!!")); 147 DebugInt3(); 148 return NULL; 149 } 150 winteb = (TEB *)OSLibSelToFlat(tibsel); 151 if(winteb == NULL) 152 { 153 dprintf(("InitializeTIB: DosSelToFlat failed!!")); 154 DebugInt3(); 155 return NULL; 156 } 157 memset(winteb, 0, PAGE_SIZE); 158 thdb = (THDB *)(winteb+1); 159 *TIBFlatPtr = (DWORD)winteb; 160 161 winteb->except = (PVOID)-1; /* 00 Head of exception handling chain */ 162 winteb->stack_top = (PVOID)OSLibGetTIB(TIB_STACKTOP); /* 04 Top of thread stack */ 163 winteb->stack_low = (PVOID)OSLibGetTIB(TIB_STACKLOW); /* 08 Stack low-water mark */ 164 winteb->htask16 = (USHORT)OSLibGetPIB(PIB_TASKHNDL); /* 0c Win16 task handle */ 165 winteb->stack_sel = getSS(); /* 0e 16-bit stack selector */ 166 winteb->self = winteb; /* 18 Pointer to this structure */ 167 winteb->flags = TEBF_WIN32; /* 1c Flags */ 168 winteb->queue = 0; /* 28 Message queue */ 169 winteb->tls_ptr = &thdb->tls_array[0]; /* 2c Pointer to TLS array */ 170 winteb->process = &ProcessPDB; /* 30 owning process (used by NT3.51 applets)*/ 171 172 memcpy(&thdb->teb, winteb, sizeof(TEB)); 173 thdb->process = &ProcessPDB; 174 thdb->exit_code = 0x103; /* STILL_ACTIVE */ 175 thdb->teb_sel = tibsel; 176 thdb->OrgTIBSel = GetFS(); 177 thdb->pWsockData = NULL; 178 thdb->threadId = GetCurrentThreadId(); 179 if(fMainThread) { 180 thdb->hThread = hThreadMain; 181 } 182 else thdb->hThread = GetCurrentThread(); 183 184 threadListMutex.enter(); 185 THDB *thdblast = threadList; 186 if(!thdblast) { 187 threadList = thdb; 188 } 189 else { 190 while(thdblast->next) { 191 thdblast = thdblast->next; 192 } 193 thdblast->next = thdb; 194 } 195 thdb->next = NULL; 196 threadListMutex.leave(); 197 198 if(OSLibGetPIB(PIB_TASKTYPE) == TASKTYPE_PM) 199 { 200 thdb->flags = 0; //todo gui 201 } 202 else thdb->flags = 0; //todo textmode 203 204 if(fMainThread) 205 { 206 //todo initialize PDB during process creation 207 207 //todo: initialize TLS array if required 208 208 //TLS in executable always TLS index 0? 209 209 ProcessTIBSel = tibsel; 210 210 ProcessPDB.exit_code = 0x103; /* STILL_ACTIVE */ 211 211 ProcessPDB.threads = 1; … … 221 221 ProcessPDB.server_pid = (void *)GetCurrentProcessId(); 222 222 223 223 GetSystemTime(&ProcessPDB.creationTime); 224 224 225 225 /* Initialize the critical section */ 226 226 InitializeCriticalSection( &ProcessPDB.crit_section ); 227 }228 dprintf(("InitializeTIB setup TEB with selector %x", tibsel));229 dprintf(("InitializeTIB: FS(%x):[0] = %x", GetFS(), QueryExceptionChain()));230 return winteb;227 } 228 dprintf(("InitializeTIB setup TEB with selector %x", tibsel)); 229 dprintf(("InitializeTIB: FS(%x):[0] = %x", GetFS(), QueryExceptionChain())); 230 return winteb; 231 231 } 232 232 //****************************************************************************** … … 239 239 THDB *thdb; 240 240 241 dprintf(("DestroyTIB: FS = %x", GetFS()));242 dprintf(("DestroyTIB: FS:[0] = %x", QueryExceptionChain()));243 244 winteb = (TEB *)*TIBFlatPtr;245 if(winteb) {246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 241 dprintf(("DestroyTIB: FS = %x", GetFS())); 242 dprintf(("DestroyTIB: FS:[0] = %x", QueryExceptionChain())); 243 244 winteb = (TEB *)*TIBFlatPtr; 245 if(winteb) { 246 thdb = (THDB *)(winteb+1); 247 orgtibsel = thdb->OrgTIBSel; 248 249 threadListMutex.enter(); 250 THDB *curthdb = threadList; 251 if(curthdb == thdb) { 252 threadList = thdb->next; 253 } 254 else { 255 while(curthdb->next != thdb) { 256 curthdb = curthdb->next; 257 if(curthdb == NULL) { 258 dprintf(("DestroyTIB: couldn't find thdb %x", thdb)); 259 DebugInt3(); 260 break; 261 } 262 } 263 if(curthdb) { 264 curthdb->next = thdb->next; 265 } 266 } 267 threadListMutex.leave(); 268 269 //Restore our original FS selector 270 270 SetFS(orgtibsel); 271 271 … … 273 273 OSLibFreeSel(thdb->teb_sel); 274 274 275 275 *TIBFlatPtr = 0; 276 276 } 277 277 else dprintf(("Already destroyed TIB")); … … 284 284 void SetPDBInstance(HINSTANCE hInstance) 285 285 { 286 ProcessPDB.hInstance = hInstance;286 ProcessPDB.hInstance = hInstance; 287 287 } 288 288 /******************************************************************************/ … … 296 296 //If we're running an Odin32 OS/2 application (not converted!), then we 297 297 //we don't switch FS selectors 298 if(fIsOS2Image) {299 return;300 }301 302 winteb = (TEB *)*TIBFlatPtr;303 if(winteb) {304 thdb = (THDB *)(winteb+1);305 orgtibsel = thdb->OrgTIBSel;306 307 //Restore our original FS selector298 if(fIsOS2Image) { 299 return; 300 } 301 302 winteb = (TEB *)*TIBFlatPtr; 303 if(winteb) { 304 thdb = (THDB *)(winteb+1); 305 orgtibsel = thdb->OrgTIBSel; 306 307 //Restore our original FS selector 308 308 SetFS(orgtibsel); 309 }309 } 310 310 } 311 311 /******************************************************************************/ … … 317 317 THDB *thdb; 318 318 319 //If we're running an Odin32 OS/2 application (not converted!), then we 320 //we don't switch FS selectors 321 if(fIsOS2Image) { 319 //If we're running an Odin32 OS/2 application (not converted!), then we 320 //we don't switch FS selectors 321 if(fIsOS2Image) { 322 return GetFS(); 323 } 324 325 winteb = (TEB *)*TIBFlatPtr; 326 if(winteb) { 327 thdb = (THDB *)(winteb+1); 328 win32tibsel = thdb->teb_sel; 329 330 //Restore our win32 FS selector 331 return SetReturnFS(win32tibsel); 332 } 333 else { 334 //we didn't create this thread, so allocate a selector now 335 //NOTE: Possible memory leak (i.e. DART threads in WINMM) 336 winteb = InitializeTIB(); 337 if(winteb == NULL) { 338 DebugInt3(); 339 return GetFS(); 340 } 341 thdb = (THDB *)(winteb+1); 342 win32tibsel = thdb->teb_sel; 343 344 //Restore our win32 FS selector 345 return SetReturnFS(win32tibsel); 346 } 347 // nested calls are OK, OS2ToWinCallback for instance 348 //else DebugInt3(); 349 322 350 return GetFS(); 323 }324 325 winteb = (TEB *)*TIBFlatPtr;326 if(winteb) {327 thdb = (THDB *)(winteb+1);328 win32tibsel = thdb->teb_sel;329 330 //Restore our win32 FS selector331 return SetReturnFS(win32tibsel);332 }333 else {334 //we didn't create this thread, so allocate a selector now335 //NOTE: Possible memory leak (i.e. DART threads in WINMM)336 winteb = InitializeTIB();337 if(winteb == NULL) {338 DebugInt3();339 return GetFS();340 }341 thdb = (THDB *)(winteb+1);342 win32tibsel = thdb->teb_sel;343 344 //Restore our win32 FS selector345 return SetReturnFS(win32tibsel);346 }347 // nested calls are OK, OS2ToWinCallback for instance348 //else DebugInt3();349 350 return GetFS();351 351 } 352 352 //****************************************************************************** … … 354 354 VOID WIN32API ExitProcess(DWORD exitcode) 355 355 { 356 dprintf(("KERNEL32: ExitProcess %d\n", exitcode));357 dprintf(("KERNEL32: ExitProcess FS = %x\n", GetFS()));358 359 SetOS2ExceptionChain(-1);360 361 if(WinExe) {362 363 364 }365 366 //Note: Needs to be done after deleting WinExe (destruction of exe + dll objects)367 //Flush and delete all open memory mapped files368 Win32MemMap::deleteAll();369 370 //Restore original OS/2 TIB selector371 DestroyTIB();372 SetExceptionChain((ULONG)-1);373 374 //avoid crashes since win32 & OS/2 exception handler aren't identical375 //(terminate process generates two exceptions)376 /* @@@PH 1998/02/12 Added Console Support */377 if (iConsoleIsActive())378 iConsoleWaitClose();379 380 O32_ExitProcess(exitcode);356 dprintf(("KERNEL32: ExitProcess %d\n", exitcode)); 357 dprintf(("KERNEL32: ExitProcess FS = %x\n", GetFS())); 358 359 SetOS2ExceptionChain(-1); 360 361 if(WinExe) { 362 delete(WinExe); 363 WinExe = NULL; 364 } 365 366 //Note: Needs to be done after deleting WinExe (destruction of exe + dll objects) 367 //Flush and delete all open memory mapped files 368 Win32MemMap::deleteAll(); 369 370 //Restore original OS/2 TIB selector 371 DestroyTIB(); 372 SetExceptionChain((ULONG)-1); 373 374 //avoid crashes since win32 & OS/2 exception handler aren't identical 375 //(terminate process generates two exceptions) 376 /* @@@PH 1998/02/12 Added Console Support */ 377 if (iConsoleIsActive()) 378 iConsoleWaitClose(); 379 380 O32_ExitProcess(exitcode); 381 381 } 382 382 //****************************************************************************** … … 387 387 BOOL rc; 388 388 389 winmod = Win32DllBase::findModule(hinstance);390 if(winmod) {391 392 393 394 395 389 winmod = Win32DllBase::findModule(hinstance); 390 if(winmod) { 391 dprintf(("FreeLibrary %s", winmod->getName())); 392 //Only free it when the nrDynamicLibRef != 0 393 //This prevent problems after ExitProcess: 394 //i.e. dll A is referenced by our exe and loaded with LoadLibrary by dll B 395 // During ExitProcess it's unloaded once (before dll B), dll B calls 396 396 // FreeLibrary, but our exe also has a reference -> unloaded too many times 397 398 399 400 401 402 403 397 if(winmod->isDynamicLib()) { 398 winmod->decDynamicLib(); 399 winmod->Release(); 400 } 401 else { 402 dprintf(("Skipping dynamic unload as nrDynamicLibRef == 0")); 403 } 404 404 return(TRUE); 405 }406 dprintf(("KERNEL32: FreeLibrary %s %X\n", OSLibGetDllName(hinstance), hinstance));407 408 //TODO: Not thread safe409 fFreeLibrary = TRUE; //ditch dll410 rc = O32_FreeLibrary(hinstance);411 fFreeLibrary = FALSE;412 dprintf(("FreeLibrary returned %X\n", rc));413 return(TRUE);405 } 406 dprintf(("KERNEL32: FreeLibrary %s %X\n", OSLibGetDllName(hinstance), hinstance)); 407 408 //TODO: Not thread safe 409 fFreeLibrary = TRUE; //ditch dll 410 rc = O32_FreeLibrary(hinstance); 411 fFreeLibrary = FALSE; 412 dprintf(("FreeLibrary returned %X\n", rc)); 413 return(TRUE); 414 414 } 415 415 /******************************************************************************/ … … 421 421 Win32DllBase *module; 422 422 423 module = Win32DllBase::findModule((LPSTR)lpszLibFile);424 if(module) {425 426 427 428 429 430 431 432 423 module = Win32DllBase::findModule((LPSTR)lpszLibFile); 424 if(module) { 425 if(module->isLxDll() && !module->isLoaded() && !fPe2Lx) { 426 //can happen with i.e. wininet 427 //wininet depends on wsock32; when the app loads wsock32 afterwards 428 //with LoadLibrary or as a child of another dll, we need to make 429 //sure it's loaded once with DosLoadModule 430 module->setLoadLibrary(); 431 } 432 module->incDynamicLib(); 433 433 module->AddRef(); 434 434 dprintf(("iLoadLibrary: found %s -> handle %x", lpszLibFile, module->getInstanceHandle())); 435 435 return module->getInstanceHandle(); 436 }437 438 strcpy(modname, lpszLibFile);439 strupr(modname);440 //rename dll if necessary (i.e. OLE32 -> OLE32OS2)441 Win32DllBase::renameDll(modname);442 443 hDll = O32_LoadLibrary(modname);444 dprintf(("KERNEL32: iLoadLibraryA %s returned %X (%d)\n",436 } 437 438 strcpy(modname, lpszLibFile); 439 strupr(modname); 440 //rename dll if necessary (i.e. OLE32 -> OLE32OS2) 441 Win32DllBase::renameDll(modname); 442 443 hDll = O32_LoadLibrary(modname); 444 dprintf(("KERNEL32: iLoadLibraryA %s returned %X (%d)\n", 445 445 lpszLibFile, 446 446 hDll, 447 447 GetLastError())); 448 if(hDll)449 {450 451 452 453 454 455 456 457 458 459 }460 461 if(!strstr(modname, ".")) {462 463 }464 465 if(Win32ImageBase::isPEImage((char *)modname))466 {448 if(hDll) 449 { 450 module = Win32DllBase::findModule(hDll); 451 if(module && module->isLxDll() && !fPe2Lx) { 452 module->setLoadLibrary(); 453 module->AddRef(); 454 } 455 if(module) 456 module->incDynamicLib(); 457 //system dll, converted dll or win32k took care of it 458 return hDll; 459 } 460 461 if(!strstr(modname, ".")) { 462 strcat(modname,".DLL"); 463 } 464 465 if(Win32ImageBase::isPEImage((char *)modname)) 466 { 467 467 module = Win32DllBase::findModule((char *)modname); 468 468 if(module) {//don't load it again 469 469 module->incDynamicLib(); 470 470 module->AddRef(); 471 471 return module->getInstanceHandle(); … … 494 494 } 495 495 return peldrDll->getInstanceHandle(); 496 }497 else return(0);496 } 497 else return(0); 498 498 } 499 499 //****************************************************************************** … … 501 501 HINSTANCE16 WIN32API LoadLibrary16(LPCTSTR lpszLibFile) 502 502 { 503 504 503 dprintf(("ERROR: LoadLibrary16 %s, not implemented", lpszLibFile)); 504 return 0; 505 505 } 506 506 //****************************************************************************** … … 508 508 VOID WIN32API FreeLibrary16(HINSTANCE16 hinstance) 509 509 { 510 510 dprintf(("ERROR: FreeLibrary16 %x, not implemented", hinstance)); 511 511 } 512 512 //****************************************************************************** … … 514 514 FARPROC WIN32API GetProcAddress16(HMODULE hModule, LPCSTR lpszProc) 515 515 { 516 517 516 dprintf(("ERROR: GetProcAddress16 %x %x, not implemented", hModule, lpszProc)); 517 return 0; 518 518 } 519 519 //****************************************************************************** … … 523 523 HINSTANCE hDll; 524 524 525 dprintf(("KERNEL32: LoadLibraryA(%s)\n",525 dprintf(("KERNEL32: LoadLibraryA(%s)\n", 526 526 lpszLibFile)); 527 dprintf(("KERNEL32: LoadLibrary %x FS = %x\n", GetCurrentThreadId(), GetFS())); 528 529 hDll = iLoadLibraryA(lpszLibFile, 0); 527 dprintf(("KERNEL32: LoadLibrary %x FS = %x\n", GetCurrentThreadId(), GetFS())); 528 529 hDll = iLoadLibraryA(lpszLibFile, 0); 530 if (hDll == 0) 531 { 532 char * pszName; 533 534 // remove path from the image name 535 pszName = strrchr((char *)lpszLibFile, 536 '\\'); 537 if (pszName != NULL) 538 { 539 pszName++; // skip backslash 540 541 // now try again without fully qualified path 542 hDll = iLoadLibraryA(pszName, 0); 543 } 544 } 545 546 return hDll; 547 } 548 //****************************************************************************** 549 //****************************************************************************** 550 HINSTANCE WIN32API LoadLibraryExA(LPCTSTR lpszLibFile, HANDLE hFile, DWORD dwFlags) 551 { 552 HINSTANCE hDll; 553 554 dprintf(("KERNEL32: LoadLibraryExA %s (%X)\n", lpszLibFile, dwFlags)); 555 hDll = iLoadLibraryA(lpszLibFile, dwFlags); 530 556 if (hDll == 0) 531 557 { … … 540 566 541 567 // now try again without fully qualified path 542 hDll = iLoadLibraryA(pszName, 0);543 }544 }545 546 return hDll;547 }548 //******************************************************************************549 //******************************************************************************550 HINSTANCE WIN32API LoadLibraryExA(LPCTSTR lpszLibFile, HANDLE hFile, DWORD dwFlags)551 {552 HINSTANCE hDll;553 554 dprintf(("KERNEL32: LoadLibraryExA %s (%X)\n", lpszLibFile, dwFlags));555 hDll = iLoadLibraryA(lpszLibFile, dwFlags);556 if (hDll == 0)557 {558 char * pszName;559 560 // remove path from the image name561 pszName = strrchr((char *)lpszLibFile,562 '\\');563 if (pszName != NULL)564 {565 pszName++; // skip backslash566 567 // now try again without fully qualified path568 568 hDll = iLoadLibraryA(pszName, dwFlags); 569 569 } … … 627 627 628 628 if(WinExe) { 629 630 629 if(WinExe->getCommandLineW()) 630 return WinExe->getCommandLineW(); 631 631 } 632 632 if(asciicmdline == NULL) //not used for converted exes … … 852 852 PSECURITY_ATTRIBUTES lpThreadAttributes, 853 853 BOOL bInheritHandles, DWORD dwCreationFlags, 854 LPVOID lpEnvironment, 854 LPVOID lpEnvironment, 855 855 LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, 856 856 LPPROCESS_INFORMATION lpProcessInfo) … … 861 861 dprintf(("KERNEL32: CreateProcessW")); 862 862 if(lpApplicationName) 863 863 astring1 = UnicodeToAsciiString((LPWSTR)lpApplicationName); 864 864 if(lpCommandLine) 865 865 astring2 = UnicodeToAsciiString(lpCommandLine); 866 866 if(lpCurrentDirectory) 867 867 astring3 = UnicodeToAsciiString((LPWSTR)lpCurrentDirectory); 868 868 rc = CreateProcessA(astring1, astring2, lpProcessAttributes, lpThreadAttributes, 869 869 bInheritHandles, dwCreationFlags, lpEnvironment, 870 astring3, (LPSTARTUPINFOA)lpStartupInfo, 870 astring3, (LPSTARTUPINFOA)lpStartupInfo, 871 871 lpProcessInfo); 872 if(astring3) 873 if(astring2) 874 if(astring1) 872 if(astring3) FreeAsciiString(astring3); 873 if(astring2) FreeAsciiString(astring2); 874 if(astring1) FreeAsciiString(astring1); 875 875 return(rc); 876 876 } … … 888 888 &startinfo, &procinfo) == FALSE) 889 889 { 890 890 return 0; 891 891 } 892 892 //block until the launched app waits for input (or a timeout of 15 seconds) … … 894 894 rc = O32_WaitForInputIdle(procinfo.hProcess, 15000); 895 895 if(rc != 0) { 896 896 dprintf(("WinExec: WaitForInputIdle %x returned %x", procinfo.hProcess, rc)); 897 897 } 898 898 return procinfo.hProcess; //correct?
Note:
See TracChangeset
for help on using the changeset viewer.