mirror of https://github.com/lianthony/NT4.0
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.
1134 lines
27 KiB
1134 lines
27 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name :
|
|
|
|
copyhook.cpp
|
|
|
|
Abstract:
|
|
|
|
Copy hook handlers
|
|
|
|
Author:
|
|
|
|
Ronald Meijer (ronaldm)
|
|
|
|
Project:
|
|
|
|
IIS Shell Extension
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "stdafx.h"
|
|
|
|
//
|
|
// Initialize GUIDs (should be done only and at-least once per DLL/EXE)
|
|
//
|
|
#pragma data_seg(".text")
|
|
#define INITGUID
|
|
#include <initguid.h>
|
|
#include <shlguid.h>
|
|
#include "shellext.h"
|
|
#pragma data_seg()
|
|
|
|
#include "svcloc.h"
|
|
#include "registry.h"
|
|
#include "ipaddr.hpp"
|
|
#include "iispage.h"
|
|
#include "w3scfg.h"
|
|
#include <lmcons.h>
|
|
|
|
//
|
|
// Global variables
|
|
//
|
|
UINT g_cRefThisDll = 0; // Reference count of this DLL.
|
|
|
|
|
|
extern CConfigDll theApp;
|
|
|
|
BOOL
|
|
IsServiceInstalled(
|
|
IN LPCTSTR lpstrComputer,
|
|
IN LPCTSTR lpstrService
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check to see if the given service is installed on the given computer
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR lpstrComputer : Computer name to check
|
|
LPCTSTR lpstrService : Service name to check for
|
|
|
|
Return Value:
|
|
|
|
TRUE, if the service is installed, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
int nState;
|
|
|
|
return ::QueryInetServiceStatus(lpstrComputer,
|
|
lpstrService, &nState) == ERROR_SUCCESS;
|
|
}
|
|
|
|
BOOL
|
|
GetServiceInfo(
|
|
IN CString & strComputer,
|
|
IN LPCTSTR lpstrService,
|
|
IN DWORD dwMask,
|
|
OUT CInetAConfigInfo * & pii
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
BOOL fService = FALSE;
|
|
int nState;
|
|
|
|
DWORD err = ::QueryInetServiceStatus(strComputer, lpstrService, &nState);
|
|
if (err == ERROR_SUCCESS
|
|
&& (nState == INetServiceRunning || nState == INetServicePaused))
|
|
{
|
|
pii = new CInetAConfigInfo(dwMask, &g_strlServers);
|
|
|
|
err = pii->GetInfo();
|
|
if (err == ERROR_SUCCESS)
|
|
{
|
|
fService = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fService = FALSE;
|
|
delete pii;
|
|
pii = NULL;
|
|
}
|
|
} else
|
|
{
|
|
if (pii!=NULL)
|
|
{
|
|
delete pii;
|
|
pii = NULL;
|
|
}
|
|
}
|
|
|
|
return fService;
|
|
}
|
|
|
|
//
|
|
// Determine if the given file is a UNC path
|
|
//
|
|
BOOL
|
|
IsUncPath(
|
|
IN const CString & strDirPath
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
if (strDirPath.GetLength() >= 5) // It must be at least as long as \\x\y,
|
|
{ //
|
|
LPCTSTR lp = strDirPath; //
|
|
if (*lp == _T('\\') // It must begin with \\,
|
|
&& *(lp + 1) == _T('\\') //
|
|
&& _tcschr(lp + 2, _T('\\')) // And have at least one more \ after that.
|
|
)
|
|
{
|
|
//
|
|
// Ok, it's a UNC path
|
|
//
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Not a UNC path
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
IsRemoteDrive(
|
|
IN const CString & strDirPath
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
BOOL fReturn=FALSE;
|
|
INT nDrive;
|
|
|
|
if (!strDirPath.IsEmpty())
|
|
{
|
|
CString strRoot=strDirPath.Left(2);
|
|
nDrive = GetDriveType( strRoot );
|
|
if (( nDrive == DRIVE_REMOTE ) || ( nDrive == DRIVE_NO_ROOT_DIR ))
|
|
{
|
|
fReturn=TRUE;
|
|
}
|
|
}
|
|
return(fReturn);
|
|
}
|
|
|
|
//
|
|
// Determine if the given file is a fully qualified path
|
|
// name.
|
|
//
|
|
BOOL
|
|
IsQualifiedDirectory(
|
|
IN const CString & strDirPath
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
if (strDirPath.GetLength() >= 3 // It must be at least as long as d:\
|
|
&& strDirPath[1] == _T(':') // directory letter followed by ':'
|
|
&& strDirPath[2] == _T('\\') // And a backslash
|
|
)
|
|
{
|
|
//
|
|
// Ok, it's a Directory Path
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Not a directory path
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Build up directory list from CInetAConfigInfo structure
|
|
//
|
|
BOOL
|
|
BuildDirList(
|
|
IN CInetAConfigInfo * pii,
|
|
OUT CObOwnedList & oblDirectories
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
LPINETA_CONFIG_INFO pci = pii
|
|
? pii->GetData()
|
|
: NULL;
|
|
|
|
BOOL fSuccess = TRUE;
|
|
|
|
//
|
|
// Clean up first
|
|
//
|
|
oblDirectories.RemoveAll();
|
|
|
|
TRY
|
|
{
|
|
if (pci && pci->VirtualRoots)
|
|
{
|
|
for (DWORD i = 0; i < pci->VirtualRoots->cEntries; i++)
|
|
{
|
|
CDirEntry * pDirEntry = new CDirEntry(
|
|
pci->VirtualRoots->aVirtRootEntry[i].pszDirectory,
|
|
pci->VirtualRoots->aVirtRootEntry[i].pszRoot,
|
|
pci->VirtualRoots->aVirtRootEntry[i].pszAccountName,
|
|
pci->VirtualRoots->aVirtRootEntry[i].AccountPassword,
|
|
pci->VirtualRoots->aVirtRootEntry[i].pszAddress,
|
|
pci->VirtualRoots->aVirtRootEntry[i].dwMask,
|
|
pci->VirtualRoots->aVirtRootEntry[i].dwError
|
|
);
|
|
|
|
ASSERT(pDirEntry != NULL);
|
|
if (pDirEntry->IsHome())
|
|
{
|
|
int nSel;
|
|
CIpAddress ipaTarget = pDirEntry->QueryIpAddress();
|
|
|
|
if (::FindExistingHome(ipaTarget, oblDirectories, nSel))
|
|
{
|
|
//
|
|
// We already had a home dir for this ip -- can't have that
|
|
//
|
|
TRACEEOLID(_T("Duplicate home directories found for this ip address."));
|
|
::AfxMessageBox(IDS_WRN_MULTIPLE_HOMES,
|
|
MB_ICONINFORMATION | MB_OK);
|
|
pDirEntry->GenerateAutoAlias();
|
|
}
|
|
}
|
|
|
|
oblDirectories.AddTail(pDirEntry);
|
|
}
|
|
}
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
::DisplayMessage(::GetLastError());
|
|
fSuccess = FALSE;
|
|
}
|
|
END_CATCH_ALL
|
|
|
|
oblDirectories.Sort(
|
|
(CObjectPlus::PCOBJPLUS_ORDER_FUNC) & CDirEntry::OrderByAlias );
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
LPINETA_VIRTUAL_ROOT_LIST
|
|
GetRoots(
|
|
IN CObOwnedList & oblDirectories
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
int cListItems = oblDirectories.GetCount();
|
|
DWORD cbNeeded = sizeof(INETA_VIRTUAL_ROOT_LIST) +
|
|
(sizeof(INETA_VIRTUAL_ROOT_ENTRY) * cListItems);;
|
|
LPINETA_VIRTUAL_ROOT_LIST pItemList = NULL;
|
|
int cItems;
|
|
|
|
TRY
|
|
{
|
|
TRACEEOLID(_T("Attempting to allocate rootlist of ") << cbNeeded
|
|
<< _T(" bytes"));
|
|
|
|
pItemList = (LPINETA_VIRTUAL_ROOT_LIST)new BYTE[cbNeeded];
|
|
|
|
ASSERT(pItemList);
|
|
//
|
|
// This shouldn't be necessary, but I tend
|
|
// to be paranoid about this sort of thing
|
|
//
|
|
::ZeroMemory(pItemList, cbNeeded);
|
|
pItemList->cEntries = cListItems;
|
|
|
|
CObListIter obli( oblDirectories );
|
|
const CDirEntry * pDirEntry;
|
|
|
|
cItems = 0;
|
|
for ( /**/ ; pDirEntry = (CDirEntry *)obli.Next() ; cItems++ )
|
|
{
|
|
TRACEEOLID(_T("Adding directory entry ") << cItems );
|
|
|
|
//
|
|
// Only fill in the IP address if the entry
|
|
// has a valid one. Otherwise, this will
|
|
// be a blank string.
|
|
//
|
|
CString strIpAddress;
|
|
if (pDirEntry->HasIPAddress())
|
|
{
|
|
strIpAddress = (CString)pDirEntry->QueryIpAddress();
|
|
}
|
|
ASSERT(strIpAddress.GetLength() <= 15); // xxx.xxx.xxx.xxx
|
|
|
|
pItemList->aVirtRootEntry[cItems].dwMask = pDirEntry->QueryMask();
|
|
|
|
::TextToText(pItemList->aVirtRootEntry[cItems].pszDirectory,
|
|
pDirEntry->QueryDirectory());
|
|
::TextToText(pItemList->aVirtRootEntry[cItems].pszRoot,
|
|
pDirEntry->QueryAlias());
|
|
::TextToText(pItemList->aVirtRootEntry[cItems].pszAccountName,
|
|
pDirEntry->QueryUserName());
|
|
::TextToText(pItemList->aVirtRootEntry[cItems].pszAddress,
|
|
strIpAddress);
|
|
TWSTRCPY(pItemList->aVirtRootEntry[cItems].AccountPassword,
|
|
pDirEntry->QueryPassword(),
|
|
STRSIZE(pItemList->aVirtRootEntry[cItems].AccountPassword));
|
|
}
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
TRACEEOLID("Exception in GetRoots() -- bailing out");
|
|
return NULL;
|
|
}
|
|
END_CATCH_ALL
|
|
|
|
//
|
|
// We should have added everything by now...
|
|
//
|
|
ASSERT(cItems == cListItems);
|
|
|
|
return pItemList;
|
|
}
|
|
|
|
//
|
|
// Destroy root list
|
|
//
|
|
void
|
|
DestroyRoots(
|
|
IN LPINETA_VIRTUAL_ROOT_LIST & pItemList
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
if (pItemList != NULL)
|
|
{
|
|
TRACEEOLID(_T("Destroying vroot list. Size of list = ")
|
|
<< pItemList->cEntries );
|
|
for (DWORD i = 0; i < pItemList->cEntries; ++i)
|
|
{
|
|
TRACEEOLID(_T("Destroying item #") << i);
|
|
delete pItemList->aVirtRootEntry[i].pszDirectory;
|
|
delete pItemList->aVirtRootEntry[i].pszRoot;
|
|
delete pItemList->aVirtRootEntry[i].pszAccountName;
|
|
delete pItemList->aVirtRootEntry[i].pszAddress;
|
|
}
|
|
|
|
delete pItemList;
|
|
pItemList = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Store directory information
|
|
//
|
|
BOOL
|
|
StoreDirList(
|
|
IN CInetAConfigInfo * pii,
|
|
OUT CObOwnedList & oblDirectories
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
CInetAConfigInfo config(*pii);
|
|
LPINETA_VIRTUAL_ROOT_LIST lpVirtualRoots = GetRoots(oblDirectories);
|
|
if (lpVirtualRoots == NULL)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
config.SetValues(
|
|
lpVirtualRoots
|
|
);
|
|
|
|
DWORD err = config.SetInfo(FALSE);
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
DestroyRoots(lpVirtualRoots);
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
::DisplayMessage(err);
|
|
}
|
|
|
|
return err == ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Check to see if the given directory path exists
|
|
// in the list of published directories. Return a
|
|
// pointer to the actual entry if found, or NULL
|
|
// if the item doesn't exist in the list.
|
|
//
|
|
CDirEntry *
|
|
IsDirInList(
|
|
IN LPCTSTR lpszPath,
|
|
IN POSITION & pos,
|
|
IN CObOwnedList & oblDirectories
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
CDirEntry * pDirEntry = NULL;
|
|
|
|
pos = oblDirectories.GetHeadPosition();
|
|
while (pos != NULL)
|
|
{
|
|
pDirEntry = (CDirEntry *)oblDirectories.GetAt(pos);
|
|
ASSERT(pDirEntry != NULL);
|
|
//
|
|
// Truncate trailing backslash (gets added with UNC paths)
|
|
//
|
|
CString strDir( pDirEntry->QueryDirectory() );
|
|
if (strDir[strDir.GetLength() - 1] == _T('\\'))
|
|
{
|
|
strDir.ReleaseBuffer(strDir.GetLength() - 1);
|
|
}
|
|
|
|
if (strDir.CompareNoCase(lpszPath) == 0)
|
|
{
|
|
//
|
|
// Found it!
|
|
//
|
|
return pDirEntry;
|
|
}
|
|
|
|
//
|
|
// Skip to the next
|
|
//
|
|
oblDirectories.GetNext(pos);
|
|
}
|
|
|
|
//
|
|
// Not found...
|
|
//
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Restore some global variables necessary
|
|
// for AFX operations
|
|
//
|
|
void
|
|
SetAfxState()
|
|
{
|
|
::AfxSetResourceHandle(hInstance);
|
|
afxCurrentInstanceHandle = hInstance;
|
|
afxCurrentWinApp = &theApp;
|
|
}
|
|
|
|
/*
|
|
BOOL
|
|
CShellExtApp::InitInstance()
|
|
{
|
|
BOOL bInit = CWinApp::InitInstance();
|
|
|
|
//
|
|
// Extension DLL one-time initialization
|
|
//
|
|
g_hmodThisDll = AfxGetInstanceHandle();
|
|
::AfxSetResourceHandle(g_hmodThisDll);
|
|
afxCurrentInstanceHandle = g_hmodThisDll;
|
|
afxCurrentWinApp = this;
|
|
|
|
CWndIpAddress::CreateWindowClass(g_hmodThisDll);
|
|
|
|
DWORD dwSize = MAX_COMPUTERNAME_LENGTH;
|
|
|
|
TRACEEOLID("Getting computer name");
|
|
|
|
//
|
|
// API's require a string list of computer names.
|
|
//
|
|
g_strlServers.RemoveAll();
|
|
|
|
if (GetComputerName(g_strComputerName.GetBuffer(dwSize), &dwSize))
|
|
{
|
|
g_strComputerName.ReleaseBuffer();
|
|
|
|
TRACEEOLID("Computer name is " << g_strComputerName );
|
|
|
|
g_strlServers.AddTail(g_strComputerName);
|
|
|
|
TRACEEOLID("Now checking for installed services");
|
|
|
|
g_fFTPInstalled = IsServiceInstalled(g_strComputerName, SZ_FTPSVCNAME);
|
|
g_fWWWInstalled = IsServiceInstalled(g_strComputerName, SZ_WWWSVCNAME);
|
|
|
|
TRACEEOLID("FTP Installed " << g_fFTPInstalled );
|
|
TRACEEOLID("WWW Installed " << g_fWWWInstalled );
|
|
}
|
|
|
|
return bInit;
|
|
}
|
|
|
|
int
|
|
CShellExtApp::ExitInstance()
|
|
{
|
|
return CWinApp::ExitInstance();
|
|
}
|
|
|
|
CShellExtApp::CShellExtApp(
|
|
LPCTSTR pszAppName
|
|
)
|
|
: CWinApp(pszAppName)
|
|
{
|
|
}
|
|
*/
|
|
|
|
SHOBJECTPROPERTIES g_pSHObjectProperties = NULL;
|
|
|
|
//
|
|
// Stolen from ntshrui\share.cxx
|
|
//
|
|
BOOL
|
|
LoadShellDllEntries(
|
|
VOID
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
static BOOL s_fEntrypointsChecked = FALSE;
|
|
|
|
if (!s_fEntrypointsChecked)
|
|
{
|
|
//
|
|
// Only check once!
|
|
//
|
|
s_fEntrypointsChecked = TRUE;
|
|
|
|
HINSTANCE hShellLibrary = LoadLibrary(_T("shell32.dll"));
|
|
if (NULL != hShellLibrary)
|
|
{
|
|
g_pSHObjectProperties =
|
|
(SHOBJECTPROPERTIES)GetProcAddress(hShellLibrary,
|
|
(LPCSTR)(MAKELONG(SHObjectPropertiesORD, 0)) );
|
|
}
|
|
}
|
|
|
|
return (NULL != g_pSHObjectProperties);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DllCanUnloadNow
|
|
//---------------------------------------------------------------------------
|
|
|
|
STDAPI
|
|
DllCanUnloadNow()
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
TRACEEOLID("In DLLCanUnloadNow " << g_cRefThisDll);
|
|
|
|
return (g_cRefThisDll == 0 ? S_OK : S_FALSE);
|
|
}
|
|
|
|
STDAPI
|
|
DllGetClassObject(
|
|
REFCLSID rclsid,
|
|
REFIID riid,
|
|
LPVOID *ppvOut
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
TRACEEOLID("In DllGetClassObject");
|
|
|
|
*ppvOut = NULL;
|
|
|
|
if (IsEqualIID(rclsid, CLSID_ShellExtension))
|
|
{
|
|
CShellExtClassFactory *pcf = new CShellExtClassFactory;
|
|
|
|
return pcf->QueryInterface(riid, ppvOut);
|
|
}
|
|
|
|
return CLASS_E_CLASSNOTAVAILABLE;
|
|
}
|
|
|
|
CShellExtClassFactory::CShellExtClassFactory()
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
TRACEEOLID("CShellExtClassFactory::CShellExtClassFactory()");
|
|
|
|
m_cRef = 0L;
|
|
|
|
++g_cRefThisDll;
|
|
}
|
|
|
|
CShellExtClassFactory::~CShellExtClassFactory()
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
--g_cRefThisDll;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CShellExtClassFactory::QueryInterface(
|
|
REFIID riid,
|
|
LPVOID FAR *ppv
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
TRACEEOLID("CShellExtClassFactory::QueryInterface()");
|
|
|
|
*ppv = NULL;
|
|
|
|
//
|
|
// Any interface on this object is the object pointer
|
|
//
|
|
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory))
|
|
{
|
|
*ppv = (LPCLASSFACTORY)this;
|
|
|
|
AddRef();
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
CShellExtClassFactory::AddRef()
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
return ++m_cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
CShellExtClassFactory::Release()
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
if (--m_cRef == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return m_cRef;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CShellExtClassFactory::CreateInstance(
|
|
LPUNKNOWN pUnkOuter,
|
|
REFIID riid,
|
|
LPVOID *ppvObj
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
TRACEEOLID("CShellExtClassFactory::CreateInstance()");
|
|
|
|
*ppvObj = NULL;
|
|
|
|
//
|
|
// Shell extensions typically don't support aggregation (inheritance)
|
|
//
|
|
if (pUnkOuter)
|
|
{
|
|
return CLASS_E_NOAGGREGATION;
|
|
}
|
|
|
|
//
|
|
// Create the main shell extension object. The shell will then call
|
|
// QueryInterface with IID_IShellExtInit--this is how shell extensions are
|
|
// initialized.
|
|
//
|
|
LPCSHELLEXT pShellExt = new CShellExt();
|
|
|
|
if (NULL == pShellExt)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return pShellExt->QueryInterface(riid, ppvObj);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CShellExtClassFactory::LockServer(
|
|
BOOL fLock
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
return NOERROR;
|
|
}
|
|
|
|
// ==========================================================================
|
|
//
|
|
// CShellExt
|
|
//
|
|
// ==========================================================================
|
|
CShellExt::CShellExt()
|
|
: m_nIIS(-1),
|
|
m_nBase(-1),
|
|
m_cRef(0L),
|
|
m_pDataObj(NULL)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
TRACEEOLID("CShellExt::CShellExt()");
|
|
|
|
++g_cRefThisDll;
|
|
}
|
|
|
|
CShellExt::~CShellExt()
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
if (m_pDataObj)
|
|
{
|
|
m_pDataObj->Release();
|
|
}
|
|
|
|
--g_cRefThisDll;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CShellExt::QueryInterface(
|
|
REFIID riid,
|
|
LPVOID FAR *ppv
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
*ppv = NULL;
|
|
|
|
if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown))
|
|
{
|
|
TRACEEOLID("CShellExt::QueryInterface()==>IID_IShellExtInit");
|
|
|
|
*ppv = (LPSHELLEXTINIT)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_IContextMenu))
|
|
{
|
|
TRACEEOLID("CShellExt::QueryInterface()==>IID_IContextMenu");
|
|
|
|
*ppv = (LPCONTEXTMENU)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_IExtractIcon))
|
|
{
|
|
TRACEEOLID("CShellExt::QueryInterface()==>IID_IExtractIcon");
|
|
|
|
*ppv = (LPEXTRACTICON)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_IPersistFile))
|
|
{
|
|
TRACEEOLID("CShellExt::QueryInterface()==>IPersistFile");
|
|
|
|
*ppv = (LPPERSISTFILE)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_IShellPropSheetExt))
|
|
{
|
|
TRACEEOLID("CShellExt::QueryInterface()==>IShellPropSheetExt");
|
|
|
|
*ppv = (LPSHELLPROPSHEETEXT)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_IShellCopyHook))
|
|
{
|
|
TRACEEOLID("CShellExt::QueryInterface()==>ICopyHook");
|
|
|
|
*ppv = (LPCOPYHOOK)this;
|
|
}
|
|
|
|
if (*ppv)
|
|
{
|
|
AddRef();
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
TRACEEOLID("CShellExt::QueryInterface()==>Unknown Interface!");
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
CShellExt::AddRef()
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
TRACEEOLID("CShellExt::AddRef()");
|
|
|
|
return ++m_cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
CShellExt::Release()
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
TRACEEOLID("CShellExt::Release()");
|
|
|
|
if (--m_cRef == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return m_cRef;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CShellExt::Initialize(
|
|
LPCITEMIDLIST pIDFolder,
|
|
LPDATAOBJECT pDataObj,
|
|
HKEY hRegKey
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
TRACEEOLID("CShellExt::Initialize()");
|
|
|
|
if (!LoadShellDllEntries())
|
|
{
|
|
TRACEEOLID("Unable to load shell dll entries");
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Initialize can be called more than once
|
|
//
|
|
if (m_pDataObj)
|
|
{
|
|
m_pDataObj->Release();
|
|
}
|
|
|
|
//
|
|
// duplicate the object pointer and registry handle
|
|
//
|
|
if (pDataObj != NULL)
|
|
{
|
|
m_pDataObj = pDataObj;
|
|
pDataObj->AddRef();
|
|
}
|
|
|
|
FORMATETC fmte =
|
|
{
|
|
CF_HDROP,
|
|
(DVTARGETDEVICE FAR *)NULL,
|
|
DVASPECT_CONTENT,
|
|
-1,
|
|
TYMED_HGLOBAL
|
|
};
|
|
|
|
STGMEDIUM medium;
|
|
HRESULT hres = 0;
|
|
|
|
//
|
|
// Paranoid check, m_pDataObj should have something by now...
|
|
//
|
|
if (m_pDataObj != NULL)
|
|
{
|
|
hres = m_pDataObj->GetData(&fmte, &medium);
|
|
}
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
//
|
|
// Find out how many files the user has selected...
|
|
//
|
|
UINT cbFiles = 0;
|
|
LPCSHELLEXT lpcsext = this;
|
|
|
|
if (medium.hGlobal)
|
|
{
|
|
cbFiles = DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, 0, 0);
|
|
}
|
|
|
|
if (cbFiles == 1)
|
|
{
|
|
DragQueryFile((HDROP)medium.hGlobal, 0,
|
|
m_strFileUserClickedOn.GetBuffer(_MAX_PATH), _MAX_PATH);
|
|
m_strFileUserClickedOn.ReleaseBuffer();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This isn't a directory
|
|
//
|
|
m_strFileUserClickedOn.Empty();
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
#define STR_GUID _T("{5a61f7a0-cde1-11cf-9113-00aa00425c62}")
|
|
#define STR_NAME _T("IIS Shell Extention")
|
|
#define STR_THREAD_MODEL _T("Apartment")
|
|
|
|
//
|
|
// Registry Values Definitions
|
|
//
|
|
typedef struct tagVALUE_PAIR
|
|
{
|
|
HKEY hKeyBase;
|
|
BOOL fOwnKey;
|
|
BOOL fOwnValue;
|
|
LPCTSTR lpstrKey;
|
|
LPCTSTR lpstrValueName;
|
|
LPCTSTR lpstrValue; // Blank is replaced with module path
|
|
} VALUE_PAIR;
|
|
|
|
//
|
|
// Registry Entries
|
|
//
|
|
// NOTE: The table must be constructed so that sub keys are listed
|
|
// after their parents, because we delete keys in the same
|
|
// order in which they are declared here.
|
|
//
|
|
VALUE_PAIR g_aValues[] =
|
|
{
|
|
//
|
|
// Base Key DelKey DelVal Key Name Value Name Value
|
|
// ============================================================================================================================================================
|
|
{ HKEY_CLASSES_ROOT, TRUE, FALSE, _T("CLSID\\") STR_GUID _T("\\InProcServer32"), _T(""), _T("") },
|
|
{ HKEY_CLASSES_ROOT, FALSE, FALSE, _T("CLSID\\") STR_GUID _T("\\InProcServer32"), _T("ThreadingModel"), STR_THREAD_MODEL },
|
|
{ HKEY_CLASSES_ROOT, TRUE, FALSE, _T("CLSID\\") STR_GUID, _T(""), STR_NAME },
|
|
|
|
//{ HKEY_CLASSES_ROOT, TRUE, FALSE, _T("Folder\\shellex\\ContextMenuHandlers\\IISSEMenu"), _T(""), STR_GUID },
|
|
//{ HKEY_CLASSES_ROOT, FALSE, TRUE, _T("Folder\\shellex\\ContextMenuHandlers"), _T(""), _T("IISSEMenu") },
|
|
|
|
{ HKEY_CLASSES_ROOT, TRUE, FALSE, _T("Folder\\shellex\\PropertySheetHandlers\\IISSEPage"), _T(""), STR_GUID },
|
|
{ HKEY_CLASSES_ROOT, FALSE, TRUE, _T("Folder\\shellex\\PropertySheetHandlers"), _T(""), _T("IISSEPage") },
|
|
|
|
//{ HKEY_CLASSES_ROOT, FALSE, TRUE, _T("Folder\\shellex\\IconHandler"), _T(""), STR_GUID },
|
|
|
|
{ HKEY_CLASSES_ROOT, TRUE, FALSE, _T("Folder\\shellex\\CopyHookHandlers\\IISCopyHook"), _T(""), STR_GUID },
|
|
|
|
{ HKEY_CLASSES_ROOT, TRUE, FALSE, _T("*\\shellex\\CopyHookHandlers\\IISCopyHook"), _T(""), STR_GUID },
|
|
|
|
{ HKEY_LOCAL_MACHINE, FALSE, TRUE, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"),STR_GUID, STR_NAME },
|
|
};
|
|
|
|
#define NUM_ENTRIES (sizeof(g_aValues) / sizeof(g_aValues[0]))
|
|
|
|
//
|
|
// Auto-registration Entry Point
|
|
//
|
|
STDAPI
|
|
DllRegisterServer(void)
|
|
{
|
|
SetAfxState();
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
CString strKeyName;
|
|
CString strValue;
|
|
CString strValueName;
|
|
CString strModulePath;
|
|
HKEY hKeyBase;
|
|
CRegKey * pRegKey = NULL;
|
|
DWORD err = ERROR_SUCCESS;
|
|
|
|
TRY
|
|
{
|
|
do
|
|
{
|
|
//
|
|
// Build current module path
|
|
//
|
|
HINSTANCE hCurrent = ::AfxGetInstanceHandle();
|
|
if (hCurrent == NULL)
|
|
{
|
|
err = ERROR_INVALID_HANDLE;
|
|
break;
|
|
}
|
|
|
|
if (::GetModuleFileName(hCurrent,
|
|
strModulePath.GetBuffer(MAX_PATH), MAX_PATH) == 0)
|
|
{
|
|
err = ::GetLastError();
|
|
break;
|
|
}
|
|
strModulePath.ReleaseBuffer();
|
|
TRACEEOLID("Module path is " << strModulePath);
|
|
|
|
//
|
|
// Loop through the entries.
|
|
// If the reg value is blank, use the module path
|
|
//
|
|
for (int i = 0; i < NUM_ENTRIES; ++i)
|
|
{
|
|
hKeyBase = g_aValues[i].hKeyBase;
|
|
ASSERT (hKeyBase != NULL);
|
|
strKeyName = g_aValues[i].lpstrKey;
|
|
TRACEEOLID("Key Name is " << strKeyName);
|
|
pRegKey = new CRegKey(strKeyName, hKeyBase);
|
|
if (pRegKey == NULL || (HKEY)*pRegKey == NULL)
|
|
{
|
|
err = ::GetLastError();
|
|
break;
|
|
}
|
|
strValueName = g_aValues[i].lpstrValueName;
|
|
strValue = g_aValues[i].lpstrValue;
|
|
if (strValue.IsEmpty())
|
|
{
|
|
//
|
|
// Use Module Path
|
|
//
|
|
strValue = strModulePath;
|
|
}
|
|
|
|
TRACEEOLID("Value Name is " << strValueName);
|
|
TRACEEOLID("Value is " << strValue);
|
|
|
|
err = pRegKey->SetValue(strValueName, strValue);
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
delete pRegKey;
|
|
}
|
|
}
|
|
while(FALSE);
|
|
}
|
|
CATCH(CMemoryException, e)
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
END_CATCH
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
::DisplayMessage(err);
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(err);
|
|
}
|
|
|
|
//
|
|
// Auto-(un) registration Entry Point
|
|
//
|
|
STDAPI
|
|
DllUnregisterServer(void)
|
|
{
|
|
SetAfxState();
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
DWORD err = ERROR_SUCCESS;
|
|
|
|
TRY
|
|
{
|
|
do
|
|
{
|
|
//
|
|
// Loop through the entries
|
|
//
|
|
for (int i = 0; i < NUM_ENTRIES; ++i)
|
|
{
|
|
ASSERT(g_aValues[i].hKeyBase != NULL);
|
|
TRACEEOLID("Key Name is " << g_aValues[i].lpstrKey);
|
|
|
|
//
|
|
// Do we own this key? If so delete the whole thing, including
|
|
// its values.
|
|
//
|
|
if (g_aValues[i].fOwnKey)
|
|
{
|
|
err = ::RegDeleteKey(g_aValues[i].hKeyBase, g_aValues[i].lpstrKey);
|
|
}
|
|
//
|
|
// Otherwise, do we own the value? Only delete it then
|
|
//
|
|
else if (g_aValues[i].fOwnValue)
|
|
{
|
|
TRACEEOLID("Value Name is " << g_aValues[i].lpstrValueName);
|
|
TRACEEOLID("Key Name is " << g_aValues[i].lpstrKey);
|
|
|
|
CRegKey rk(g_aValues[i].hKeyBase, g_aValues[i].lpstrKey);
|
|
err = ::RegDeleteValue(rk, g_aValues[i].lpstrValueName);
|
|
}
|
|
|
|
//
|
|
// If the key or value is already gone, that's ok
|
|
//
|
|
if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
|
|
{
|
|
TRACEEOLID("Registry entry was already gone");
|
|
err = ERROR_SUCCESS;
|
|
}
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
while(FALSE);
|
|
}
|
|
CATCH(CMemoryException, e)
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
END_CATCH
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
::DisplayMessage(err);
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(err);
|
|
}
|