429 lines
11 KiB
C++
429 lines
11 KiB
C++
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved
|
|
|
|
#include "stdafx.h"
|
|
|
|
// TODO - TODO - TODO -TODO - TODO - TODO - TODO - TODO - TODO - TODO
|
|
//
|
|
// CLSID_FDProvider must match the value defined in FDProvider.cpp
|
|
//
|
|
// TODO - TODO - TODO -TODO - TODO - TODO - TODO - TODO - TODO - TODO
|
|
const GUID CLSID_FDProvider = { 0x8c19066a, 0x643a, 0x4586, { 0x92, 0xb2, 0xa7, 0x85, 0xb9, 0xd, 0x76, 0x6f }};
|
|
|
|
class TClassFactory:
|
|
public IClassFactory
|
|
{
|
|
public:
|
|
// IUnknown
|
|
STDMETHODIMP_(ULONG) AddRef();
|
|
|
|
STDMETHODIMP_(ULONG) Release();
|
|
|
|
STDMETHODIMP QueryInterface(
|
|
REFIID riid,
|
|
__deref_out void** ppv);
|
|
|
|
// IClassFactory
|
|
STDMETHODIMP CreateInstance(
|
|
__in_opt IUnknown* punkOuter,
|
|
REFIID iid,
|
|
__deref_out void** ppv);
|
|
|
|
STDMETHODIMP LockServer(
|
|
BOOL fLock);
|
|
|
|
// Constructor / Destuctor
|
|
TClassFactory();
|
|
HRESULT Init();
|
|
|
|
// Public functionality
|
|
HRESULT ProcessLogoffNotification(
|
|
DWORD SessionId);
|
|
|
|
|
|
protected:
|
|
~TClassFactory();
|
|
|
|
LONG m_cRef;
|
|
IClassFactory* m_pFDProviderClassFactory;
|
|
IEXEHostControl* m_pIEXEHostControl;
|
|
}; // TClassFactory
|
|
|
|
// Forward defines
|
|
VOID __stdcall ProviderLifetimeNotificationCallback(
|
|
bool fDestructed);
|
|
|
|
// Global variables
|
|
HANDLE g_hQuitEvent = NULL;
|
|
LONG g_cHostProcessRefCount = 0;
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Begin TClassFactory implemetation
|
|
//---------------------------------------------------------------------------
|
|
|
|
TClassFactory::TClassFactory():
|
|
m_cRef(1),
|
|
m_pFDProviderClassFactory(NULL),
|
|
m_pIEXEHostControl(NULL)
|
|
{
|
|
} // TClassFactory::TClassFactory
|
|
|
|
TClassFactory::~TClassFactory()
|
|
{
|
|
if (m_pFDProviderClassFactory)
|
|
{
|
|
m_pFDProviderClassFactory->Release();
|
|
m_pFDProviderClassFactory = NULL;
|
|
}
|
|
if (m_pIEXEHostControl)
|
|
{
|
|
m_pIEXEHostControl->Release();
|
|
m_pIEXEHostControl = NULL;
|
|
}
|
|
} // TClassFactory::~TClassFactory
|
|
|
|
HRESULT TClassFactory::Init()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Load the profider that will be hosted
|
|
// and get a pointer to it's class factory
|
|
hr = CoGetClassObject(
|
|
CLSID_FDProvider,
|
|
CLSCTX_INPROC_SERVER,
|
|
NULL,
|
|
IID_IClassFactory,
|
|
(void**) &m_pFDProviderClassFactory);
|
|
|
|
// Get a pointer to IEXEHostControl exposed by
|
|
// the provider's class factory
|
|
if (S_OK == hr)
|
|
{
|
|
hr = m_pFDProviderClassFactory->QueryInterface(
|
|
__uuidof(IEXEHostControl),
|
|
(void**) &m_pIEXEHostControl);
|
|
}
|
|
|
|
// Register our liftime notification callback with the provider
|
|
if (S_OK == hr)
|
|
{
|
|
hr = m_pIEXEHostControl->RegisterProviderLifetimeNotificationCallback(
|
|
&ProviderLifetimeNotificationCallback);
|
|
}
|
|
|
|
return hr;
|
|
} // TClassFactory::Init
|
|
|
|
STDMETHODIMP_(ULONG) TClassFactory::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_cRef);
|
|
} // TClassFactory::AddRef
|
|
|
|
STDMETHODIMP_(ULONG) TClassFactory::Release()
|
|
{
|
|
LONG cRef = InterlockedDecrement(&m_cRef);
|
|
if (0 == cRef)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return cRef;
|
|
} // TClassFactory::Release
|
|
|
|
STDMETHODIMP TClassFactory::QueryInterface(
|
|
REFIID riid,
|
|
__deref_out_opt void** ppv)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (ppv)
|
|
{
|
|
*ppv = NULL;
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
if (IID_IUnknown == riid)
|
|
{
|
|
AddRef();
|
|
*ppv = (IUnknown*) this;
|
|
}
|
|
else if (IID_IClassFactory == riid)
|
|
{
|
|
AddRef();
|
|
*ppv = (IClassFactory*) this;
|
|
}
|
|
else
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
} // TClassFactory::QueryInterface
|
|
|
|
STDMETHODIMP TClassFactory::CreateInstance(
|
|
__in_opt IUnknown* pUnkownOuter,
|
|
REFIID riid,
|
|
__deref_out_opt void** ppv)
|
|
{
|
|
return m_pFDProviderClassFactory->CreateInstance(
|
|
pUnkownOuter,
|
|
riid,
|
|
ppv);
|
|
} // TClassFactory::CreateInstance
|
|
|
|
STDMETHODIMP TClassFactory::LockServer(
|
|
BOOL fLock)
|
|
{
|
|
// External calls to LockServer are passed through to
|
|
// the ProviderLifetime manager callback
|
|
if (fLock)
|
|
{
|
|
ProviderLifetimeNotificationCallback(false);
|
|
}
|
|
else
|
|
{
|
|
ProviderLifetimeNotificationCallback(true);
|
|
}
|
|
|
|
return S_OK;
|
|
} // TClassFactory::LockServer
|
|
|
|
HRESULT TClassFactory::ProcessLogoffNotification(
|
|
DWORD SessionId)
|
|
{
|
|
return m_pIEXEHostControl->LogoffNotification(SessionId);
|
|
} // TClassFactory::ProcessLogoffNotification
|
|
|
|
//---------------------------------------------------------------------------
|
|
// End TClassFactory implemetation
|
|
//---------------------------------------------------------------------------
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Begin global function implementation
|
|
//---------------------------------------------------------------------------
|
|
|
|
VOID __stdcall ProviderLifetimeNotificationCallback(
|
|
bool fDestructed)
|
|
{
|
|
if (!fDestructed)
|
|
{
|
|
InterlockedIncrement(&g_cHostProcessRefCount);
|
|
CoAddRefServerProcess();
|
|
}
|
|
else
|
|
{
|
|
InterlockedDecrement(&g_cHostProcessRefCount);
|
|
if (CoReleaseServerProcess() == 0)
|
|
{
|
|
// If there are no provider objects
|
|
// and no Lock on the class object, let the exe exit
|
|
SetEvent(g_hQuitEvent);
|
|
}
|
|
}
|
|
} // ProviderLifetimeNotificationCallback
|
|
|
|
int __stdcall WinMain(
|
|
__in HINSTANCE hInstance,
|
|
__in_opt HINSTANCE hPrevInstance,
|
|
__in_opt LPSTR lpCmdLine,
|
|
__in int nShowCmd)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TClassFactory* pClassFactory = NULL;
|
|
ULONG hClassRegistration = NULL;
|
|
HWND hMessageWindow = NULL;
|
|
bool fWTSRegistered = false;
|
|
bool fQuit = false;
|
|
DWORD WaitResult = 0;
|
|
MSG msg = {0};
|
|
|
|
hr = CoInitializeEx(
|
|
NULL,
|
|
COINIT_MULTITHREADED);
|
|
|
|
// Create and event that will be signaled
|
|
// when all COM objects have been released
|
|
// and the process should end.
|
|
if (S_OK == hr)
|
|
{
|
|
// Create a event that will be signaled when the Host should exit
|
|
if (S_OK == hr)
|
|
{
|
|
g_hQuitEvent = CreateEvent(
|
|
NULL,
|
|
TRUE,
|
|
FALSE,
|
|
NULL);
|
|
if (!g_hQuitEvent)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
|
|
// Create our class factory
|
|
if (S_OK == hr)
|
|
{
|
|
pClassFactory = new(std::nothrow) TClassFactory();
|
|
if (!pClassFactory)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
if (S_OK == hr)
|
|
{
|
|
hr = pClassFactory->Init();
|
|
}
|
|
|
|
// TODO - TODO - TODO -TODO - TODO - TODO - TODO - TODO - TODO - TODO
|
|
//
|
|
// If this EXE host is converted into a Windows Service,
|
|
// the message pump and WTSRegisterSessionNotification should be
|
|
// removed and HandlerEx with SERVICE_CONTROL_SESSIONCHANGE
|
|
// should be used instead.
|
|
//
|
|
// TODO - TODO - TODO -TODO - TODO - TODO - TODO - TODO - TODO - TODO
|
|
|
|
// Create a message only window to process
|
|
// session change events that will notify us when a logoff has occured.
|
|
if (S_OK == hr)
|
|
{
|
|
hMessageWindow = CreateWindow(
|
|
L"Message",
|
|
L"",
|
|
0,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
|
HWND_MESSAGE, // Message only window
|
|
NULL,
|
|
hInstance,
|
|
NULL);
|
|
if (!hMessageWindow)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
|
|
// Register the window for session change events
|
|
if (S_OK == hr)
|
|
{
|
|
if (WTSRegisterSessionNotification(
|
|
hMessageWindow,
|
|
NOTIFY_FOR_ALL_SESSIONS))
|
|
{
|
|
fWTSRegistered = true;
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
|
|
// Register our class factory with COM remoting
|
|
if (S_OK == hr)
|
|
{
|
|
hr = CoRegisterClassObject(
|
|
CLSID_FDProvider,
|
|
(IClassFactory*) pClassFactory,
|
|
CLSCTX_LOCAL_SERVER,
|
|
REGCLS_MULTIPLEUSE,
|
|
&hClassRegistration);
|
|
}
|
|
|
|
// Start a message pump and wait for g_hQuitEvent to be signaled
|
|
if (S_OK == hr)
|
|
{
|
|
while (!fQuit)
|
|
{
|
|
WaitResult = MsgWaitForMultipleObjectsEx(
|
|
1,
|
|
&g_hQuitEvent,
|
|
INFINITE,
|
|
QS_ALLINPUT,
|
|
MWMO_INPUTAVAILABLE);
|
|
|
|
if (WAIT_OBJECT_0 == WaitResult)
|
|
{
|
|
// g_hQuitEvent has been signaled
|
|
fQuit = true;
|
|
}
|
|
else if (WAIT_OBJECT_0 + 1 == WaitResult)
|
|
{
|
|
// Window messages are avaialble, process them
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
if (WM_QUIT == msg.message)
|
|
{
|
|
// WM_QUIT message has been posted.
|
|
fQuit = true;
|
|
}
|
|
if (WM_WTSSESSION_CHANGE == msg.message)
|
|
{
|
|
if (WTS_SESSION_LOGOFF == msg.wParam)
|
|
{
|
|
// A logoff has occured.
|
|
|
|
hr = pClassFactory->ProcessLogoffNotification((DWORD) msg.lParam);
|
|
if (S_OK != hr)
|
|
{
|
|
// if the logoff can not be processed,
|
|
// exit the process.
|
|
fQuit = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// This is unexpected, exit the process.
|
|
fQuit = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cleanup
|
|
if (hClassRegistration)
|
|
{
|
|
CoRevokeClassObject(hClassRegistration);
|
|
}
|
|
if (pClassFactory)
|
|
{
|
|
pClassFactory->Release();
|
|
}
|
|
if (fWTSRegistered)
|
|
{
|
|
WTSUnRegisterSessionNotification(hMessageWindow);
|
|
}
|
|
if (hMessageWindow)
|
|
{
|
|
DestroyWindow(hMessageWindow);
|
|
}
|
|
if (g_hQuitEvent)
|
|
{
|
|
CloseHandle(g_hQuitEvent);
|
|
}
|
|
|
|
CoUninitialize();
|
|
}
|
|
|
|
return hr;
|
|
} // WinMain
|
|
|
|
//---------------------------------------------------------------------------
|
|
// End global function implementation
|
|
//---------------------------------------------------------------------------
|