Exit process if the primary thread is detached
Processes on Windows 10 that return rather than call `ExitProcess` may have a 30 second delay before terminating. This seems due to the console creating a thread. Detect a detached primary thread and explicitly call `ExitProcess`.
This commit is contained in:
parent
3c97a6e4e7
commit
d7a2be9964
44
ANSI.c
44
ANSI.c
@ -197,11 +197,12 @@
|
||||
v1.83, 16 February, 2018:
|
||||
create the flush thread on first use.
|
||||
|
||||
v1.84-wip, 17 February, 26 to 30 April, 2018:
|
||||
v1.84-wip, 17 February, 26 April to 2 May, 2018:
|
||||
close the flush handles on detach;
|
||||
dynamically load WINMM.DLL;
|
||||
use sprintf/_snprintf/_snwprintf instead of wsprintf, avoiding USER32.DLL;
|
||||
replace bsearch (in procrva.c) with specific code.
|
||||
replace bsearch (in procrva.c) with specific code;
|
||||
if the primary thread is detached exit the process.
|
||||
*/
|
||||
|
||||
#include "ansicon.h"
|
||||
@ -3859,6 +3860,19 @@ void OriginalAttr( PVOID lpReserved )
|
||||
}
|
||||
|
||||
|
||||
// A Win10 process that returns (rather than calling ExitProcess) may have a 30
|
||||
// second delay before terminating. This seems due to another thread being
|
||||
// created for the console. If the primary thread is detached, wait for it to
|
||||
// finish, then explicitly exit.
|
||||
DWORD WINAPI exit_thread( LPVOID lpParameter )
|
||||
{
|
||||
DWORD rc;
|
||||
WaitForSingleObject( lpParameter, 30000 );
|
||||
GetExitCodeThread( lpParameter, &rc );
|
||||
ExitProcess( rc );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// DllMain()
|
||||
// Function called by the system when processes and threads are initialized
|
||||
@ -3874,6 +3888,7 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
|
||||
TCHAR logstr[4];
|
||||
typedef LONG (WINAPI *PNTQIT)( HANDLE, int, PVOID, ULONG, PULONG );
|
||||
static PNTQIT NtQueryInformationThread;
|
||||
static DWORD primary_tid;
|
||||
|
||||
if (dwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
@ -3917,11 +3932,16 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
|
||||
|
||||
NtQueryInformationThread = (PNTQIT)GetProcAddress(
|
||||
GetModuleHandle( L"ntdll.dll" ), "NtQueryInformationThread" );
|
||||
if (NtQueryInformationThread == NULL)
|
||||
DisableThreadLibraryCalls( hInstance );
|
||||
|
||||
InitializeCriticalSection( &CritSect );
|
||||
hFlushTimer = CreateWaitableTimer( NULL, FALSE, NULL );
|
||||
|
||||
// If it's a static load, assume this is the primary thread.
|
||||
if (lpReserved)
|
||||
primary_tid = GetCurrentThreadId();
|
||||
|
||||
if (NtQueryInformationThread == NULL && primary_tid == 0)
|
||||
DisableThreadLibraryCalls( hInstance );
|
||||
}
|
||||
else if (dwReason == DLL_PROCESS_DETACH)
|
||||
{
|
||||
@ -3964,9 +3984,19 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
|
||||
else if (dwReason == DLL_THREAD_DETACH)
|
||||
{
|
||||
PVOID start;
|
||||
if (NtQueryInformationThread( GetCurrentThread(),
|
||||
9 /* ThreadQuerySetWin32StartAddress */,
|
||||
&start, sizeof(start), NULL ) == 0
|
||||
if (primary_tid && GetCurrentThreadId() == primary_tid)
|
||||
{
|
||||
HANDLE hThread;
|
||||
DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),
|
||||
GetCurrentProcess(), &hThread,
|
||||
0, FALSE, DUPLICATE_SAME_ACCESS );
|
||||
CloseHandle( CreateThread( NULL, 4096, exit_thread, hThread, 0, NULL ) );
|
||||
DEBUGSTR( 1, "Primary thread detached, exiting process" );
|
||||
}
|
||||
else if (NtQueryInformationThread &&
|
||||
NtQueryInformationThread( GetCurrentThread(),
|
||||
9 /* ThreadQuerySetWin32StartAddress */,
|
||||
&start, sizeof(start), NULL ) == 0
|
||||
&& (start == Hooks[0].oldfunc || start == Hooks[1].oldfunc
|
||||
|| start == Hooks[0].apifunc || start == Hooks[1].apifunc))
|
||||
{
|
||||
|
10
readme.txt
10
readme.txt
@ -339,9 +339,11 @@ Version History
|
||||
|
||||
Legend: + added, - bug-fixed, * changed.
|
||||
|
||||
1.84-wip - 30 April, 2018:
|
||||
1.84-wip - 2 May, 2018:
|
||||
- close the flush handles on detach;
|
||||
* remove dependency on USER32, dynamically load WINMM.
|
||||
* remove dependency on USER32, dynamically load WINMM;
|
||||
* exit process if the primary thread is detached (for processes on Win10
|
||||
that return, rather than call ExitProcess).
|
||||
|
||||
1.83 - 16 February, 2018:
|
||||
- create the flush thread on first use.
|
||||
@ -616,5 +618,5 @@ Distribution
|
||||
in LICENSE.txt.
|
||||
|
||||
|
||||
===========================
|
||||
Jason Hood, 30 April, 2018.
|
||||
========================
|
||||
Jason Hood, 2 May, 2018.
|
||||
|
Loading…
x
Reference in New Issue
Block a user