348 lines
8.4 KiB
C
348 lines
8.4 KiB
C
//---------------------------------------------------------------------------
|
|
//
|
|
// Copyright (c) Microsoft Corporation 1993-1994
|
|
//
|
|
// File: thread.c
|
|
//
|
|
// This files contains the thread creation routines. (These routines
|
|
// were swiped from the shell.)
|
|
//
|
|
// Public API is RunDLLThread().
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "brfprv.h"
|
|
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
static const TCHAR c_szStubWindowClass[] = TEXT("BrfStubWindow32");
|
|
#pragma data_seg()
|
|
|
|
// SHOpenPropSheet uses these messages. It is unclear if
|
|
// we need to support this or not.
|
|
#define STUBM_SETDATA (WM_USER)
|
|
#define STUBM_GETDATA (WM_USER+1)
|
|
|
|
typedef void (WINAPI * NEWTHREADPROC)(HWND hwndStub,
|
|
HINSTANCE hAppInstance,
|
|
LPTSTR lpszCmdLine, int nCmdShow);
|
|
|
|
typedef struct // dlle
|
|
{
|
|
HINSTANCE hinst;
|
|
NEWTHREADPROC lpfn;
|
|
} DLLENTRY;
|
|
|
|
|
|
typedef struct _NEWTHREAD_NOTIFY
|
|
{
|
|
NMHDR hdr;
|
|
HICON hIcon;
|
|
LPCTSTR lpszTitle;
|
|
} NEWTHREAD_NOTIFY;
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Parses a command line entry into a DLLENTRY struct.
|
|
|
|
Returns: TRUE on success
|
|
Cond: --
|
|
*/
|
|
BOOL PRIVATE InitializeDLLEntry(
|
|
LPTSTR lpszCmdLine,
|
|
DLLENTRY * pdlle)
|
|
{
|
|
LPTSTR lpStart, lpEnd, lpFunction;
|
|
|
|
TRACE_MSG(TF_GENERAL, TEXT("RunDLLThread(%s)"), lpszCmdLine);
|
|
|
|
for (lpStart=lpszCmdLine; ; )
|
|
{
|
|
// Skip leading blanks
|
|
//
|
|
while (*lpStart == TEXT(' '))
|
|
{
|
|
++lpStart;
|
|
}
|
|
|
|
// Check if there are any switches
|
|
//
|
|
if (*lpStart != TEXT('/'))
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Look at all the switches; ignore unknown ones
|
|
//
|
|
for (++lpStart; ; ++lpStart)
|
|
{
|
|
switch (*lpStart)
|
|
{
|
|
case TEXT(' '):
|
|
case TEXT('\0'):
|
|
goto EndSwitches;
|
|
break;
|
|
|
|
// Put any switches we care about here
|
|
//
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
EndSwitches:
|
|
;
|
|
}
|
|
|
|
// We have found the DLL,FN parameter
|
|
//
|
|
lpEnd = StrChr(lpStart, TEXT(' '));
|
|
if (lpEnd)
|
|
{
|
|
*lpEnd++ = TEXT('\0');
|
|
}
|
|
|
|
// There must be a DLL name and a function name
|
|
//
|
|
lpFunction = StrChr(lpStart, TEXT(','));
|
|
if (!lpFunction)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
*lpFunction++ = TEXT('\0');
|
|
|
|
// Load the library and get the procedure address
|
|
// Note that we try to get a module handle first, so we don't need
|
|
// to pass full file names around
|
|
//
|
|
pdlle->hinst = GetModuleHandle(lpStart);
|
|
if (pdlle->hinst)
|
|
{
|
|
TCHAR szName[MAXPATHLEN];
|
|
|
|
GetModuleFileName(pdlle->hinst, szName, ARRAYSIZE(szName));
|
|
LoadLibrary(szName);
|
|
}
|
|
else
|
|
{
|
|
pdlle->hinst = LoadLibrary(lpStart);
|
|
if (!ISVALIDHINSTANCE(pdlle->hinst))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
{
|
|
CHAR szFunction[MAX_PATH] = "";
|
|
WideCharToMultiByte(CP_ACP, 0, lpFunction, -1, szFunction, MAX_PATH, NULL, NULL);
|
|
pdlle->lpfn = (NEWTHREADPROC)GetProcAddress(pdlle->hinst, szFunction);
|
|
}
|
|
#else
|
|
{
|
|
pdlle->lpfn = (NEWTHREADPROC)GetProcAddress(pdlle->hinst, lpFunction);
|
|
}
|
|
#endif
|
|
|
|
if (!pdlle->lpfn)
|
|
{
|
|
FreeLibrary(pdlle->hinst);
|
|
return(FALSE);
|
|
}
|
|
|
|
// Copy the rest of the command parameters down
|
|
//
|
|
if (lpEnd)
|
|
{
|
|
lstrcpy(lpszCmdLine, lpEnd);
|
|
}
|
|
else
|
|
{
|
|
*lpszCmdLine = TEXT('\0');
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Handles WM_NOTIFY messages for stub window
|
|
Returns: varies
|
|
Cond: --
|
|
*/
|
|
LRESULT PRIVATE StubNotify(
|
|
HWND hWnd,
|
|
WPARAM wParam,
|
|
NEWTHREAD_NOTIFY *lpn)
|
|
{
|
|
switch (lpn->hdr.code)
|
|
{
|
|
#ifdef COOLICON
|
|
case RDN_TASKINFO:
|
|
SetWindowText(hWnd, lpn->lpszTitle ? lpn->lpszTitle : TEXT(""));
|
|
g_hIcon = lpn->hIcon ? lpn->hIcon :
|
|
LoadIcon(hInst, MAKEINTRESOURCE(IDI_DEFAULT));
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
return(DefWindowProc(hWnd, WM_NOTIFY, wParam, (LPARAM)lpn));
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Window proc for thread
|
|
|
|
Returns: varies
|
|
Cond: --
|
|
*/
|
|
LRESULT CALLBACK WndProc(
|
|
HWND hWnd,
|
|
UINT iMessage,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
switch(iMessage)
|
|
{
|
|
case WM_CREATE:
|
|
#ifdef COOLICON
|
|
g_hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_DEFAULT));
|
|
#endif
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
return(StubNotify(hWnd, wParam, (NEWTHREAD_NOTIFY *)lParam));
|
|
|
|
#ifdef COOLICON
|
|
case WM_QUERYDRAGICON:
|
|
return(MAKELRESULT(g_hIcon, 0));
|
|
#endif
|
|
|
|
case STUBM_SETDATA:
|
|
SetWindowLong(hWnd, 0, wParam);
|
|
SetWindowLong(hWnd, 4, lParam);
|
|
break;
|
|
|
|
case STUBM_GETDATA:
|
|
*((LONG *)lParam) = GetWindowLong(hWnd, 4);
|
|
return GetWindowLong(hWnd, 0);
|
|
|
|
default:
|
|
return DefWindowProc(hWnd, iMessage, wParam, lParam) ;
|
|
break;
|
|
}
|
|
|
|
return 0L;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a stub window to handle the thread
|
|
|
|
Returns: handle to window
|
|
Cond: --
|
|
*/
|
|
HWND PRIVATE CreateStubWindow(void)
|
|
{
|
|
WNDCLASS wndclass;
|
|
|
|
if (!GetClassInfo(g_hinst, c_szStubWindowClass, &wndclass))
|
|
{
|
|
wndclass.style = 0 ;
|
|
wndclass.lpfnWndProc = (WNDPROC)WndProc ;
|
|
wndclass.cbClsExtra = 0 ;
|
|
wndclass.cbWndExtra = sizeof(DWORD) * 2 ;
|
|
wndclass.hInstance = g_hinst;
|
|
wndclass.hIcon = NULL ;
|
|
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
|
|
wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
|
|
wndclass.lpszMenuName = NULL ;
|
|
wndclass.lpszClassName = c_szStubWindowClass ;
|
|
|
|
if (!RegisterClass(&wndclass))
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return CreateWindowEx(WS_EX_TOOLWINDOW, c_szStubWindowClass, c_szNULL,
|
|
0, 0, 0, 0, 0, NULL, NULL, g_hinst, NULL);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Initializes a new thread in our DLL
|
|
|
|
Returns: 0
|
|
Cond: --
|
|
*/
|
|
DWORD PRIVATE ThreadInitDLL(
|
|
LPVOID pszCmdLine)
|
|
{
|
|
DLLENTRY dlle;
|
|
|
|
if (InitializeDLLEntry((LPTSTR)pszCmdLine, &dlle))
|
|
{
|
|
HWND hwndStub = CreateStubWindow();
|
|
if (hwndStub)
|
|
{
|
|
SetForegroundWindow(hwndStub);
|
|
dlle.lpfn(hwndStub, g_hinst, pszCmdLine, SW_NORMAL);
|
|
DestroyWindow(hwndStub);
|
|
}
|
|
FreeLibrary(dlle.hinst);
|
|
}
|
|
|
|
GFree(pszCmdLine);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Start a new thread
|
|
|
|
This code was swiped from the shell.
|
|
|
|
Returns: TRUE if the thread was created successfully
|
|
Cond: --
|
|
*/
|
|
BOOL PUBLIC RunDLLThread(
|
|
HWND hwnd,
|
|
LPCTSTR pszCmdLine,
|
|
int nCmdShow)
|
|
{
|
|
BOOL fSuccess=FALSE; // assume error
|
|
LPTSTR pszCopy = GAlloc(CbFromCch(lstrlen(pszCmdLine)+1));
|
|
|
|
if (pszCopy)
|
|
{
|
|
DWORD idThread;
|
|
HANDLE hthread;
|
|
lstrcpy(pszCopy, pszCmdLine);
|
|
|
|
if (hthread=CreateThread(NULL, 0, ThreadInitDLL, pszCopy, 0, &idThread))
|
|
{
|
|
// We don't need to communicate with this thread any more.
|
|
// Close the handle and let it run and terminate itself.
|
|
//
|
|
// Notes: In this case, pszCopy will be freed by the thread.
|
|
//
|
|
CloseHandle(hthread);
|
|
fSuccess=TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Thread creation failed, we should free the buffer.
|
|
GFree(pszCopy);
|
|
}
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|