windows-nt/Source/XPSP1/NT/ds/nw/svcdlls/nwwks/client/nwshext.cxx
2020-09-26 16:20:57 +08:00

852 lines
21 KiB
C++

/*++
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;
}