#include "SvcEx.h"
#include "XHdr.h"
#include "SvcUtils.h"
#include "resource.h"
#include "DlgService.h"
#include "DlgConflict.h"
#include "Structs.h"
#include "_Error.h"
#include <winsvc.h>
#include <tchar.h>
extern ULONG g_cDllRef;
extern HINSTANCE g_hDll;
extern HMENU g_hSubMenu;
extern DWORD g_dwLastError;
extern TCHAR g_lpcszApplicationName[];
TCHAR pszServiceName[_MAX_PATH + 1];
ISvcExClassFactory::ISvcExClassFactory()
: m_cRef(0L)
{
InterlockedIncrement((long *)&g_cDllRef);
}
ISvcExClassFactory::~ISvcExClassFactory()
{
InterlockedDecrement((long *)&g_cDllRef);
}
STDMETHODIMP
ISvcExClassFactory::QueryInterface(REFIID riid, LPVOID FAR *ppvObject)
{
HRESULT hr = E_NOINTERFACE;
*ppvObject = NULL;
if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory))
{
*ppvObject = (LPISVCEXCLASSFACTORY)this;
AddRef();
hr = NOERROR;
}
return hr;
}
STDMETHODIMP_(ULONG)
ISvcExClassFactory::AddRef()
{
InterlockedIncrement((long *)&m_cRef);
return m_cRef;
}
STDMETHODIMP_(ULONG)
ISvcExClassFactory::Release()
{
InterlockedDecrement((long *)&m_cRef);
if(m_cRef == 0L)
delete this;
return 0L;
}
STDMETHODIMP
ISvcExClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject)
{
HRESULT hr = S_OK;
LPISVCEXCSHELLEXT pShellExt = (LPISVCEXCSHELLEXT)NULL;
*ppvObject = NULL;
if(pUnkOuter != (LPUNKNOWN)NULL)
hr = CLASS_E_NOAGGREGATION;
else
{
pShellExt = new ISvcExShellExt;
if(pShellExt == (LPISVCEXCSHELLEXT)NULL)
hr = E_OUTOFMEMORY;
}
if(hr == S_OK)
hr = pShellExt->QueryInterface(riid, ppvObject);
return hr;
}
STDMETHODIMP
ISvcExClassFactory::LockServer(BOOL fLock)
{
UNREFERENCED_PARAMETER(fLock);
return NOERROR;
}
ISvcExShellExt::ISvcExShellExt()
:
m_xFileCount(0),
m_ppszFileUserClickedOn(0),
m_cRef(0L),
m_pDataObj(NULL)
{
InterlockedIncrement((long *)&g_cDllRef);
}
ISvcExShellExt::~ISvcExShellExt()
{
if(m_pDataObj)
m_pDataObj->Release();
DeleteFileData();
InterlockedDecrement((long *)&g_cDllRef);
}
void
ISvcExShellExt::DeleteFileData()
{
if(m_xFileCount > 0)
{
for(register UINT x = 0; x < m_xFileCount; x++)
{
delete[] m_ppszFileUserClickedOn[x];
}
delete m_ppszFileUserClickedOn;
}
}
STDMETHODIMP
ISvcExShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv)
{
*ppv = NULL;
if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown))
*ppv = (LPSHELLEXTINIT)this;
else if (IsEqualIID(riid, IID_IContextMenu))
*ppv = (LPCONTEXTMENU)this;
if(*ppv)
{
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG)
ISvcExShellExt::AddRef()
{
InterlockedIncrement((long *)&m_cRef);
return m_cRef;
}
STDMETHODIMP_(ULONG)
ISvcExShellExt::Release()
{
InterlockedDecrement((long *)&m_cRef);
if(m_cRef == 0L)
delete this;
return m_cRef;
}
STDMETHODIMP
ISvcExShellExt::Initialize(LPCITEMIDLIST pIDFolder, LPDATAOBJECT pDataObj, HKEY hRegKey)
{
UNREFERENCED_PARAMETER(hRegKey);
UNREFERENCED_PARAMETER(pIDFolder);
if(m_pDataObj)
{
m_pDataObj->Release();
m_pDataObj = 0;
}
if(pDataObj)
{
m_pDataObj = pDataObj;
pDataObj->AddRef();
}
return NOERROR;
}
STDMETHODIMP
ISvcExShellExt::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
{
UNREFERENCED_PARAMETER(idCmdLast);
UINT idCmd = idCmdFirst;
pszServiceName[0] = _T('\0');
GetFileNames();
if(m_xFileCount != 1)
return NOERROR;
char *szMenuText_Popup = "&Service...";
char *szMenuText_Install = "&Install";
char *szMenuText_Open = "&Open";
char *szMenuText_Uninstall = "&Uninstall";
char *szMenuText_About = "&About...";
BOOL bAppendItems = TRUE;
if((uFlags & 0x000F) == CMF_NORMAL)
bAppendItems = TRUE;
else if (uFlags & CMF_VERBSONLY)
bAppendItems = TRUE;
else if (uFlags & CMF_EXPLORE)
bAppendItems = TRUE;
else
bAppendItems = FALSE;
if(bAppendItems)
{
InsertMenu(hMenu, indexMenu, MF_SEPARATOR | MF_BYPOSITION, 0, NULL);
indexMenu++;
g_hSubMenu = CreateMenu();
if(g_hSubMenu)
{
// this exe is a service?
LPTSTR ppSvcNames = NULL;
int nIndex = -1;
BOOL fIsSvc = GetServicesByPath(&ppSvcNames, &nIndex);
if(nIndex >= 0)
{
delete ppSvcNames;
}
InsertMenu(g_hSubMenu, 0, MF_STRING | MF_BYPOSITION, idCmd++, szMenuText_Install);
InsertMenu(g_hSubMenu, 1, MF_STRING | MF_BYPOSITION, idCmd++, szMenuText_Open);
InsertMenu(g_hSubMenu, 2, MF_STRING | MF_BYPOSITION, idCmd++, szMenuText_Uninstall);
InsertMenu(g_hSubMenu, 3, MF_SEPARATOR | MF_BYPOSITION, 0 , NULL);
InsertMenu(g_hSubMenu, 4, MF_STRING | MF_BYPOSITION, idCmd++, szMenuText_About);
EnableMenuItem(g_hSubMenu, 0, MF_BYPOSITION | (fIsSvc ? MF_GRAYED : MF_ENABLED));
EnableMenuItem(g_hSubMenu, 1, MF_BYPOSITION | (fIsSvc ? MF_ENABLED : MF_GRAYED));
EnableMenuItem(g_hSubMenu, 2, MF_BYPOSITION | (fIsSvc ? MF_ENABLED : MF_GRAYED));
}
InsertMenu(hMenu, indexMenu, MF_STRING | MF_POPUP | MF_BYPOSITION, (UINT_PTR)g_hSubMenu, szMenuText_Popup);
indexMenu++;
InsertMenu(hMenu, indexMenu, MF_SEPARATOR | MF_BYPOSITION, 0, NULL);
indexMenu++;
return ResultFromShort(idCmd - idCmdFirst);
}
return NOERROR;
}
BOOL
ISvcExShellExt::GetServicesByPath(LPTSTR *ppSvcNames, int *pnIndex)
{
SC_HANDLE schSCM = 0;
SC_HANDLE schService = 0;
DWORD dwResumeHandle = 0;
BOOL bEnumRetVal = FALSE;
LPENUM_SERVICE_STATUS lpSvc = 0;
DWORD dwBytesNeeded = 0;
DWORD dwBufferSize = 0;
DWORD dwServicesReturned = 0;
TCHAR lpszServiceName[_MAX_PATH + 1];
BOOL fIsSvc = FALSE;
// Open SCM of remote (or local) machine. All access or die.
schSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if(schSCM)
{
dwResumeHandle = 0;
#pragma warning(disable:4127)
do
{
_retry_:
bEnumRetVal =
EnumServicesStatus
(
schSCM,
SERVICE_WIN32,
SERVICE_STATE_ALL,
lpSvc,
dwBufferSize,
&dwBytesNeeded,
&dwServicesReturned,
&dwResumeHandle
);
if(!bEnumRetVal)
{
g_dwLastError = GetLastError();
if(g_dwLastError == ERROR_MORE_DATA)
{
#pragma warning(disable:4127)
if(lpSvc != 0)
{
HeapFree(GetProcessHeap(), 0, lpSvc);
lpSvc = 0;
}
lpSvc = (LPENUM_SERVICE_STATUS)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytesNeeded);
if(lpSvc)
{
dwBufferSize = dwBytesNeeded;
lpSvc->lpServiceName = lpszServiceName;
goto _retry_;
}
else
goto _cleanup_;
}
else if(g_dwLastError == ERROR_NO_MORE_ITEMS)
break;
else
goto _cleanup_;
}
else
{
// insert all entries in list
register DWORD x = 0;
for(x = 0; x < dwServicesReturned; x++)
{
schService = OpenService(schSCM, lpSvc[x].lpServiceName, SERVICE_ALL_ACCESS);
if(schService)
{
QUERY_SERVICE_CONFIG *pqsc;
DWORD _dwFalseSize = 0;
DWORD _dwBytesNeeded = 0;
char lpszBPN[_MAX_PATH + 1];
char lpszDep[_MAX_PATH + 1];
char lpszDN[_MAX_PATH + 1];
char lpszLOG[_MAX_PATH + 1];
char lpszSSN[_MAX_PATH + 1];
_dwFalseSize = sizeof(QUERY_SERVICE_CONFIG);
_dwFalseSize += 5 * (_MAX_PATH + 1);
pqsc = (LPQUERY_SERVICE_CONFIG)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, _dwFalseSize);
pqsc->lpBinaryPathName = lpszBPN;
pqsc->lpDependencies = lpszDep;
pqsc->lpDisplayName = lpszDN;
pqsc->lpLoadOrderGroup = lpszLOG;
pqsc->lpServiceStartName = lpszSSN;
BOOL bQSC = QueryServiceConfig(schService, pqsc, _dwFalseSize, &_dwBytesNeeded);
#pragma warning(disable:4127)
HeapFree(GetProcessHeap(), 0, pqsc);
BOOL _fIsSvc = bQSC ?
(_tcsicmp(m_ppszFileUserClickedOn[0], pqsc->lpBinaryPathName) == 0 ? TRUE : FALSE) : FALSE;
if(!fIsSvc)
{
if(_fIsSvc)
fIsSvc = TRUE;
}
CloseServiceHandle(schService);
schService = 0;
if(_fIsSvc)
{
if(*ppSvcNames == (LPTSTR)NULL)
*ppSvcNames = (TCHAR *)malloc((2 + _tcslen(lpSvc[x].lpServiceName)) * sizeof(TCHAR));
else
{
int nOldLen = _tcslen(*ppSvcNames);
TCHAR *sz = (TCHAR *)malloc((1 + nOldLen) * sizeof(TCHAR));
_tcscpy(sz, *ppSvcNames);
*ppSvcNames = (TCHAR *)realloc(*ppSvcNames,
(2 + _tcslen(lpSvc[x].lpServiceName) + nOldLen) * sizeof(TCHAR));
_tcscpy(*ppSvcNames, sz);
free(sz);
}
(*pnIndex)++;
if(*pnIndex == 0)
_tcscpy(*ppSvcNames, lpSvc[x].lpServiceName);
else
_tcscat(*ppSvcNames, lpSvc[x].lpServiceName);
_tcscat(*ppSvcNames, _T("#"));
}
}
}
}
if(dwResumeHandle == 0)
break;
} while(TRUE);
_cleanup_:
#pragma warning(disable:4127)
if(lpSvc != 0)
HeapFree(GetProcessHeap(), 0, lpSvc);
CloseServiceHandle(schSCM);
}
return fIsSvc;
}
STDMETHODIMP
ISvcExShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
{
HRESULT hr = E_INVALIDARG;
if (!HIWORD(lpcmi->lpVerb))
{
UINT idCmd = LOWORD(lpcmi->lpVerb);
switch (idCmd)
{
case 0:
hr = Install(lpcmi->hwnd, lpcmi->lpDirectory, lpcmi->lpVerb, lpcmi->lpParameters, lpcmi->nShow);
break;
case 1:
hr = Open(lpcmi->hwnd, lpcmi->lpDirectory, lpcmi->lpVerb, lpcmi->lpParameters, lpcmi->nShow);
break;
case 2:
hr = Uninstall(lpcmi->hwnd, lpcmi->lpDirectory, lpcmi->lpVerb, lpcmi->lpParameters, lpcmi->nShow);
break;
case 3:
hr = About(lpcmi->hwnd, lpcmi->lpDirectory, lpcmi->lpVerb, lpcmi->lpParameters, lpcmi->nShow);
break;
default:
break;
}
}
return hr;
}
STDMETHODIMP
ISvcExShellExt::GetCommandString(UINT idCmd, UINT uFlags, UINT FAR *reserved, LPSTR pszName, UINT cchMax)
{
UNREFERENCED_PARAMETER(reserved);
UNREFERENCED_PARAMETER(uFlags);
*pszName = 0;
cchMax = 40;
char psz[40];
switch (idCmd)
{
case 0:
LoadString(g_hDll, IDCMD_NEW, psz, cchMax);
break;
case 1:
LoadString(g_hDll, IDCMD_OPEN, psz, cchMax);
break;
case 2:
LoadString(g_hDll, IDCMD_DELETE, psz, cchMax);
break;
case 3:
LoadString(g_hDll, IDCMD_ABOUT, psz, cchMax);
break;
default:
break;
}
wcscpy((unsigned short *)pszName, _WCSTR(psz));
return NOERROR;
}
STDMETHODIMP
ISvcExShellExt::Install(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, LPCSTR pszParam, int iShowCmd)
{
UNREFERENCED_PARAMETER(pszWorkingDir);
UNREFERENCED_PARAMETER(pszCmd);
UNREFERENCED_PARAMETER(pszParam);
UNREFERENCED_PARAMETER(iShowCmd);
LPSERVICEDESC lpSD = (LPSERVICEDESC)malloc(sizeof(SERVICEDESC));
lpSD->pszExeName = (TCHAR *)malloc((_MAX_PATH + 1) * sizeof(TCHAR));
lpSD->pszServiceName = NULL;
_tcscpy(lpSD->pszExeName, m_ppszFileUserClickedOn[0]);
DialogBoxParam(g_hDll, MAKEINTRESOURCE(IDD_SERVICE), hParent, ManageService_DlgProc, (LPARAM)lpSD);
return S_OK;
}
STDMETHODIMP
ISvcExShellExt::Open(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, LPCSTR pszParam, int iShowCmd)
{
UNREFERENCED_PARAMETER(pszWorkingDir);
UNREFERENCED_PARAMETER(pszCmd);
UNREFERENCED_PARAMETER(pszParam);
UNREFERENCED_PARAMETER(iShowCmd);
LPTSTR ppSvcNames = NULL;
int nIndex = -1;
LPLPTSTR *ppS = NULL;
BOOL fIsSvc = GetServicesByPath(&ppSvcNames, &nIndex);
if(fIsSvc)
{
ppS = (LPLPTSTR *)malloc(sizeof(LPLPTSTR));
ppS->ppStr = ppSvcNames;
ppS->nHowMany = nIndex;
_tcscpy(ppS->szExeName, m_ppszFileUserClickedOn[0]);
}
else
return S_OK;
if(nIndex > 0) // more than 1
{
int nRetVal = DialogBoxParam(g_hDll, MAKEINTRESOURCE(IDD_CONFLICT), hParent, ConflictDlg_Proc, (LPARAM)ppS);
if(nRetVal == IDCANCEL)
{
free(ppS->ppStr);
free(ppS);
return S_OK;
}
}
else
{
TCHAR *szSvcName = _tcstok(ppSvcNames, _T("#"));
_tcscpy(ppS->szServiceName, szSvcName);
}
LPSERVICEDESC lpSD = (LPSERVICEDESC)malloc(sizeof(SERVICEDESC));
lpSD->pszExeName = (TCHAR *)malloc((_MAX_PATH + 1) * sizeof(TCHAR));
lpSD->pszServiceName = (TCHAR *)malloc((_MAX_PATH + 1) * sizeof(TCHAR));
_tcscpy(lpSD->pszExeName, m_ppszFileUserClickedOn[0]);
_tcscpy(lpSD->pszServiceName, ppS->szServiceName);
free(ppS->ppStr);
free(ppS);
DialogBoxParam(g_hDll, MAKEINTRESOURCE(IDD_SERVICE), hParent, ManageService_DlgProc, (LPARAM)lpSD);
return S_OK;
}
STDMETHODIMP
ISvcExShellExt::Uninstall(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, LPCSTR pszParam, int iShowCmd)
{
UNREFERENCED_PARAMETER(pszWorkingDir);
UNREFERENCED_PARAMETER(pszCmd);
UNREFERENCED_PARAMETER(pszParam);
UNREFERENCED_PARAMETER(iShowCmd);
LPTSTR ppSvcNames = NULL;
int nIndex = -1;
LPLPTSTR *ppS = NULL;
BOOL fIsSvc = GetServicesByPath(&ppSvcNames, &nIndex);
if(fIsSvc)
{
ppS = (LPLPTSTR *)malloc(sizeof(LPLPTSTR));
ppS->ppStr = ppSvcNames;
ppS->nHowMany = nIndex;
_tcscpy(ppS->szExeName, m_ppszFileUserClickedOn[0]);
}
else
return S_OK;
if(nIndex > 0) // more than 1
{
int nRetVal = DialogBoxParam(g_hDll, MAKEINTRESOURCE(IDD_CONFLICT), hParent, ConflictDlg_Proc, (LPARAM)ppS);
if(nRetVal == IDCANCEL)
{
free(ppS->ppStr);
free(ppS);
return S_OK;
}
}
else
{
TCHAR *szSvcName = _tcstok(ppSvcNames, _T("#"));
_tcscpy(ppS->szServiceName, szSvcName);
}
TCHAR pszServiceName[_MAX_PATH + 1];
_tcscpy(pszServiceName, ppS->szServiceName);
free(ppS->ppStr);
free(ppS);
// Delete service.
{
TCHAR lpszMsg[512], lpszFmt[256];
LoadString(g_hDll, IDS_DELETESERVICE, lpszFmt, 256);
_stprintf(lpszMsg, lpszFmt, pszServiceName);
if(MessageBox(hParent, lpszMsg, g_lpcszApplicationName, MB_YESNO | MB_ICONQUESTION) == IDNO)
return S_OK;
SC_HANDLE schSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if(schSCM)
{
SC_HANDLE schService = OpenService(schSCM, pszServiceName, DELETE);
if(schService)
{
if(DeleteService(schService))
{
LoadString(g_hDll, IDS_SERVICEDELETED, lpszFmt, 256);
_stprintf(lpszMsg, lpszFmt, pszServiceName);
MessageBox(hParent, lpszMsg, g_lpcszApplicationName, MB_OK | MB_ICONINFORMATION);
}
else
ReportLastError(NULL, g_lpcszApplicationName, TRUE, 0);
CloseServiceHandle(schService);
}
else
ReportLastError(NULL, NULL, TRUE, 0);
CloseServiceHandle(schSCM);
}
else
ReportLastError(NULL, NULL, TRUE, 0);
}
return S_OK;
}
STDMETHODIMP
ISvcExShellExt::About(HWND hParent, LPCSTR pszWorkingDir, LPCSTR pszCmd, LPCSTR pszParam, int iShowCmd)
{
UNREFERENCED_PARAMETER(iShowCmd);
UNREFERENCED_PARAMETER(pszParam);
UNREFERENCED_PARAMETER(pszCmd);
UNREFERENCED_PARAMETER(pszWorkingDir);
char szAboutText[1024];
LoadString(g_hDll, IDS_ABOUT, szAboutText, 1024);
MessageBox(hParent, szAboutText, TEXT("Windows Explorer"), MB_OK | MB_ICONINFORMATION);
return NOERROR;
}
STDMETHODIMP
ISvcExShellExt::GetFileNames()
{
HRESULT hr = S_FALSE;
IEnumFORMATETC *pefEtc = 0;
hr = m_pDataObj->EnumFormatEtc(DATADIR_GET, &pefEtc);
if(SUCCEEDED(hr))
{
hr = pefEtc->Reset();
if(SUCCEEDED(hr))
{
FORMATETC fEtc;
ULONG ulFetched = 0L;
while(TRUE)
{
hr = pefEtc->Next(1, &fEtc, &ulFetched);
if(FAILED(hr) || (ulFetched <= 0))
break;
fEtc.cfFormat = CF_HDROP;
fEtc.dwAspect = DVASPECT_CONTENT;
fEtc.lindex = -1;
fEtc.ptd = NULL;
fEtc.tymed = TYMED_HGLOBAL;
STGMEDIUM stgM;
hr = m_pDataObj->GetData(&fEtc, &stgM);
if(SUCCEEDED(hr))
{
if(stgM.tymed == TYMED_HGLOBAL)
{
UINT nFileCount = DragQueryFile((HDROP)stgM.hGlobal, (UINT)INVALID_HANDLE_VALUE, NULL, 0);
if(nFileCount >= 1)
{
if(m_ppszFileUserClickedOn)
{
DeleteFileData();
}
m_ppszFileUserClickedOn = new LPTSTR[nFileCount];
for(register UINT x = 0; x < nFileCount; x++)
{
m_ppszFileUserClickedOn[x] = new TCHAR[_MAX_PATH + 1];
DragQueryFile((HDROP)stgM.hGlobal, x, m_ppszFileUserClickedOn[x], _MAX_PATH + 1);
}
m_xFileCount = nFileCount;
}
}
}
}
}
}
if(pefEtc)
pefEtc->Release();
return hr;
}