windows-nt/Source/XPSP1/NT/shell/tools/reginst/app.cpp
2020-09-26 16:20:57 +08:00

561 lines
12 KiB
C++

#include "priv.h"
const TCHAR c_szAppName[] = TEXT("reginst");
const TCHAR c_szDllReg[] = TEXT("DllRegisterServer");
const TCHAR c_szDllUnreg[] = TEXT("DllUnregisterServer");
typedef HRESULT (CALLBACK* DLLREGPROC)(void);
typedef HRESULT (CALLBACK* DLLINSTALLPROC)(BOOL bInstall, LPCWSTR pszCmdLine);
HINSTANCE g_hinst;
#define RIF_QUIET 0x00000001
#define RIF_UNINSTALL 0x00000002
#define RIF_INSTALLONLY 0x00000004
#define RIF_REGONLY 0x00000008
#define RIF_HELP 0x00000010
// Don't link to shlwapi.dll so this is a stand-alone tool
/*----------------------------------------------------------
Purpose: If a path is contained in quotes then remove them.
Returns: --
Cond: --
*/
void
PathUnquoteSpaces(
LPTSTR lpsz)
{
int cch;
cch = lstrlen(lpsz);
// Are the first and last chars quotes?
if (lpsz[0] == TEXT('"') && lpsz[cch-1] == TEXT('"'))
{
// Yep, remove them.
lpsz[cch-1] = TEXT('\0');
hmemcpy(lpsz, lpsz+1, (cch-1) * SIZEOF(TCHAR));
}
}
// returns a pointer to the arguments in a cmd type path or pointer to
// NULL if no args exist
//
// "foo.exe bar.txt" -> "bar.txt"
// "foo.exe" -> ""
//
// Spaces in filenames must be quoted.
// " "A long name.txt" bar.txt " -> "bar.txt"
LPTSTR
PathGetArgs(
LPCTSTR pszPath)
{
BOOL fInQuotes = FALSE;
if (!pszPath)
return NULL;
while (*pszPath)
{
if (*pszPath == TEXT('"'))
fInQuotes = !fInQuotes;
else if (!fInQuotes && *pszPath == TEXT(' '))
return (LPTSTR)pszPath+1;
pszPath = CharNext(pszPath);
}
return (LPTSTR)pszPath;
}
__inline BOOL ChrCmpA_inline(WORD w1, WORD wMatch)
{
/* Most of the time this won't match, so test it first for speed.
*/
if (LOBYTE(w1) == LOBYTE(wMatch))
{
if (IsDBCSLeadByte(LOBYTE(w1)))
{
return(w1 != wMatch);
}
return FALSE;
}
return TRUE;
}
LPSTR FAR PASCAL StrChrA(LPCSTR lpStart, WORD wMatch)
{
for ( ; *lpStart; lpStart = AnsiNext(lpStart))
{
if (!ChrCmpA_inline(*(UNALIGNED WORD FAR *)lpStart, wMatch))
return((LPSTR)lpStart);
}
return (NULL);
}
BOOL
StrTrim(
IN OUT LPSTR pszTrimMe,
IN LPCSTR pszTrimChars)
{
BOOL bRet = FALSE;
LPSTR psz;
LPSTR pszStartMeat;
LPSTR pszMark = NULL;
ASSERT(IS_VALID_STRING_PTRA(pszTrimMe, -1));
ASSERT(IS_VALID_STRING_PTRA(pszTrimChars, -1));
if (pszTrimMe)
{
/* Trim leading characters. */
psz = pszTrimMe;
while (*psz && StrChrA(pszTrimChars, *psz))
psz = CharNextA(psz);
pszStartMeat = psz;
/* Trim trailing characters. */
// (The old algorithm used to start from the end and go
// backwards, but that is piggy because DBCS version of
// CharPrev iterates from the beginning of the string
// on every call.)
while (*psz)
{
if (StrChrA(pszTrimChars, *psz))
{
pszMark = psz;
}
else
{
pszMark = NULL;
}
psz = CharNextA(psz);
}
// Any trailing characters to clip?
if (pszMark)
{
// Yes
*pszMark = '\0';
bRet = TRUE;
}
/* Relocate stripped string. */
if (pszStartMeat > pszTrimMe)
{
/* (+ 1) for null terminator. */
MoveMemory(pszTrimMe, pszStartMeat, CbFromCchA(lstrlenA(pszStartMeat) + 1));
bRet = TRUE;
}
else
ASSERT(pszStartMeat == pszTrimMe);
ASSERT(IS_VALID_STRING_PTRA(pszTrimMe, -1));
}
return bRet;
}
HRESULT ParseOption(LPCTSTR * ppsz, LPDWORD pdwFlags)
{
HRESULT hres = S_FALSE;
LPCTSTR psz = *ppsz;
// Skip any leading whitespace
while (*psz && (' ' == *psz || '\t' == *psz))
psz++;
if ('/' == *psz || '-' == *psz)
{
hres = S_OK;
psz++;
switch (*psz)
{
case '?':
*pdwFlags |= RIF_HELP;
break;
case 'q':
*pdwFlags |= RIF_QUIET;
break;
case 'u':
*pdwFlags |= RIF_UNINSTALL;
break;
case 'i':
*pdwFlags |= RIF_INSTALLONLY;
break;
case 'r':
*pdwFlags |= RIF_REGONLY;
break;
default:
hres = E_FAIL;
break;
}
// Return the new position in the string
*ppsz = psz+1;
}
else
{
*ppsz = psz;
}
return hres;
}
HRESULT CallInstall(UINT * pids, DLLREGPROC pfnRegSvr, DLLINSTALLPROC pfnInstall, BOOL bInstall, LPCWSTR psz)
{
HRESULT hres = S_OK;
ASSERT(NULL == pfnRegSvr || IS_VALID_CODE_PTR(pfnRegSvr, DLLREGPROC));
ASSERT(NULL == pfnInstall || IS_VALID_CODE_PTR(pfnInstall, DLLINSTALLPROC));
ASSERT(IS_VALID_STRING_PTRW(psz, -1));
_try
{
if (pfnRegSvr)
{
hres = pfnRegSvr();
if (FAILED(hres))
*pids = IDS_INSTALLFAILED;
else
*pids = IDS_REGSUCCESS;
}
if (SUCCEEDED(hres) && pfnInstall)
{
hres = pfnInstall(bInstall, psz);
if (FAILED(hres))
*pids = IDS_INSTALLFAILED;
else
*pids = IDS_INSTALLSUCCESS;
}
}
_except (EXCEPTION_EXECUTE_HANDLER)
{
hres = E_UNEXPECTED;
*pids = IDS_UNEXPECTED;
}
return hres;
}
/*----------------------------------------------------------
Purpose: Worker function to do the work
reginst /q /u /i /r foo.dll <cmdline>
/q Quiet
/u Uninstall
Calls both DllInstall and DllRegisterServer unless:
/i Call DllInstall only
/r Call DllRegisterServer/DllUnregisterServer only
<cmdline> is passed to DllInstall if it exists.
*/
HRESULT
DoWork(HWND hwnd, LPCTSTR pszCmdLine)
{
TCHAR szDll[MAX_PATH];
WCHAR wszArgs[MAX_PATH];
LPCTSTR psz;
LPCTSTR pszArgs;
DWORD dwFlags = 0;
HRESULT hres;
UINT ids = 0;
LPCTSTR pszFnError = NULL;
// Options come first
psz = PathGetArgs(pszCmdLine);
while (S_OK == (hres = ParseOption(&psz, &dwFlags)))
; // Loop thru options
if (dwFlags & RIF_HELP)
{
ids = IDS_HELP;
hres = S_OK;
}
else
{
// Now psz should point at DLL or null terminator
lstrcpyn(szDll, psz, SIZECHARS(szDll));
// Strip off args from the dll name
LPTSTR pszT = PathGetArgs(szDll);
if (*pszT)
*pszT = 0;
StrTrim(szDll, " \t");
PathUnquoteSpaces(szDll);
// Get args to pass to DllInstall
pszArgs = PathGetArgs(psz);
MultiByteToWideChar(CP_ACP, 0, pszArgs, -1, wszArgs, SIZECHARS(wszArgs));
HINSTANCE hinst = LoadLibrary(szDll);
if (hinst)
{
DLLREGPROC pfnRegSvr = NULL;
DLLINSTALLPROC pfnInstall = NULL;
hres = S_OK;
if (IsFlagClear(dwFlags, RIF_INSTALLONLY))
{
if (dwFlags & RIF_UNINSTALL)
{
pfnRegSvr = (DLLREGPROC)GetProcAddress(hinst, "DllUnregisterServer");
pszFnError = c_szDllUnreg;
}
else
{
pfnRegSvr = (DLLREGPROC)GetProcAddress(hinst, "DllRegisterServer");
pszFnError = c_szDllReg;
}
}
if (IsFlagClear(dwFlags, RIF_REGONLY))
{
pfnInstall = (DLLINSTALLPROC)GetProcAddress(hinst, "DllInstall");
pszFnError = TEXT("DllInstall");
}
if (NULL == pfnInstall && NULL == pfnRegSvr)
{
ids = IDS_FAILED;
hres = E_FAIL;
}
else
{
hres = CallInstall(&ids, pfnRegSvr, pfnInstall, IsFlagClear(dwFlags, RIF_UNINSTALL), wszArgs);
if (SUCCEEDED(hres))
{
if (pfnRegSvr && pfnInstall)
ids = IDS_FULLSUCCESS;
if (IsFlagSet(dwFlags, RIF_UNINSTALL))
{
// refer to "uninstall" msgs instead
ids += (IDS_UNREGSUCCESS - IDS_REGSUCCESS);
}
}
}
FreeLibrary(hinst);
}
else
{
ids = IDS_LOADFAILED;
hres = E_FAIL;
}
}
if (0 != ids && IsFlagClear(dwFlags, RIF_QUIET))
{
TCHAR szFmt[512];
TCHAR szMsg[1024];
TCHAR szT[32];
LPCTSTR rgpsz[2];
UINT uFlags = MB_OK;
rgpsz[0] = szDll;
rgpsz[1] = pszFnError;
LoadString(g_hinst, IDS_TITLE, szT, SIZECHARS(szT));
LoadString(g_hinst, ids, szFmt, SIZECHARS(szFmt));
FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
szFmt, 0, 0, szMsg, SIZECHARS(szMsg), (va_list *)rgpsz);
switch (ids)
{
case IDS_UNEXPECTED:
uFlags |= MB_ICONERROR;
break;
case IDS_FAILED:
case IDS_LOADFAILED:
case IDS_INSTALLFAILED:
uFlags |= MB_ICONWARNING;
break;
default:
uFlags |= MB_ICONINFORMATION;
break;
}
MessageBox(hwnd, szMsg, szT, uFlags);
}
return hres;
}
// stolen from the CRT, used to shrink our code
int
_stdcall
ModuleEntry(void)
{
int i;
STARTUPINFO si;
LPTSTR pszCmdLine = GetCommandLine();
si.dwFlags = 0;
GetStartupInfoA(&si);
i = WinMain(GetModuleHandle(NULL),
NULL,
pszCmdLine,
(si.dwFlags & STARTF_USESHOWWINDOW) ? si.wShowWindow : SW_SHOWDEFAULT);
ExitProcess(i);
return i; // We never come here
}
/*----------------------------------------------------------
Purpose: Stub window proc
Returns:
Cond: --
*/
LRESULT
CALLBACK
WndProc(
HWND hWnd,
UINT iMessage,
WPARAM wParam,
LPARAM lParam)
{
switch(iMessage)
{
case WM_CREATE:
break;
case WM_DESTROY:
break;
default:
return DefWindowProc(hWnd, iMessage, wParam, lParam);
break;
}
return 0L;
}
/*----------------------------------------------------------
Purpose: Initialize a stub window
Returns:
Cond: --
*/
BOOL
InitStubWindow(
IN HINSTANCE hInst,
IN HINSTANCE hPrevInstance,
OUT HWND * phwnd)
{
WNDCLASS wndclass;
if (!hPrevInstance)
{
wndclass.style = 0 ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInst ;
wndclass.hIcon = NULL;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = c_szAppName;
if (!RegisterClass(&wndclass))
{
return(FALSE);
}
}
*phwnd = CreateWindowEx(WS_EX_TOOLWINDOW,
c_szAppName,
TEXT(""),
WS_OVERLAPPED,
CW_USEDEFAULT, CW_USEDEFAULT, 0, 0,
NULL, NULL, hInst, NULL);
return (NULL != *phwnd);
}
/*----------------------------------------------------------
Purpose: WinMain
Returns:
Cond: --
*/
int
WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR pszCmdLine,
int nCmdShow)
{
HWND hwndStub;
int nRet = 0;
g_hinst = hInstance;
#ifdef DEBUG
CcshellGetDebugFlags();
if (IsFlagSet(g_dwBreakFlags, BF_ONOPEN))
DebugBreak();
#endif
// turn off critical error stuff
SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
if (InitStubWindow(hInstance, hPrevInstance, &hwndStub))
{
// Do work here
nRet = DoWork(hwndStub, pszCmdLine);
DestroyWindow(hwndStub);
}
return nRet;
}