diff options
Diffstat (limited to '')
-rw-r--r-- | private/nw/svcdlls/nwwks/client/nwshext.cxx | 854 |
1 files changed, 854 insertions, 0 deletions
diff --git a/private/nw/svcdlls/nwwks/client/nwshext.cxx b/private/nw/svcdlls/nwwks/client/nwshext.cxx new file mode 100644 index 000000000..4818a3823 --- /dev/null +++ b/private/nw/svcdlls/nwwks/client/nwshext.cxx @@ -0,0 +1,854 @@ +/*++ + +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 + +--*/ + +extern "C" +{ +#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 <shsemip.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; +} + |