windows-nt/Source/XPSP1/NT/admin/pchealth/helpctr/hcapi/lib/lib.cpp
2020-09-26 16:20:57 +08:00

459 lines
13 KiB
C++

/******************************************************************************
Copyright (c) 2000 Microsoft Corporation
Module Name:
HCApiLib.cpp
Abstract:
This file contains the implementation of the HCApi Library.
Revision History:
Davide Massarenti (Dmassare) 04/15/2000
created
******************************************************************************/
#include "StdAfx.h"
////////////////////////////////////////////////////////////////////////////////
static const WCHAR c_HelpCtr[] = HC_ROOT_HELPSVC_BINARIES L"\\HelpCtr.exe";
////////////////////////////////////////////////////////////////////////////////
HCAPI::CmdData::CmdData()
{
// BUILD BREAK m_clsidCaller = CLSID_PCHHelpCenterIPC; // CLSID m_clsidCaller;
//
m_fSize = false; // bool m_fSize;
m_lX = 0; // LONG m_lX;
m_lY = 0; // LONG m_lY;
m_lWidth = 0; // LONG m_lWidth;
m_lHeight = 0; // LONG m_lHeight;
//
m_fMode = false; // bool m_fMode;
m_dwFlags = 0; // DWORD m_dwFlags;
//
m_fWindow = false; // bool m_fWindow;
m_hwndParent = NULL; // HWND m_hwndParent;
//
m_fCtx = false; // bool m_fCtx;
// CComBSTR m_bstrCtx;
//
m_fURL = false; // bool m_fURL;
// CComBSTR m_bstrURL;
//
m_fError = false; // bool m_fError;
m_clsidError = CLSID_NULL; // CLSID m_clsidError;
}
HRESULT HCAPI::CmdData::Serialize( /*[out]*/ CComBSTR& bstrBLOB )
{
__HCP_FUNC_ENTRY( "HCAPI::CmdData::Serialize" );
HRESULT hr;
MPC::Serializer_Memory streamMem;
MPC::Serializer& stream = streamMem;
HGLOBAL hg = NULL;
//
// Dump the state of the object into the serializer.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_clsidCaller );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_fMode );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_dwFlags );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_fWindow );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream.HWND_write( m_hwndParent ));
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_fSize );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_lX );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_lY );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_lWidth );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_lHeight );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_fCtx );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_bstrCtxName );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_bstrCtxInfo );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_fURL );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_bstrURL );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_fError );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream << m_clsidError );
//
// Copy data into an HGLOBAL.
//
__MPC_EXIT_IF_CALL_RETURNS_NULL(hr, (hg = ::GlobalAlloc( GMEM_FIXED, streamMem.GetSize() )));
::CopyMemory( hg, streamMem.GetData(), streamMem.GetSize() );
//
// Convert to string.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::ConvertHGlobalToHex( hg, bstrBLOB ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
if(hg) ::GlobalFree( hg );
__HCP_FUNC_EXIT(hr);
}
HRESULT HCAPI::CmdData::Unserialize( /*[in]*/ const CComBSTR& bstrBLOB )
{
__HCP_FUNC_ENTRY( "HCAPI::CmdData::Unserialize" );
HRESULT hr;
MPC::Serializer_Memory streamMem;
MPC::Serializer& stream = streamMem;
HGLOBAL hg = NULL;
//
// Convert from string.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::ConvertHexToHGlobal( bstrBLOB, hg ));
//
// Copy data from an HGLOBAL.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, streamMem.SetSize( ::GlobalSize( hg ) ));
__MPC_EXIT_IF_METHOD_FAILS(hr, streamMem.write ( ::GlobalLock( hg ), ::GlobalSize( hg ) ));
//
// Read the state of the object from the serializer.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_clsidCaller );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_fMode );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_dwFlags );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_fWindow );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream.HWND_read( m_hwndParent ));
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_fSize );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_lX );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_lY );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_lWidth );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_lHeight );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_fCtx );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_bstrCtxName );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_bstrCtxInfo );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_fURL );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_bstrURL );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_fError );
__MPC_EXIT_IF_METHOD_FAILS(hr, stream >> m_clsidError );
hr = S_OK;
__HCP_FUNC_CLEANUP;
if(hg) ::GlobalFree( hg );
__HCP_FUNC_EXIT(hr);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
HCAPI::Locator::Locator()
{
// CComPtr<IPCHHelpCenterIPC> m_ipc;
// CComPtr<IRunningObjectTable> m_rt;
// CComPtr<IMoniker> m_moniker;
m_dwRegister = 0; // DWORD m_dwRegister;
}
HCAPI::Locator::~Locator()
{
Cleanup();
}
////////////////////
void HCAPI::Locator::Cleanup()
{
if(m_rt)
{
if(m_dwRegister)
{
(void)m_rt->Revoke( m_dwRegister );
m_dwRegister = NULL;
}
}
m_ipc .Release();
m_rt .Release();
m_moniker.Release();
}
HRESULT HCAPI::Locator::Init( /*[in]*/ REFCLSID clsid, /*[in]*/ IPCHHelpCenterIPC* ipc )
{
__HCP_FUNC_ENTRY( "HCAPI::Locator::Init" );
HRESULT hr;
Cleanup();
//
// Get a pointer to the ROT and create a class moniker.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, ::GetRunningObjectTable( 0, &m_rt ));
__MPC_EXIT_IF_METHOD_FAILS(hr, ::CreateClassMoniker( clsid, &m_moniker ));
//
// If IPC != NULL, register as provider, otherwise look for a provider.
//
if(ipc)
{
__MPC_EXIT_IF_METHOD_FAILS(hr, m_rt->Register( ROTFLAGS_REGISTRATIONKEEPSALIVE, ipc, m_moniker, &m_dwRegister ));
}
else
{
CComPtr<IUnknown> obj;
if(SUCCEEDED(m_rt->GetObject( m_moniker, &obj )) && obj)
{
// BUILD BREAK __MPC_EXIT_IF_METHOD_FAILS(hr, obj->QueryInterface( IID_IPCHHelpCenterIPC, (void**)&m_ipc ));
}
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
////////////////////////////////////////
HRESULT HCAPI::Locator::IsOpen( /*[out]*/ bool& fOpen, /*[in]*/ CLSID* pclsid )
{
__HCP_FUNC_ENTRY( "HCAPI::Locator::IsOpen" );
HRESULT hr;
fOpen = false;
if(m_ipc == NULL)
{
// BUILD BREAK __MPC_EXIT_IF_METHOD_FAILS(hr, Init( pclsid ? *pclsid : CLSID_PCHHelpCenterIPC ));
}
// BUILD BREAK if(m_ipc && SUCCEEDED(m_ipc->Ping()))
// BUILD BREAK {
// BUILD BREAK fOpen = true;
// BUILD BREAK }
hr = S_OK;
// BUILD BREAK __HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
HRESULT HCAPI::Locator::ExecCommand( /*[out]*/ CmdData& cd )
{
__HCP_FUNC_ENTRY( "HCAPI::Locator::ExecCommand" );
HRESULT hr;
PROCESS_INFORMATION piProcessInformation;
STARTUPINFOW siStartupInfo;
MPC::NamedMutex nm( L"PCH_COMSERVER" );
CComBSTR bstrBLOB;
bool fOpen;
::ZeroMemory( (PVOID)&piProcessInformation, sizeof( piProcessInformation ) );
::ZeroMemory( (PVOID)&siStartupInfo , sizeof( siStartupInfo ) ); siStartupInfo.cb = sizeof( siStartupInfo );
__MPC_EXIT_IF_METHOD_FAILS(hr, cd.Serialize( bstrBLOB ));
//
// Before entrying this section, let's acquire the shared mutex, so only one instance of HelpCtr at a time will execute it.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, nm.Acquire( 0 ));
if(cd.m_fMode)
{
if(cd.m_dwFlags & HCAPI_MODE_NEW_INSTANCE)
{
__MPC_EXIT_IF_METHOD_FAILS(hr, ::CoCreateGuid( &cd.m_clsidCaller ));
}
}
__MPC_EXIT_IF_METHOD_FAILS(hr, IsOpen( fOpen, &cd.m_clsidCaller ));
if(fOpen)
{
// __MPC_EXIT_IF_METHOD_FAILS(hr, m_ipc->Navigate( bstrBLOB ));
}
else
{
MPC::wstring strExe( c_HelpCtr ); MPC::SubstituteEnvVariables( strExe );
int iRetries = 100;
strExe += L" -cmd ";
strExe += SAFEBSTR( bstrBLOB );
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::CreateProcessW( NULL ,
(LPWSTR)strExe.c_str() ,
NULL ,
NULL ,
FALSE ,
NORMAL_PRIORITY_CLASS,
NULL ,
NULL ,
&siStartupInfo ,
&piProcessInformation ));
while(iRetries--)
{
::Sleep( 100 );
if(SUCCEEDED(Init( cd.m_clsidCaller ))) break;
}
__MPC_EXIT_IF_METHOD_FAILS(hr, IsOpen( fOpen, &cd.m_clsidCaller ));
}
//
// If successful, clean the command, but not the caller, it's used to located the same instance of the Help Center.
//
cd.m_fSize = false;
cd.m_fMode = false;
cd.m_fWindow = false;
cd.m_fCtx = false;
cd.m_fURL = false;
cd.m_fError = false;
hr = S_OK;
__HCP_FUNC_CLEANUP;
if(piProcessInformation.hProcess) ::CloseHandle( piProcessInformation.hProcess );
if(piProcessInformation.hThread ) ::CloseHandle( piProcessInformation.hThread );
__HCP_FUNC_EXIT(hr);
}
HRESULT HCAPI::Locator::PopUp()
{
__HCP_FUNC_ENTRY( "HCAPI::Locator::PopUp" );
HRESULT hr;
bool fOpen;
__MPC_EXIT_IF_METHOD_FAILS(hr, IsOpen( fOpen ));
if(fOpen == false)
{
CmdData cd;
__MPC_EXIT_IF_METHOD_FAILS(hr, ExecCommand( cd ));
}
// BUILD BREAK __MPC_EXIT_IF_METHOD_FAILS(hr, m_ipc->Popup());
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
HRESULT HCAPI::Locator::Close()
{
__HCP_FUNC_ENTRY( "HCAPI::Locator::Close" );
HRESULT hr;
bool fOpen;
__MPC_EXIT_IF_METHOD_FAILS(hr, IsOpen( fOpen ));
if(fOpen)
{
// BUILD BREAK __MPC_EXIT_IF_METHOD_FAILS(hr, m_ipc->Close());
m_ipc.Release();
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
HRESULT HCAPI::Locator::WaitForTermination( /*[in]*/ DWORD dwTimeout )
{
__HCP_FUNC_ENTRY( "HCAPI::Locator::WaitForTermination" );
HRESULT hr;
bool fOpen;
//
// Polling implementation...
//
while(1)
{
DWORD dwWait;
__MPC_EXIT_IF_METHOD_FAILS(hr, IsOpen( fOpen ));
if(fOpen == false) break;
if(dwTimeout == 0)
{
__MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_TIMEOUT);
}
if(dwTimeout == INFINITE)
{
::Sleep( 100 );
}
else
{
dwWait = min( dwTimeout, 10 );
::Sleep( dwWait );
dwTimeout -= dwWait;
}
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}