You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
338 lines
10 KiB
338 lines
10 KiB
// SupTools.cpp : Defines the entry point for the DLL application.
|
|
//
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <tchar.h>
|
|
#include <MsiQuery.h>
|
|
#include <psapi.h>
|
|
#include "dbgwrap.h"
|
|
|
|
#define STRSAFE_NO_DEPRECATE
|
|
#include "strsafe.h"
|
|
|
|
#include "objbase.h"
|
|
#include "atlbase.h"
|
|
|
|
//
|
|
// CLSID for PCHUpdate
|
|
//
|
|
const CLSID CLSID_PCHUpdate = { 0x833E4012,0xAFF7,0x4AC3,{ 0xAA,0xC2,0x9F,0x24,0xC1,0x45,0x7B,0xCE } };
|
|
|
|
|
|
//
|
|
// dispatch interface entries
|
|
//
|
|
#define DISPID_HCU_BASE 0x08030000
|
|
|
|
#define DISPID_HCU_BASE_UPDATE (DISPID_HCU_BASE + 0x0000)
|
|
#define DISPID_HCU_BASE_ITEM (DISPID_HCU_BASE + 0x0100)
|
|
#define DISPID_HCU_BASE_EVENTS (DISPID_HCU_BASE + 0x0200)
|
|
|
|
#define DISPID_HCU_LATESTVERSION (DISPID_HCU_BASE_UPDATE + 0x10)
|
|
#define DISPID_HCU_CREATEINDEX (DISPID_HCU_BASE_UPDATE + 0x11)
|
|
#define DISPID_HCU_UPDATEPKG (DISPID_HCU_BASE_UPDATE + 0x12)
|
|
#define DISPID_HCU_REMOVEPKG (DISPID_HCU_BASE_UPDATE + 0x13)
|
|
#define DISPID_HCU_REMOVEPKGBYID (DISPID_HCU_BASE_UPDATE + 0x14)
|
|
|
|
|
|
//
|
|
// custom macros
|
|
//
|
|
|
|
#define SAFE_RELEASE( pointer ) \
|
|
if ( (pointer) != NULL ) \
|
|
{ \
|
|
(pointer)->Release(); \
|
|
(pointer) = NULL; \
|
|
} \
|
|
1
|
|
|
|
|
|
//
|
|
// DLL entry point
|
|
//
|
|
|
|
BOOL APIENTRY DllMain( HANDLE hModule,
|
|
DWORD ul_reason_for_call,
|
|
LPVOID lpReserved
|
|
)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// globAL VARIABLES
|
|
TCHAR g_tszTitle[1024] = _T("");
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// IsHSCAppRunningEnum - msi custom action
|
|
// Checks if the Help and Support Center app is running
|
|
///////////////////////////////////////////////////////////
|
|
|
|
BOOL CALLBACK IsHSCAppRunningEnum( HWND hwnd, LPARAM lParam )
|
|
{
|
|
DWORD dwID;
|
|
TCHAR tszTitle[1024] = _T("");
|
|
HWND hParent = NULL;
|
|
|
|
GetWindowThreadProcessId(hwnd, &dwID);
|
|
// if this the desired process ID
|
|
if(dwID == (DWORD)lParam) {
|
|
// get handle to root window
|
|
hParent = GetAncestor(hwnd, GA_ROOTOWNER);
|
|
if (hParent) {
|
|
if ( GetWindowText(hParent, tszTitle, sizeof(tszTitle)) ) {
|
|
if SUCCEEDED(StringCchCopy(g_tszTitle, 1024, tszTitle)) {
|
|
DEBUGMSG(1, ("\r\nNeed to shutdown app: %s", g_tszTitle));
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// IsHSCAppRunning - msi custom action
|
|
// Checks if the Help and Support Center app is running
|
|
///////////////////////////////////////////////////////////
|
|
|
|
UINT __stdcall IsHSCAppRunning(MSIHANDLE hInstall)
|
|
{
|
|
TCHAR tszHSCAppPath[MAX_PATH + 1];
|
|
TCHAR tszHelpDir[] = _T("\\PCHEALTH\\HELPCTR\\Binaries\\");
|
|
TCHAR tszProcessName[MAX_PATH+1] = _T("");
|
|
TCHAR tszModulePath[MAX_PATH] = _T("");
|
|
TCHAR tszHSCApp[] = _T("HelpCtr.exe");
|
|
TCHAR tszProperty[] = _T("HSCAPPRUNNING");
|
|
TCHAR tszPropTitle[] = _T("HSCAPPTITLE");
|
|
DWORD aProcesses[1024], cbNeededTotal, cProcesses;
|
|
HMODULE hMod;
|
|
DWORD cbNeeded;
|
|
HANDLE hProcess = NULL;
|
|
HRESULT hr;
|
|
unsigned int i;
|
|
|
|
// Prepare HSCAppPath
|
|
if (!(GetWindowsDirectory(tszHSCAppPath, MAX_PATH+1))) { return ERROR_INSTALL_FAILURE; }
|
|
hr = StringCchCat(tszHSCAppPath, MAX_PATH, tszHelpDir);
|
|
if (FAILED(hr)) { return ERROR_INSTALL_FAILURE; }
|
|
hr = StringCchCat(tszHSCAppPath, MAX_PATH, tszHSCApp);
|
|
if (FAILED(hr)) { return ERROR_INSTALL_FAILURE; }
|
|
|
|
// Enumerate all processes
|
|
if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeededTotal ) ) {
|
|
// return error
|
|
return ERROR_INSTALL_FAILURE;
|
|
}
|
|
|
|
// Calculate how many process identifiers were returned.
|
|
cProcesses = cbNeededTotal / sizeof(DWORD);
|
|
// Iterate through the process list.
|
|
for ( i = 0; i < cProcesses; i++ ) {
|
|
// Get a handle to the process.
|
|
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i] );
|
|
if ( hProcess ) {
|
|
// GET MODULE HANDLE
|
|
if( EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
|
|
// Get the process name.
|
|
if ( GetModuleBaseName( hProcess, hMod, tszProcessName, sizeof(tszProcessName))) {
|
|
// Get process path
|
|
if (GetModuleFileNameEx( hProcess, hMod, tszModulePath, sizeof(tszModulePath))) {
|
|
// if both process name and path matches
|
|
if ( (0 == _tcsicmp(tszProcessName, tszHSCApp)) && (0 == _tcsicmp(tszModulePath, tszHSCAppPath)) ) {
|
|
// set msi property and get window title
|
|
MsiSetProperty(hInstall, tszProperty, _T("1"));
|
|
EnumWindows((WNDENUMPROC)IsHSCAppRunningEnum, (LPARAM)aProcesses[i]);
|
|
if ( _tcsicmp(g_tszTitle, _T(""))) {
|
|
MsiSetProperty(hInstall, tszPropTitle, g_tszTitle);
|
|
} else {
|
|
DEBUGMSG(1, ("\r\nDetected HSC running, but failed to obtain window title"));
|
|
return ERROR_INSTALL_FAILURE;
|
|
}
|
|
break;
|
|
}
|
|
} else { DEBUGMSG(1, ("\r\nGetModuleFileNameEx failed. GetLastError returned %u\n", GetLastError() ));
|
|
}
|
|
} else { DEBUGMSG(1, ("\r\nGetModuleBaseName failed. GetLastError returned %u\n", GetLastError() ));
|
|
}
|
|
}else { DEBUGMSG(1, ("\r\nEnumProcessModules failed. GetLastError returned %u\n", GetLastError() ));
|
|
}
|
|
// done with the handle
|
|
CloseHandle(hProcess);
|
|
} else { DEBUGMSG(1, ("\r\nOpenProcess failed. GetLastError returned %u\n", GetLastError() ));
|
|
}
|
|
}
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// IsHSCAppRunning - msi custom action
|
|
// Checks if the Help and Support Center app is running
|
|
///////////////////////////////////////////////////////////
|
|
|
|
UINT __stdcall UpdatePackage(MSIHANDLE hInstall)
|
|
{
|
|
DWORD dwError = 0;
|
|
DWORD dwLength = 0;
|
|
HRESULT hr = S_OK;
|
|
IUnknown* pUnknown = NULL;
|
|
IDispatch* pPCHUpdate = NULL;
|
|
UINT nResult = ERROR_SUCCESS;
|
|
LPTSTR pszCabFileName = NULL;
|
|
BOOL bNeedProxySecurity = FALSE;
|
|
|
|
// method execution specific variables
|
|
CComVariant pvars[ 2 ];
|
|
DISPPARAMS disp = { pvars, NULL, 2, 0 };
|
|
|
|
//
|
|
// initialize the COM library
|
|
hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return ERROR_INSTALL_FAILURE;
|
|
}
|
|
|
|
//
|
|
// initialize the security of the COM/OLE
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// *) We don't care which authentication service we use
|
|
// *) We want to identify the callers.
|
|
// *) For package installation let's use the thread token for outbound calls
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
hr = CoInitializeSecurity( NULL, -1, NULL, NULL,
|
|
RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_DYNAMIC_CLOAKING, NULL );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
//
|
|
// since this function will be called by MSI, the calling application would have alredy
|
|
// set the security which makes this function to fail -- so, instead of breaking at this
|
|
// point, we flag here so that CoSetProxyBlanket will be called
|
|
//
|
|
bNeedProxySecurity = TRUE;
|
|
}
|
|
|
|
//
|
|
// get the interface pointer to the PCHUPDATE interface
|
|
hr = CoCreateInstance( CLSID_PCHUpdate, NULL, CLSCTX_ALL, IID_IUnknown, (void **) &pUnknown );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
nResult = ERROR_INSTALL_FAILURE;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// call the CoSetProxyBlanket function -- do this only if needed
|
|
if ( bNeedProxySecurity == TRUE )
|
|
{
|
|
hr = CoSetProxyBlanket( pUnknown,
|
|
RPC_C_AUTHN_DEFAULT, RPC_C_AUTHZ_DEFAULT, COLE_DEFAULT_PRINCIPAL,
|
|
RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_DYNAMIC_CLOAKING );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
nResult = ERROR_INSTALL_FAILURE;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// get the dispatch interface pointer
|
|
hr = pUnknown->QueryInterface(IID_IDispatch, (void **) &pPCHUpdate);
|
|
if ( FAILED( hr ) )
|
|
{
|
|
nResult = ERROR_INSTALL_FAILURE;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// call the CoSetProxyBlanket function -- do this only if needed
|
|
if ( bNeedProxySecurity == TRUE )
|
|
{
|
|
hr = CoSetProxyBlanket( pPCHUpdate,
|
|
RPC_C_AUTHN_DEFAULT, RPC_C_AUTHZ_DEFAULT, COLE_DEFAULT_PRINCIPAL,
|
|
RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_DYNAMIC_CLOAKING );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
nResult = ERROR_INSTALL_FAILURE;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// default length
|
|
dwLength = 255;
|
|
|
|
|
|
get_cabinet_name:
|
|
|
|
//
|
|
// allocate memory to get the cabinet name
|
|
pszCabFileName = new TCHAR[ dwLength + 1 ];
|
|
if ( pszCabFileName == NULL )
|
|
{
|
|
nResult = ERROR_INSTALL_FAILURE;
|
|
goto cleanup;
|
|
}
|
|
|
|
// ...
|
|
ZeroMemory( pszCabFileName, (dwLength + 1) * sizeof( TCHAR ) );
|
|
|
|
//
|
|
// get the appropriate cab file name
|
|
dwError = MsiGetProperty( hInstall, _T( "HSCCabinet" ), pszCabFileName, &dwLength );
|
|
if ( dwError == ERROR_MORE_DATA && dwLength == 255 )
|
|
{
|
|
// buffer is not sufficient -- allocate more memory and call again
|
|
delete [] pszCabFileName;
|
|
pszCabFileName = NULL;
|
|
|
|
// ...
|
|
goto get_cabinet_name;
|
|
}
|
|
else if ( dwError != ERROR_SUCCESS )
|
|
{
|
|
nResult = ERROR_INSTALL_FAILURE;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// prepare the input parameters for UpdatePkg method
|
|
pvars[ 0 ] = true;
|
|
pvars[ 1 ] = pszCabFileName;
|
|
|
|
//
|
|
// execute the function
|
|
pPCHUpdate->Invoke( DISPID_HCU_UPDATEPKG, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, NULL, NULL, NULL );
|
|
|
|
//
|
|
// success
|
|
nResult = ERROR_SUCCESS;
|
|
|
|
//
|
|
// cleanup section
|
|
//
|
|
|
|
cleanup:
|
|
|
|
//
|
|
// release the interface pointers
|
|
SAFE_RELEASE( pUnknown );
|
|
SAFE_RELEASE( pPCHUpdate );
|
|
|
|
// release memory allocated for cabinet name
|
|
if ( pszCabFileName != NULL )
|
|
{
|
|
delete [] pszCabFileName;
|
|
pszCabFileName = NULL;
|
|
}
|
|
|
|
//
|
|
// uninitialize the COM library
|
|
CoUninitialize();
|
|
|
|
// return
|
|
return nResult;
|
|
}
|