|
|
/******************************************************************************
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); }
|