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.
476 lines
12 KiB
476 lines
12 KiB
/*++
|
|
|
|
Copyright (C) 1996-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
EXEMAIN.CPP
|
|
|
|
Abstract:
|
|
|
|
EXE/COM Helpers
|
|
|
|
History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include <stdio.h>
|
|
#include "commain.cpp"
|
|
#include <strutils.h>
|
|
|
|
DWORD g_dwMainThreadId = 0xFFFFFFFF;
|
|
|
|
class CExeClassFactory : public IClassFactory, IExternalConnection
|
|
{
|
|
long m_lRef;
|
|
IClassFactory* m_pFactory;
|
|
CUnkInternal* m_pInternalUnk;
|
|
|
|
public:
|
|
|
|
CExeClassFactory( CUnkInternal* pInternalUnk )
|
|
: m_pInternalUnk( pInternalUnk ), m_lRef(0), m_pFactory(0)
|
|
{
|
|
m_pInternalUnk->InternalAddRef();
|
|
m_pInternalUnk->InternalQueryInterface( IID_IClassFactory,
|
|
(void**)&m_pFactory );
|
|
}
|
|
|
|
~CExeClassFactory()
|
|
{
|
|
m_pInternalUnk->InternalRelease();
|
|
}
|
|
|
|
STDMETHOD(QueryInterface)( REFIID riid, void** ppv )
|
|
{
|
|
HRESULT hr;
|
|
|
|
if ( riid == IID_IUnknown || riid == IID_IClassFactory )
|
|
{
|
|
*ppv = this;
|
|
AddRef();
|
|
hr = S_OK;
|
|
}
|
|
else if ( riid == IID_IExternalConnection )
|
|
{
|
|
*ppv = (IExternalConnection*)this;
|
|
AddRef();
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHOD_(ULONG, AddRef)()
|
|
{
|
|
return InterlockedIncrement( &m_lRef );
|
|
}
|
|
|
|
STDMETHOD_(ULONG, Release)()
|
|
{
|
|
long lRef = InterlockedDecrement( &m_lRef );
|
|
|
|
if ( lRef == 0 )
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return lRef;
|
|
}
|
|
|
|
STDMETHOD(CreateInstance)(IUnknown* pOuter, REFIID riid, void** ppv)
|
|
{
|
|
return m_pFactory->CreateInstance( pOuter, riid, ppv );
|
|
}
|
|
|
|
STDMETHOD(LockServer)(BOOL fLock)
|
|
{
|
|
return m_pFactory->LockServer( fLock );
|
|
}
|
|
|
|
STDMETHOD_(DWORD,AddConnection)( DWORD exconn, DWORD dwreserved )
|
|
{
|
|
m_pFactory->LockServer( TRUE );
|
|
return 1;
|
|
}
|
|
|
|
STDMETHOD_(DWORD,ReleaseConnection)( DWORD exconn,
|
|
DWORD dwreserved,
|
|
BOOL fLastReleaseCloses )
|
|
{
|
|
m_pFactory->LockServer( FALSE );
|
|
return 1;
|
|
}
|
|
};
|
|
|
|
class CExeLifeControl : public CLifeControl
|
|
{
|
|
protected:
|
|
long m_lNumObjects;
|
|
BOOL m_bUnloading;
|
|
CMyCritSec m_cs;
|
|
|
|
protected:
|
|
virtual void Quit()
|
|
{
|
|
PostThreadMessage(g_dwMainThreadId, WM_QUIT, 0, 0);
|
|
}
|
|
public:
|
|
CExeLifeControl() : m_lNumObjects(0), m_bUnloading(FALSE){}
|
|
virtual BOOL ObjectCreated(IUnknown* pv)
|
|
{
|
|
CMyInCritSec ics(&m_cs);
|
|
if(m_bUnloading)
|
|
return FALSE;
|
|
|
|
m_lNumObjects++;
|
|
return TRUE;
|
|
}
|
|
virtual void ObjectDestroyed(IUnknown* pv)
|
|
{
|
|
EnterCriticalSection(&m_cs);
|
|
long l = --m_lNumObjects;
|
|
if(l == 0)
|
|
{
|
|
m_bUnloading = TRUE;
|
|
LeaveCriticalSection(&m_cs);
|
|
Quit();
|
|
}
|
|
else
|
|
{
|
|
LeaveCriticalSection(&m_cs);
|
|
}
|
|
}
|
|
|
|
virtual void AddRef(IUnknown* pv){}
|
|
virtual void Release(IUnknown* pv){}
|
|
};
|
|
|
|
BOOL ContainsSubstring( LPCTSTR szStr, LPCTSTR szSubStr )
|
|
{
|
|
BOOL bContains;
|
|
#ifdef UNICODE
|
|
bContains = wcsstr(szStr,szSubStr) != NULL;
|
|
#else
|
|
bContains = strstr(szStr,szSubStr) != NULL;
|
|
#endif
|
|
return bContains;
|
|
}
|
|
|
|
void MessageLoop()
|
|
{
|
|
MSG msg;
|
|
while(GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
|
|
struct ServiceInfo
|
|
{
|
|
BOOL m_bUsed;
|
|
|
|
LPTSTR m_szServiceName;
|
|
LPTSTR m_szDisplayName;
|
|
BOOL m_bAuto;
|
|
|
|
HANDLE m_hEvent;
|
|
SERVICE_STATUS_HANDLE m_hStatus;
|
|
|
|
ServiceInfo() : m_bUsed(FALSE){}
|
|
|
|
} g_ServiceInfo;
|
|
|
|
void SetServiceInfo(LPTSTR szServiceName, LPTSTR szDisplayName, BOOL bAuto)
|
|
{
|
|
g_ServiceInfo.m_bUsed = TRUE;
|
|
g_ServiceInfo.m_szServiceName = szServiceName;
|
|
g_ServiceInfo.m_szDisplayName = szDisplayName;
|
|
g_ServiceInfo.m_bAuto = bAuto;
|
|
}
|
|
|
|
void WINAPI ServiceHandler(DWORD dwControl)
|
|
{
|
|
SERVICE_STATUS Status;
|
|
Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
|
Status.dwCurrentState = SERVICE_RUNNING;
|
|
Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
|
Status.dwWin32ExitCode = NO_ERROR;
|
|
Status.dwCheckPoint = 0;
|
|
Status.dwWaitHint = 0;
|
|
|
|
if(!SetServiceStatus(g_ServiceInfo.m_hStatus, &Status))
|
|
{
|
|
long lRes = GetLastError();
|
|
return;
|
|
}
|
|
switch(dwControl)
|
|
{
|
|
case SERVICE_CONTROL_STOP:
|
|
Status.dwCurrentState = SERVICE_STOPPED;
|
|
SetServiceStatus(g_ServiceInfo.m_hStatus, &Status);
|
|
SetEvent(g_ServiceInfo.m_hEvent);
|
|
ExitProcess(0);
|
|
return;
|
|
case SERVICE_CONTROL_PAUSE:
|
|
case SERVICE_CONTROL_CONTINUE:
|
|
case SERVICE_CONTROL_INTERROGATE:
|
|
case SERVICE_CONTROL_SHUTDOWN:
|
|
return;
|
|
};
|
|
}
|
|
|
|
void WINAPI ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv)
|
|
{
|
|
g_ServiceInfo.m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
g_ServiceInfo.m_hStatus = RegisterServiceCtrlHandler(
|
|
g_ServiceInfo.m_szServiceName,
|
|
(LPHANDLER_FUNCTION)&ServiceHandler);
|
|
if(g_ServiceInfo.m_hStatus == NULL)
|
|
{
|
|
long lRes = GetLastError();
|
|
return;
|
|
}
|
|
|
|
SERVICE_STATUS Status;
|
|
Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
|
Status.dwCurrentState = SERVICE_START_PENDING;
|
|
Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
|
Status.dwWin32ExitCode = NO_ERROR;
|
|
Status.dwCheckPoint = 0;
|
|
Status.dwWaitHint = 10000;
|
|
|
|
if(!SetServiceStatus(g_ServiceInfo.m_hStatus, &Status))
|
|
{
|
|
long lRes = GetLastError();
|
|
return;
|
|
}
|
|
|
|
Status.dwCurrentState = SERVICE_RUNNING;
|
|
if(!SetServiceStatus(g_ServiceInfo.m_hStatus, &Status))
|
|
{
|
|
long lRes = GetLastError();
|
|
return;
|
|
}
|
|
|
|
MessageLoop();
|
|
}
|
|
|
|
|
|
BOOL StartService()
|
|
{
|
|
SERVICE_TABLE_ENTRY aEntries[2];
|
|
aEntries[0].lpServiceName = g_ServiceInfo.m_szServiceName;
|
|
aEntries[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)&ServiceMain;
|
|
aEntries[1].lpServiceName = NULL;
|
|
aEntries[1].lpServiceProc = NULL;
|
|
|
|
if(!StartServiceCtrlDispatcher(aEntries))
|
|
{
|
|
long lRes = GetLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL InstallService()
|
|
{
|
|
SC_HANDLE hManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
|
|
TCHAR szFilename[1024];
|
|
GetModuleFileName(NULL, szFilename, 1023);
|
|
|
|
SC_HANDLE hService = CreateService(hManager,
|
|
g_ServiceInfo.m_szServiceName,
|
|
g_ServiceInfo.m_szDisplayName,
|
|
SERVICE_ALL_ACCESS,
|
|
SERVICE_WIN32_OWN_PROCESS,
|
|
g_ServiceInfo.m_bAuto?SERVICE_AUTO_START : SERVICE_DEMAND_START,
|
|
SERVICE_ERROR_NORMAL,
|
|
szFilename, NULL, NULL, NULL,
|
|
NULL, //Local System
|
|
NULL // no password
|
|
);
|
|
|
|
if(hService == NULL)
|
|
{
|
|
long lRes = GetLastError();
|
|
return FALSE;
|
|
}
|
|
/*
|
|
// Create AppId key
|
|
// ================
|
|
|
|
GUID AppId = *g_aClassInfos[0].m_pClsid;
|
|
char szAppId[128];
|
|
WCHAR wszAppId[128];
|
|
char szAppIdKey[128];
|
|
|
|
StringFromGUID2(*pInfo->m_pClsid, wszAppId, 128);
|
|
wcstombs(szAppId, wszAppId, 128);
|
|
strcpy(szAppIdKey, "SOFTWARE\\Classes\\AppId\\");
|
|
strcat(szAppIdKey, szAppId);
|
|
|
|
HKEY hKey1;
|
|
RegCreateKey(HKEY_LOCAL_MACHINE, szAppIdKey, &hKey1);
|
|
|
|
RegSetValueEx(hKey1, "LocalService", 0, REG_SZ,
|
|
g_ServiceInfo.m_szServiceName,
|
|
strlen(g_ServiceInfo.m_szServiceName)+1);
|
|
*/
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
BOOL DeinstallService()
|
|
{
|
|
SC_HANDLE hManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
|
|
SC_HANDLE hService = OpenService(hManager, g_ServiceInfo.m_szServiceName,
|
|
SERVICE_ALL_ACCESS);
|
|
if(hService == NULL)
|
|
{
|
|
long lRes = GetLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
if(!DeleteService(hService))
|
|
{
|
|
long lRes = GetLastError();
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
CExeLifeControl g_LifeControl;
|
|
CLifeControl* g_pLifeControl = &g_LifeControl;
|
|
|
|
void CALLBACK MyTimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
|
|
{
|
|
PostQuitMessage(0);
|
|
}
|
|
|
|
void __cdecl main()
|
|
{
|
|
LPTSTR szOrigCommandLine = GetCommandLine();
|
|
size_t cchLen = lstrlen(szOrigCommandLine)+1;
|
|
LPTSTR szCommandLine = new TCHAR[cchLen];
|
|
|
|
if (!szCommandLine)
|
|
return;
|
|
|
|
StringCchCopy( szCommandLine,cchLen,szOrigCommandLine );
|
|
TCHAR * pc = szCommandLine;
|
|
while(*pc)
|
|
*(pc++) = (TCHAR)wbem_towupper(*pc);
|
|
|
|
GlobalInitialize();
|
|
|
|
if ( ContainsSubstring(szCommandLine, TEXT("-REGSERVER")) ||
|
|
ContainsSubstring(szCommandLine, TEXT("/REGSERVER")) )
|
|
{
|
|
GlobalRegister();
|
|
for(LIST_ENTRY * pEntry = g_ClassInfoHead.Flink;
|
|
pEntry != &g_ClassInfoHead;
|
|
pEntry = pEntry->Flink)
|
|
{
|
|
CClassInfo* pInfo = CONTAINING_RECORD(pEntry,CClassInfo,m_Entry);
|
|
HRESULT hres = RegisterServer(pInfo, TRUE);
|
|
if(FAILED(hres)) return;
|
|
}
|
|
if(g_ServiceInfo.m_bUsed)
|
|
{
|
|
InstallService();
|
|
}
|
|
}
|
|
else if ( ContainsSubstring( szCommandLine, TEXT("-UNREGSERVER")) ||
|
|
ContainsSubstring( szCommandLine, TEXT("/UNREGSERVER")))
|
|
{
|
|
GlobalUnregister();
|
|
for(LIST_ENTRY * pEntry = g_ClassInfoHead.Flink;
|
|
pEntry != &g_ClassInfoHead;
|
|
pEntry = pEntry->Flink)
|
|
{
|
|
CClassInfo* pInfo = CONTAINING_RECORD(pEntry,CClassInfo,m_Entry);
|
|
HRESULT hres = UnregisterServer(pInfo, TRUE);
|
|
if(FAILED(hres)) return;
|
|
}
|
|
if(g_ServiceInfo.m_bUsed)
|
|
{
|
|
DeinstallService();
|
|
}
|
|
}
|
|
else if( !ContainsSubstring(szCommandLine, TEXT("EMBEDDING")) &&
|
|
!g_ServiceInfo.m_bUsed )
|
|
{
|
|
printf("Cannot run standalone\n");
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
if(FAILED(GlobalInitializeCom()))
|
|
return;
|
|
|
|
for(LIST_ENTRY * pEntry = g_ClassInfoHead.Flink;
|
|
pEntry != &g_ClassInfoHead;
|
|
pEntry = pEntry->Flink)
|
|
{
|
|
CClassInfo* pInfo = CONTAINING_RECORD(pEntry,CClassInfo,m_Entry);
|
|
|
|
IClassFactory* pFactory = new CExeClassFactory( pInfo->m_pFactory);
|
|
|
|
if ( pFactory == NULL )
|
|
return;
|
|
|
|
HRESULT hres = CoRegisterClassObject(
|
|
*pInfo->m_pClsid, pFactory, CLSCTX_SERVER,
|
|
REGCLS_MULTIPLEUSE, &pInfo->m_dwCookie);
|
|
|
|
if(FAILED(hres)) return;
|
|
}
|
|
|
|
if(g_ServiceInfo.m_bUsed)
|
|
{
|
|
StartService();
|
|
}
|
|
else
|
|
{
|
|
g_dwMainThreadId = GetCurrentThreadId();
|
|
MessageLoop();
|
|
}
|
|
|
|
for(LIST_ENTRY * pEntry = g_ClassInfoHead.Flink;
|
|
pEntry != &g_ClassInfoHead;
|
|
pEntry = pEntry->Flink)
|
|
{
|
|
CClassInfo* pInfo = CONTAINING_RECORD(pEntry,CClassInfo,m_Entry);
|
|
HRESULT hres = CoRevokeClassObject(pInfo->m_dwCookie);
|
|
if(FAILED(hres)) return;
|
|
}
|
|
|
|
SetTimer(NULL, 0, 1000, (TIMERPROC)MyTimerProc);
|
|
MessageLoop();
|
|
|
|
GlobalUninitialize();
|
|
}
|
|
}
|
|
|
|
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine,
|
|
int nCmdShow)
|
|
{
|
|
main();
|
|
return 0;
|
|
}
|
|
|