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.
851 lines
22 KiB
851 lines
22 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
nwshext.cxx
|
|
|
|
Abstract:
|
|
|
|
This module implements the basics of shell extension classes.
|
|
It includes AddRef(), Release(), QueryInterface() of the
|
|
following classes.
|
|
CNWObjContextMenuClassFactory, CNWObjContextMenu
|
|
CNWFldContextMenuClassFactory, CNWFldContextMenu
|
|
CNWHoodContextMenuClassFactory, CNWHoodContextMenu
|
|
|
|
|
|
Author:
|
|
|
|
Yi-Hsin Sung (yihsins) 25-Oct-1995
|
|
|
|
--*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
|
|
#include <shellapi.h>
|
|
#include <shlobj.h>
|
|
#include <stdio.h>
|
|
#define DONT_WANT_SHELLDEBUG
|
|
#include <shlobjp.h>
|
|
|
|
#include <nwreg.h>
|
|
|
|
#include "nwshcmn.h"
|
|
#include "nwshext.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 "nwclsid.h"
|
|
#pragma data_seg()
|
|
|
|
//
|
|
// Global variables
|
|
//
|
|
LONG g_cRefThisDll = 0; // Reference count of this DLL.
|
|
WCHAR g_szProviderName[256]; // Store the provider name
|
|
|
|
HINSTANCE g_hShellLibrary = NULL;
|
|
SHELLGETNETRESOURCE g_pFuncSHGetNetResource = NULL;
|
|
SHELLDRAGQUERYFILE g_pFuncSHDragQueryFile = NULL;
|
|
SHELLCHANGENOTIFY g_pFuncSHChangeNotify = NULL;
|
|
SHELLEXECUTEEX g_pFuncSHExecuteEx = NULL;
|
|
|
|
|
|
#if DBG
|
|
WCHAR szDebugStr[256]; // For Debug Output
|
|
#endif
|
|
|
|
BOOL LoadShellDllEntries( VOID );
|
|
|
|
extern "C"
|
|
{
|
|
//---------------------------------------------------------------------------
|
|
// NwCleanupShellExtension
|
|
//---------------------------------------------------------------------------
|
|
|
|
VOID NwCleanupShellExtensions( VOID )
|
|
{
|
|
if ( g_hShellLibrary )
|
|
{
|
|
FreeLibrary( g_hShellLibrary );
|
|
g_hShellLibrary = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DllCanUnloadNow
|
|
//---------------------------------------------------------------------------
|
|
|
|
STDAPI DllCanUnloadNow(void)
|
|
{
|
|
#if DBG
|
|
wsprintf( szDebugStr,L"In DLLCanUnloadNow: g_cRefThisDll = %d\r\n", g_cRefThisDll);
|
|
ODS( szDebugStr );
|
|
#endif
|
|
|
|
return ResultFromScode((g_cRefThisDll == 0) ? S_OK : S_FALSE);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DllGetClassObject
|
|
//---------------------------------------------------------------------------
|
|
|
|
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut)
|
|
{
|
|
*ppvOut = NULL;
|
|
|
|
if ( !LoadShellDllEntries() )
|
|
return ResultFromScode(CLASS_E_CLASSNOTAVAILABLE);
|
|
|
|
if (IsEqualIID(rclsid, CLSID_NetWareObjectExt))
|
|
{
|
|
CNWObjContextMenuClassFactory *pcf = new CNWObjContextMenuClassFactory;
|
|
|
|
if ( pcf == NULL )
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
HRESULT hr = pcf->QueryInterface(riid, ppvOut);
|
|
|
|
if ( FAILED(hr) )
|
|
delete pcf;
|
|
|
|
return hr;
|
|
}
|
|
else if (IsEqualIID(rclsid, CLSID_NetWareFolderMenuExt))
|
|
{
|
|
CNWFldContextMenuClassFactory *pcf = new CNWFldContextMenuClassFactory;
|
|
|
|
if ( pcf == NULL )
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
HRESULT hr = pcf->QueryInterface(riid, ppvOut);
|
|
|
|
if ( FAILED(hr) )
|
|
delete pcf;
|
|
|
|
return hr;
|
|
}
|
|
else if (IsEqualIID(rclsid, CLSID_NetworkNeighborhoodMenuExt))
|
|
{
|
|
CNWHoodContextMenuClassFactory *pcf= new CNWHoodContextMenuClassFactory;
|
|
|
|
if ( pcf == NULL )
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
HRESULT hr = pcf->QueryInterface(riid, ppvOut);
|
|
|
|
if ( FAILED(hr) )
|
|
delete pcf;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
return ResultFromScode(CLASS_E_CLASSNOTAVAILABLE);
|
|
}
|
|
|
|
BOOL LoadShellDllEntries( VOID )
|
|
{
|
|
static BOOL s_fLoaded = FALSE;
|
|
|
|
if ( !s_fLoaded )
|
|
{
|
|
DWORD err;
|
|
HKEY hkey;
|
|
|
|
g_hShellLibrary = LoadLibrary( L"shell32.dll");
|
|
if ( g_hShellLibrary != NULL )
|
|
{
|
|
s_fLoaded = TRUE;
|
|
|
|
g_pFuncSHGetNetResource =
|
|
(SHELLGETNETRESOURCE) GetProcAddress( g_hShellLibrary,
|
|
(LPCSTR)(MAKELONG(SHGetNetResourceORD, 0)) );
|
|
|
|
g_pFuncSHDragQueryFile =
|
|
(SHELLDRAGQUERYFILE) GetProcAddress( g_hShellLibrary,
|
|
(LPCSTR) "DragQueryFileW");
|
|
g_pFuncSHChangeNotify =
|
|
(SHELLCHANGENOTIFY) GetProcAddress( g_hShellLibrary,
|
|
(LPCSTR) "SHChangeNotify");
|
|
g_pFuncSHExecuteEx =
|
|
(SHELLEXECUTEEX) GetProcAddress( g_hShellLibrary,
|
|
(LPCSTR) "ShellExecuteExW");
|
|
}
|
|
|
|
// Set the default provider name in case we fail to read
|
|
// it from the registry.
|
|
wcscpy( g_szProviderName, L"NetWare or Compatible Network");
|
|
|
|
//
|
|
// Read the Network Provider Name.
|
|
//
|
|
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
|
|
// \NWCWorkstation\networkprovider
|
|
//
|
|
err = RegOpenKeyExW(
|
|
HKEY_LOCAL_MACHINE,
|
|
NW_WORKSTATION_PROVIDER_PATH,
|
|
REG_OPTION_NON_VOLATILE, // options
|
|
KEY_READ, // desired access
|
|
&hkey
|
|
);
|
|
|
|
if ( err == NO_ERROR )
|
|
{
|
|
LPWSTR pszProviderName = NULL;
|
|
|
|
//
|
|
// ignore the return code. if fail, pszProviderName is NULL
|
|
//
|
|
err = NwReadRegValue(
|
|
hkey,
|
|
NW_PROVIDER_VALUENAME,
|
|
&pszProviderName // free with LocalFree
|
|
);
|
|
|
|
if ( err == NO_ERROR && pszProviderName != NULL )
|
|
{
|
|
wcscpy( g_szProviderName, pszProviderName );
|
|
LocalFree( pszProviderName );
|
|
}
|
|
|
|
RegCloseKey( hkey );
|
|
}
|
|
}
|
|
|
|
return s_fLoaded;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// CNWObjContextMenuClassFactory
|
|
//---------------------------------------------------------------------------
|
|
|
|
CNWObjContextMenuClassFactory::CNWObjContextMenuClassFactory()
|
|
{
|
|
_cRef = 0L;
|
|
InterlockedIncrement( &g_cRefThisDll );
|
|
|
|
#if DBG
|
|
wsprintf( szDebugStr,L"CNWObjContextMenuClassFactory::CNWObjContextMenuClassFactory(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
|
|
ODS( szDebugStr );
|
|
#endif
|
|
}
|
|
|
|
CNWObjContextMenuClassFactory::~CNWObjContextMenuClassFactory()
|
|
{
|
|
InterlockedDecrement( &g_cRefThisDll );
|
|
|
|
#if DBG
|
|
wsprintf( szDebugStr,L"CNWObjContextMenuClassFactory::~CNWObjContextMenuClassFactory(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
|
|
ODS( szDebugStr );
|
|
#endif
|
|
}
|
|
|
|
STDMETHODIMP CNWObjContextMenuClassFactory::QueryInterface(REFIID riid,
|
|
LPVOID FAR *ppv)
|
|
{
|
|
*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 ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CNWObjContextMenuClassFactory::AddRef()
|
|
{
|
|
return ++_cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CNWObjContextMenuClassFactory::Release()
|
|
{
|
|
if (--_cRef)
|
|
return _cRef;
|
|
|
|
delete this;
|
|
|
|
return 0L;
|
|
}
|
|
|
|
STDMETHODIMP CNWObjContextMenuClassFactory::CreateInstance(LPUNKNOWN pUnkOuter,
|
|
REFIID riid,
|
|
LPVOID *ppvObj)
|
|
{
|
|
*ppvObj = NULL;
|
|
|
|
// Shell extensions typically don't support aggregation (inheritance)
|
|
|
|
if (pUnkOuter)
|
|
return ResultFromScode(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.
|
|
|
|
LPCNWOBJCONTEXTMENU pShellExt = new CNWObjContextMenu(); // Create the CNWObjContextMenu object
|
|
|
|
if (NULL == pShellExt)
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
//
|
|
// We set the reference count of CNWObjContextMenu to one at initialization.
|
|
// Hence, we can call Release() after QueryInterface.
|
|
// So, if QueryInterface failed, Release will free the object.
|
|
//
|
|
|
|
HRESULT hr = pShellExt->QueryInterface(riid, ppvObj);
|
|
pShellExt->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CNWObjContextMenuClassFactory::LockServer(BOOL fLock)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// CNWObjContextMenu
|
|
//---------------------------------------------------------------------------
|
|
|
|
CNWObjContextMenu::CNWObjContextMenu()
|
|
{
|
|
_cRef = 1L;
|
|
_pDataObj = NULL;
|
|
|
|
_fGotClusterInfo = FALSE;
|
|
_dwTotal = 0;
|
|
_dwFree = 0;
|
|
|
|
InterlockedIncrement( &g_cRefThisDll );
|
|
|
|
#if DBG
|
|
wsprintf( szDebugStr,L"CNWObjContextMenu::CNWObjContextMenu(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
|
|
ODS( szDebugStr );
|
|
#endif
|
|
}
|
|
|
|
CNWObjContextMenu::~CNWObjContextMenu()
|
|
{
|
|
if (_pDataObj)
|
|
_pDataObj->Release();
|
|
|
|
InterlockedDecrement( &g_cRefThisDll );
|
|
|
|
#if DBG
|
|
wsprintf( szDebugStr,L"CNWObjContextMenu::~CNWObjContextMenu(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
|
|
ODS( szDebugStr );
|
|
#endif
|
|
}
|
|
|
|
STDMETHODIMP CNWObjContextMenu::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;
|
|
}
|
|
else if (IsEqualIID(riid, IID_IShellPropSheetExt))
|
|
{
|
|
*ppv = (LPSHELLPROPSHEETEXT)this;
|
|
}
|
|
|
|
if (*ppv)
|
|
{
|
|
AddRef();
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CNWObjContextMenu::AddRef()
|
|
{
|
|
return ++_cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CNWObjContextMenu::Release()
|
|
{
|
|
if (--_cRef)
|
|
return _cRef;
|
|
|
|
delete this;
|
|
|
|
return 0L;
|
|
}
|
|
|
|
//
|
|
// FUNCTION: CNWObjContextMenu::Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY)
|
|
//
|
|
// PURPOSE: Called by the shell when initializing a context menu or property
|
|
// sheet extension.
|
|
//
|
|
// PARAMETERS:
|
|
// pIDFolder - Specifies the parent folder
|
|
// pDataObj - Spefifies the set of items selected in that folder.
|
|
// hRegKey - Specifies the type of the focused item in the selection.
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// NOERROR in all cases.
|
|
//
|
|
// COMMENTS: Note that at the time this function is called, we don't know
|
|
// (or care) what type of shell extension is being initialized.
|
|
// It could be a context menu or a property sheet.
|
|
//
|
|
|
|
STDMETHODIMP CNWObjContextMenu::Initialize( LPCITEMIDLIST pIDFolder,
|
|
LPDATAOBJECT pDataObj,
|
|
HKEY hRegKey)
|
|
{
|
|
// We do not need the registry handle so ignore it.
|
|
|
|
// Initialize can be called more than once
|
|
|
|
if (_pDataObj)
|
|
_pDataObj->Release();
|
|
|
|
// Duplicate the object pointer
|
|
|
|
if (pDataObj)
|
|
{
|
|
_pDataObj = pDataObj;
|
|
pDataObj->AddRef();
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// CNWFldContextMenuClassFactory
|
|
//---------------------------------------------------------------------------
|
|
|
|
CNWFldContextMenuClassFactory::CNWFldContextMenuClassFactory()
|
|
{
|
|
_cRef = 0L;
|
|
InterlockedIncrement( &g_cRefThisDll );
|
|
|
|
#if DBG
|
|
wsprintf( szDebugStr,L"CNWFldContextMenuClassFactory::CNWFldContextMenuClassFactory(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
|
|
ODS( szDebugStr );
|
|
#endif
|
|
}
|
|
|
|
CNWFldContextMenuClassFactory::~CNWFldContextMenuClassFactory()
|
|
{
|
|
InterlockedDecrement( &g_cRefThisDll );
|
|
|
|
#if DBG
|
|
wsprintf( szDebugStr,L"CNWFldContextMenuClassFactory::~CNWFldContextMenuClassFactory(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
|
|
ODS( szDebugStr );
|
|
#endif
|
|
}
|
|
|
|
STDMETHODIMP CNWFldContextMenuClassFactory::QueryInterface(REFIID riid,
|
|
LPVOID FAR *ppv)
|
|
{
|
|
*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 ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CNWFldContextMenuClassFactory::AddRef()
|
|
{
|
|
return ++_cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CNWFldContextMenuClassFactory::Release()
|
|
{
|
|
if (--_cRef)
|
|
return _cRef;
|
|
|
|
delete this;
|
|
|
|
return 0L;
|
|
}
|
|
|
|
STDMETHODIMP CNWFldContextMenuClassFactory::CreateInstance(LPUNKNOWN pUnkOuter,
|
|
REFIID riid,
|
|
LPVOID *ppvObj)
|
|
{
|
|
*ppvObj = NULL;
|
|
|
|
// Shell extensions typically don't support aggregation (inheritance)
|
|
|
|
if (pUnkOuter)
|
|
return ResultFromScode(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.
|
|
|
|
LPCNWFLDCONTEXTMENU pShellExt = new CNWFldContextMenu(); // Create the CNWFldContextMenu object
|
|
|
|
if (NULL == pShellExt)
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
//
|
|
// We set the reference count of CNWFldContextMenu to one at initialization.
|
|
// Hence, we can call Release() after QueryInterface.
|
|
// So, if QueryInterface failed, Release will free the object.
|
|
//
|
|
|
|
HRESULT hr = pShellExt->QueryInterface(riid, ppvObj);
|
|
pShellExt->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CNWFldContextMenuClassFactory::LockServer(BOOL fLock)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// CNWFldContextMenu
|
|
//---------------------------------------------------------------------------
|
|
|
|
CNWFldContextMenu::CNWFldContextMenu()
|
|
{
|
|
_cRef = 1L;
|
|
_pDataObj = NULL;
|
|
|
|
InterlockedIncrement( &g_cRefThisDll );
|
|
|
|
#if DBG
|
|
wsprintf( szDebugStr,L"CNWFldContextMenu::CNWFldContextMenu(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
|
|
ODS( szDebugStr );
|
|
#endif
|
|
}
|
|
|
|
CNWFldContextMenu::~CNWFldContextMenu()
|
|
{
|
|
if (_pDataObj)
|
|
_pDataObj->Release();
|
|
|
|
InterlockedDecrement( &g_cRefThisDll );
|
|
|
|
#if DBG
|
|
wsprintf( szDebugStr,L"CNWFldContextMenu::~CNWFldContextMenu(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
|
|
ODS( szDebugStr );
|
|
#endif
|
|
}
|
|
|
|
STDMETHODIMP CNWFldContextMenu::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 ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CNWFldContextMenu::AddRef()
|
|
{
|
|
return ++_cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CNWFldContextMenu::Release()
|
|
{
|
|
if (--_cRef)
|
|
return _cRef;
|
|
|
|
delete this;
|
|
|
|
return 0L;
|
|
}
|
|
|
|
//
|
|
// FUNCTION: CNWFldContextMenu::Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY)
|
|
//
|
|
// PURPOSE: Called by the shell when initializing a context menu or property
|
|
// sheet extension.
|
|
//
|
|
// PARAMETERS:
|
|
// pIDFolder - Specifies the parent folder
|
|
// pDataObj - Spefifies the set of items selected in that folder.
|
|
// hRegKey - Specifies the type of the focused item in the selection.
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// NOERROR in all cases.
|
|
//
|
|
// COMMENTS: Note that at the time this function is called, we don't know
|
|
// (or care) what type of shell extension is being initialized.
|
|
// It could be a context menu or a property sheet.
|
|
//
|
|
|
|
STDMETHODIMP CNWFldContextMenu::Initialize( LPCITEMIDLIST pIDFolder,
|
|
LPDATAOBJECT pDataObj,
|
|
HKEY hRegKey)
|
|
{
|
|
// We do not need the registry handle so ignore it.
|
|
|
|
// Initialize can be called more than once
|
|
|
|
if (_pDataObj)
|
|
_pDataObj->Release();
|
|
|
|
// Duplicate the object pointer
|
|
|
|
if (pDataObj)
|
|
{
|
|
_pDataObj = pDataObj;
|
|
pDataObj->AddRef();
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// CNWHoodContextMenuClassFactory
|
|
//---------------------------------------------------------------------------
|
|
|
|
CNWHoodContextMenuClassFactory::CNWHoodContextMenuClassFactory()
|
|
{
|
|
_cRef = 0L;
|
|
InterlockedIncrement( &g_cRefThisDll );
|
|
|
|
#if DBG
|
|
wsprintf( szDebugStr,L"CNWHoodContextMenuClassFactory::CNWHoodContextMenuClassFactory(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
|
|
ODS( szDebugStr );
|
|
#endif
|
|
}
|
|
|
|
CNWHoodContextMenuClassFactory::~CNWHoodContextMenuClassFactory()
|
|
{
|
|
InterlockedDecrement( &g_cRefThisDll );
|
|
|
|
#if DBG
|
|
wsprintf( szDebugStr,L"CNWHoodContextMenuClassFactory::~CNWHoodContextMenuClassFactory(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
|
|
ODS( szDebugStr );
|
|
#endif
|
|
}
|
|
|
|
STDMETHODIMP CNWHoodContextMenuClassFactory::QueryInterface(REFIID riid,
|
|
LPVOID FAR *ppv)
|
|
{
|
|
*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 ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CNWHoodContextMenuClassFactory::AddRef()
|
|
{
|
|
return ++_cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CNWHoodContextMenuClassFactory::Release()
|
|
{
|
|
if (--_cRef)
|
|
return _cRef;
|
|
|
|
delete this;
|
|
|
|
return 0L;
|
|
}
|
|
|
|
STDMETHODIMP CNWHoodContextMenuClassFactory::CreateInstance(LPUNKNOWN pUnkOuter,
|
|
REFIID riid,
|
|
LPVOID *ppvObj)
|
|
{
|
|
*ppvObj = NULL;
|
|
|
|
// Shell extensions typically don't support aggregation (inheritance)
|
|
|
|
if (pUnkOuter)
|
|
return ResultFromScode(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.
|
|
|
|
LPCNWHOODCONTEXTMENU pShellExt = new CNWHoodContextMenu(); // Create the CNWHoodContextMenu object
|
|
|
|
if (NULL == pShellExt)
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
//
|
|
// We set the reference count of CNWHoodContextMenu to one at initialization.
|
|
// Hence, we can call Release() after QueryInterface.
|
|
// So, if QueryInterface failed, Release will free the object.
|
|
//
|
|
|
|
HRESULT hr = pShellExt->QueryInterface(riid, ppvObj);
|
|
pShellExt->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CNWHoodContextMenuClassFactory::LockServer(BOOL fLock)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// CNWHoodContextMenu
|
|
//---------------------------------------------------------------------------
|
|
|
|
CNWHoodContextMenu::CNWHoodContextMenu()
|
|
{
|
|
_cRef = 1L;
|
|
_pDataObj = NULL;
|
|
|
|
InterlockedIncrement( &g_cRefThisDll );
|
|
|
|
#if DBG
|
|
wsprintf( szDebugStr,L"CNWHoodContextMenu::CNWHoodContextMenu(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
|
|
ODS( szDebugStr );
|
|
#endif
|
|
}
|
|
|
|
CNWHoodContextMenu::~CNWHoodContextMenu()
|
|
{
|
|
if (_pDataObj)
|
|
_pDataObj->Release();
|
|
|
|
InterlockedDecrement( &g_cRefThisDll );
|
|
|
|
#if DBG
|
|
wsprintf( szDebugStr,L"CNWHoodContextMenu::~CNWHoodContextMenu(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
|
|
ODS( szDebugStr );
|
|
#endif
|
|
}
|
|
|
|
STDMETHODIMP CNWHoodContextMenu::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 ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CNWHoodContextMenu::AddRef()
|
|
{
|
|
return ++_cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CNWHoodContextMenu::Release()
|
|
{
|
|
if (--_cRef)
|
|
return _cRef;
|
|
|
|
delete this;
|
|
|
|
return 0L;
|
|
}
|
|
|
|
//
|
|
// FUNCTION: CNWHoodContextMenu::Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY)
|
|
//
|
|
// PURPOSE: Called by the shell when initializing a context menu or property
|
|
// sheet extension.
|
|
//
|
|
// PARAMETERS:
|
|
// pIDFolder - Specifies the parent folder
|
|
// pDataObj - Spefifies the set of items selected in that folder.
|
|
// hRegKey - Specifies the type of the focused item in the selection.
|
|
//
|
|
// RETURN VALUE:
|
|
//
|
|
// NOERROR in all cases.
|
|
//
|
|
// COMMENTS: Note that at the time this function is called, we don't know
|
|
// (or care) what type of shell extension is being initialized.
|
|
// It could be a context menu or a property sheet.
|
|
//
|
|
|
|
STDMETHODIMP CNWHoodContextMenu::Initialize( LPCITEMIDLIST pIDFolder,
|
|
LPDATAOBJECT pDataObj,
|
|
HKEY hRegKey)
|
|
{
|
|
// We do not need the registry handle so ignore it.
|
|
|
|
// Initialize can be called more than once
|
|
|
|
if (_pDataObj)
|
|
_pDataObj->Release();
|
|
|
|
// Duplicate the object pointer
|
|
|
|
if (pDataObj)
|
|
{
|
|
_pDataObj = pDataObj;
|
|
pDataObj->AddRef();
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|