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.
5624 lines
182 KiB
5624 lines
182 KiB
//---------------------------------------------------------------------------
|
|
//
|
|
// Copyright (c) Microsoft Corporation 1991-1993
|
|
//
|
|
// File: netviewx.c
|
|
//
|
|
// History:
|
|
// 12-06-93 SatoNa Created.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "shellprv.h"
|
|
#pragma hdrstop
|
|
|
|
#ifdef USE_OLEDB
|
|
#include "oledbshl.h"
|
|
#endif
|
|
|
|
#include <shguidp.h>
|
|
|
|
#pragma warning(disable:4200) // Zero-sized array in struct
|
|
|
|
//
|
|
// Use WNetConnectionDialog1
|
|
//
|
|
#define WNETCONNECTIONDIALOG1
|
|
|
|
// Internal function prototypes
|
|
void CNetRes_FillNetResource(LPCITEMIDLIST pidlAbs, LPNETRESOURCE pnr,
|
|
LPTSTR pszProviderBuff, UINT cchProviderBuff,
|
|
LPTSTR pszRemoteBuff, UINT cchRemoteBuff);
|
|
HKEY CNetwork_OpenProviderTypeKey(LPCITEMIDLIST pidlAbs);
|
|
HKEY CNetwork_OpenProviderKey(LPCITEMIDLIST pidlAbs);
|
|
HRESULT CNETDetails_Create(HWND hwndMain, LPVOID * ppvOut);
|
|
HRESULT CNETIDLData_GetNetResource(IDataObject *pdtobj, LPSTGMEDIUM pmedium);
|
|
HRESULT CNETIDLData_GetHDrop(IDataObject *pdtobj, LPSTGMEDIUM pmedium);
|
|
|
|
LPTSTR NET_CopyProviderNameAbs(LPCITEMIDLIST pidlAbs, LPTSTR pszBuff, UINT cchBuff);
|
|
LPTSTR NET_CopyProviderNameRelative(LPCITEMIDLIST pidlRelative, LPTSTR pszBuff, UINT cchBuff);
|
|
|
|
|
|
#pragma pack(1)
|
|
typedef struct _IDNETRESOURCE // idn
|
|
{
|
|
WORD cb;
|
|
BYTE bFlags; // Display type in low nibble
|
|
BYTE uType;
|
|
BYTE uUsage; // Usage in low nibble, More Flags in high nibble
|
|
CHAR szNetResName[1];
|
|
// char szProvider[*] - If NET_HASPROVIDER bit is set
|
|
// char szComment[*] - If NET_HASCOMMENT bit is set.
|
|
// WCHAR szNetResNameWide[*] - If NET_UNICODE bit it set.
|
|
// WCHAR szProviderWide[*] - If NET_UNICODE and NET_HASPROVIDER
|
|
// WCHAR szCommentWide[*] - If NET_UNICODE and NET_HASCOMMENT
|
|
} IDNETRESOURCE, *LPIDNETRESOURCE;
|
|
typedef const IDNETRESOURCE *LPCIDNETRESOURCE;
|
|
#pragma pack()
|
|
|
|
//
|
|
// By the way...Win95 shipped with the below provider
|
|
// names. Since the name can be changed and be localized,
|
|
// we have to try and map these correctly for net pidl
|
|
// interop.
|
|
//
|
|
typedef struct _NETPROVIDERS
|
|
{
|
|
LPCTSTR lpName;
|
|
WORD wNetType;
|
|
} NETPROVIDERS, *LPNETPROVIDERS;
|
|
|
|
const TCHAR szMSNet[] = TEXT("Microsoft Network");
|
|
const TCHAR szNWNet[] = TEXT("NetWare");
|
|
|
|
const NETPROVIDERS aChiProv[] = {
|
|
{ szMSNet, HIWORD(WNNC_NET_LANMAN) },
|
|
{ szNWNet, HIWORD(WNNC_NET_NETWARE) }
|
|
};
|
|
#define WNNC_NET_LARGEST WNNC_NET_SYMFONET
|
|
|
|
//===========================================================================
|
|
// CNetwork: Some private macro
|
|
//===========================================================================
|
|
|
|
#define NET_DISPLAYNAMEOFFSET ((UINT)((LPIDNETRESOURCE)0)->szNetResName)
|
|
#define NET_GetFlags(pidnRel) ((pidnRel)->bFlags)
|
|
#define NET_GetDisplayType(pidnRel) ((pidnRel)->bFlags & 0x0f)
|
|
#define NET_GetType(pidnRel) ((pidnRel)->uType)
|
|
#define NET_GetUsage(pidnRel) ((pidnRel)->uUsage & 0x0f)
|
|
#define NET_IsReg(pidnRel) ((pidnRel)->bFlags == SHID_NET_REGITEM)
|
|
#define NET_IsJunction(pidnRel) ((pidnRel)->bFlags & SHID_JUNCTION)
|
|
|
|
|
|
// Define some Flags that are on high nibble of uUsage byte
|
|
#define NET_HASPROVIDER 0x80 // Has own copy of provider
|
|
#define NET_HASCOMMENT 0x40 // Has comment field in pidl
|
|
#define NET_REMOTEFLD 0x20 // Is remote folder
|
|
#define NET_UNICODE 0x10 // Has unicode names
|
|
#define NET_FHasComment(pidnRel) ((pidnRel)->uUsage & NET_HASCOMMENT)
|
|
#define NET_FHasProvider(pidnRel) ((pidnRel)->uUsage & NET_HASPROVIDER)
|
|
#define NET_IsRemoteFld(pidnRel) ((pidnRel)->uUsage & NET_REMOTEFLD)
|
|
#define NET_IsUnicode(pidnRel) ((pidnRel)->uUsage & NET_UNICODE)
|
|
|
|
// Define a collate order for the hood object types
|
|
#define HOOD_COL_RON 0
|
|
#define HOOD_COL_REMOTE 1
|
|
#define HOOD_COL_FILE 2
|
|
#define HOOD_COL_NET 3
|
|
|
|
#define PTROFFSET(pBase, p) ((LPBYTE)(p) - (LPBYTE)(pBase))
|
|
|
|
LPTSTR NET_CopyComment(LPIDNETRESOURCE pidn, LPTSTR pszBuff, UINT cchBuff);
|
|
LPTSTR NET_CopyResName(LPCIDNETRESOURCE pidn, LPTSTR pszBuff, UINT cchBuff);
|
|
|
|
enum
|
|
{
|
|
ICOL_NAME = 0,
|
|
ICOL_COMMENT,
|
|
ICOL_MAX, // Make sure this is the last enum item
|
|
};
|
|
|
|
|
|
|
|
//===========================================================================
|
|
// CNetwork: class definition
|
|
//===========================================================================
|
|
|
|
typedef struct _CNetRes
|
|
{
|
|
IShellFolder sf;
|
|
IPersistFolder pf;
|
|
UINT cRef;
|
|
LPCITEMIDLIST pidl; // Absolute IDList
|
|
IShellFolder* psf; // this is the actual IShellFolder pointer.
|
|
// it will point to the "aggregated"
|
|
// regitem IShellFolder for Server objects,
|
|
// otherwise it will point to this->sf.
|
|
BOOL bRemote; // TRUE if remote computer. If TRUE, must RegClose(hkRegItems) and ILFree(pidlRemote) on destruction.
|
|
HKEY hkRegItems;
|
|
LPCITEMIDLIST pidlRemote;
|
|
|
|
} CNetRes, * LPNETRES;
|
|
|
|
|
|
typedef struct _CNetHood
|
|
{
|
|
IShellFolder *psfNetHood;
|
|
LPITEMIDLIST pidlNetHood;
|
|
} CNetHood, * LPNETHOOD;
|
|
|
|
//===========================================================================
|
|
// CNetwork: member prototype
|
|
//===========================================================================
|
|
|
|
STDMETHODIMP CNetRes_SF_QueryInterface(LPSHELLFOLDER psf, REFIID riid, LPVOID * ppvObj);
|
|
STDMETHODIMP_(ULONG) CNetRes_AddRef(LPSHELLFOLDER psf);
|
|
STDMETHODIMP_(ULONG) CNetRes_Release(LPSHELLFOLDER psf);
|
|
STDMETHODIMP CNetwork_ParseDisplayName(LPSHELLFOLDER psf, HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
|
|
ULONG * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes);
|
|
STDMETHODIMP CNetRoot_SF_QueryInterface(LPSHELLFOLDER psf, REFIID riid, LPVOID * ppvObj);
|
|
STDMETHODIMP CNetRoot_EnumObjects( LPSHELLFOLDER psf, HWND hwndOwner, DWORD grfFlags, LPENUMIDLIST * ppenumUnknown);
|
|
STDMETHODIMP CNetRes_EnumObjects( LPSHELLFOLDER psf, HWND hwndOwner, DWORD grfFlags, LPENUMIDLIST * ppenumUnknown);
|
|
STDMETHODIMP CNetwork_BindToObject(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPBC pbc,
|
|
REFIID riid, LPVOID * ppvOut);
|
|
STDMETHODIMP CNetwork_CompareIDs(LPSHELLFOLDER psf, LPARAM iCol, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
|
|
STDMETHODIMP CNetwork_CreateViewObject(LPSHELLFOLDER psf, HWND hwnd, REFIID riid, LPVOID * ppvOut);
|
|
STDMETHODIMP CNetwork_GetAttributesOf(LPSHELLFOLDER psf, UINT cidl, LPCITEMIDLIST * apidl, ULONG * rgfOut);
|
|
STDMETHODIMP CNetwork_GetUIObjectOf(LPSHELLFOLDER psf, HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl,
|
|
REFIID riid, UINT * prgfInOut, LPVOID * ppvOut);
|
|
STDMETHODIMP CNetwork_GetDisplayNameOf(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, DWORD dwReserved, LPSTRRET pStrRet);
|
|
STDMETHODIMP CNetwork_SetNameOf(LPSHELLFOLDER psf, HWND hwndOwner,
|
|
LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD dwReserved, LPITEMIDLIST * ppidlOut);
|
|
|
|
STDMETHODIMP CNetRoot_PF_QueryInterface(LPPERSISTFOLDER fld, REFIID riid, LPVOID * ppvObj);
|
|
STDMETHODIMP_(ULONG) CNetRoot_PF_AddRef(LPPERSISTFOLDER fld);
|
|
STDMETHODIMP_(ULONG) CNetRoot_PF_Release(LPPERSISTFOLDER fld);
|
|
STDMETHODIMP CNetRoot_PF_GetClassID(LPPERSISTFOLDER fld, LPCLSID lpClassID);
|
|
STDMETHODIMP CNetRoot_PF_Initialize(LPPERSISTFOLDER fld, LPCITEMIDLIST pidl);
|
|
STDMETHODIMP CNetRoot_GetAttributesOf(LPSHELLFOLDER psf, UINT cidl, LPCITEMIDLIST * apidl, ULONG * rgfOut);
|
|
STDMETHODIMP CNetRoot_GetUIObjectOf(LPSHELLFOLDER psf, HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl,
|
|
REFIID riid, UINT * prgfInOut, LPVOID * ppvOut);
|
|
STDMETHODIMP CNetRoot_GetDisplayNameOf(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, DWORD dwReserved, LPSTRRET pStrRet);
|
|
STDMETHODIMP CNetRoot_SetNameOf(LPSHELLFOLDER psf, HWND hwndOwner,
|
|
LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD dwReserved, LPITEMIDLIST * ppidlOut);
|
|
STDMETHODIMP CNetRoot_CompareIDs(LPSHELLFOLDER psf, LPARAM iCol, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
|
|
STDMETHODIMP CNetRoot_CreateViewObject(LPSHELLFOLDER psf, HWND hwnd, REFIID riid, LPVOID * ppvOut);
|
|
LPSHELLFOLDER CNetRoot_GetPSF(HWND hwnd);
|
|
LPITEMIDLIST CNetRoot_GetPIDL(HWND hwnd);
|
|
|
|
STDMETHODIMP CNetRootDropTarget_DragEnter(LPDROPTARGET pdropt, LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);
|
|
STDMETHODIMP CNetRootDropTarget_Drop(IDropTarget *pdropt, IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);
|
|
|
|
BOOL _CNetwork_JunctionToFSPath(LPCIDNETRESOURCE pidn, LPTSTR lpszPath);
|
|
|
|
//===========================================================================
|
|
// CNetRoot: Vtable
|
|
//===========================================================================
|
|
IShellFolderVtbl c_NetRootVtbl =
|
|
{
|
|
CNetRoot_SF_QueryInterface,
|
|
CSIShellFolder_AddRef,
|
|
CSIShellFolder_Release,
|
|
CNetwork_ParseDisplayName,
|
|
CNetRoot_EnumObjects,
|
|
CNetwork_BindToObject,
|
|
CDefShellFolder_BindToStorage,
|
|
CNetRoot_CompareIDs,
|
|
CNetRoot_CreateViewObject,
|
|
CNetRoot_GetAttributesOf,
|
|
CNetRoot_GetUIObjectOf,
|
|
CNetRoot_GetDisplayNameOf,
|
|
CNetRoot_SetNameOf,
|
|
};
|
|
|
|
IPersistFolderVtbl c_NetRootVtblPF =
|
|
{
|
|
CNetRoot_PF_QueryInterface,
|
|
CNetRoot_PF_AddRef,
|
|
CNetRoot_PF_Release,
|
|
CNetRoot_PF_GetClassID,
|
|
CNetRoot_PF_Initialize,
|
|
};
|
|
|
|
IShellFolderVtbl c_NetResVtbl =
|
|
{
|
|
CNetRes_SF_QueryInterface,
|
|
CNetRes_AddRef,
|
|
CNetRes_Release,
|
|
CNetwork_ParseDisplayName,
|
|
CNetRes_EnumObjects,
|
|
CNetwork_BindToObject,
|
|
CDefShellFolder_BindToStorage,
|
|
CNetwork_CompareIDs,
|
|
CNetwork_CreateViewObject,
|
|
CNetwork_GetAttributesOf,
|
|
CNetwork_GetUIObjectOf,
|
|
CNetwork_GetDisplayNameOf,
|
|
CNetwork_SetNameOf,
|
|
};
|
|
|
|
IDropTargetVtbl c_CNetRootTargetVtbl =
|
|
{
|
|
CIDLDropTarget_QueryInterface,
|
|
CIDLDropTarget_AddRef,
|
|
CIDLDropTarget_Release,
|
|
CNetRootDropTarget_DragEnter,
|
|
CIDLDropTarget_DragOver,
|
|
CIDLDropTarget_DragLeave,
|
|
CNetRootDropTarget_Drop,
|
|
};
|
|
|
|
//
|
|
// We have a single instance of this NetRoot class in code segment.
|
|
//
|
|
CNetRes c_netRoot =
|
|
{
|
|
&c_NetRootVtbl,
|
|
&c_NetRootVtblPF,
|
|
0,
|
|
(LPCITEMIDLIST)&c_idlNet,
|
|
&c_netRoot.sf, // self-referencial initialization
|
|
FALSE,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
|
|
#pragma data_seg(DATASEG_PERINSTANCE)
|
|
CNetHood c_netHood = { NULL, NULL };
|
|
|
|
// This is one-entry cache for remote junctions resolution
|
|
// BUGBUG limit really should be max_remote_name
|
|
// PERF BUGBUG It is much more appropriate to alloc strings dynamically
|
|
// from process heap. Ask Satoshi how shelldll typically handles this
|
|
TCHAR g_szLastAttemptedJunctionName[MAX_PATH] = {TEXT('\0')};
|
|
TCHAR g_szLastResolvedJunctionName[MAX_PATH] = {TEXT('\0')};
|
|
|
|
#pragma data_seg()
|
|
|
|
//
|
|
// Remote Computer registry items info
|
|
//
|
|
|
|
const TCHAR c_szRemoteComputerNameSpace[] = TEXT("RemoteComputer\\NameSpace");
|
|
|
|
|
|
|
|
//===========================================================================
|
|
// CNetwork: Constructor
|
|
//===========================================================================
|
|
|
|
//
|
|
// Te be called from IClassFactory::CreateInstance
|
|
//
|
|
HRESULT CALLBACK CNetwork_CreateInstance(LPUNKNOWN punkOuter,
|
|
REFIID riid, LPVOID * ppv)
|
|
{
|
|
Assert(punkOuter==NULL);
|
|
return c_netRoot.psf->lpVtbl->QueryInterface(c_netRoot.psf, riid, ppv);
|
|
}
|
|
|
|
int WINAPI SHOutOfMemoryMessageBox(HWND hwndOwner, LPTSTR pszTitle, UINT fuStyle)
|
|
{
|
|
extern LPTSTR g_pszOutOfMemory;
|
|
TCHAR szTitle[128];
|
|
int ret;
|
|
|
|
szTitle[0] = TEXT('\0');
|
|
|
|
if (pszTitle==NULL)
|
|
{
|
|
GetWindowText(hwndOwner, szTitle, ARRAYSIZE(szTitle));
|
|
pszTitle = szTitle;
|
|
}
|
|
|
|
ret = MessageBox(hwndOwner, g_pszOutOfMemory, pszTitle, fuStyle|MB_SETFOREGROUND);
|
|
if (ret == -1)
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("regular message box failed, trying sysmodal"));
|
|
ret = MessageBox(hwndOwner, g_pszOutOfMemory, pszTitle, fuStyle | MB_SYSTEMMODAL);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
//
|
|
// hwndOwner -- NULL indicates no UI.
|
|
//
|
|
DWORD _OpenEnumRetry(HWND hwndOwner, DWORD dwType, LPNETRESOURCE pnr, HANDLE * phEnum)
|
|
{
|
|
DWORD err;
|
|
LPCTSTR lpProvider = (pnr == NULL) ? NULL : pnr->lpProvider;
|
|
UINT idTemplate = ((pnr != NULL) && pnr->lpRemoteName) ?
|
|
IDS_ENUMERR_NETTEMPLATE2 : IDS_ENUMERR_NETTEMPLATE1;
|
|
DWORD dwScope = pnr? RESOURCE_GLOBALNET : RESOURCE_CONTEXT;
|
|
|
|
do
|
|
{
|
|
err = WNetOpenEnum(dwScope, dwType, RESOURCEUSAGE_ALL,
|
|
pnr, phEnum);
|
|
|
|
if (err!=WN_SUCCESS) {
|
|
DebugMsg(DM_TRACE, TEXT("sh TR - _OER: 1st WNetOpenEnum failed (%d)"), err);
|
|
}
|
|
|
|
//
|
|
// If hwndOwner is NULL, we shouldn't put any UI.
|
|
//
|
|
if (hwndOwner==NULL) {
|
|
return err;
|
|
}
|
|
|
|
#ifndef WINNT
|
|
//
|
|
// If it failed, because the user has not been logged on,
|
|
// give him/her a chance to logon at this moment.
|
|
//
|
|
if (err==WN_NOT_LOGGED_ON)
|
|
{
|
|
err = WNetLogon(lpProvider, hwndOwner);
|
|
|
|
if (err == WN_SUCCESS)
|
|
{
|
|
// Retry WNetOpenEnum.
|
|
err = WNetOpenEnum(dwScope, dwType,
|
|
RESOURCEUSAGE_ALL, pnr, phEnum);
|
|
}
|
|
}
|
|
#endif // !WINNT
|
|
|
|
//
|
|
// If it failed because you are not authenticated yet,
|
|
// we need to let the user loggin to this network resource.
|
|
//
|
|
// REVIEW: Ask LenS to review this code.
|
|
if (err == WN_NOT_AUTHENTICATED
|
|
|| err == ERROR_LOGON_FAILURE
|
|
|| err == WN_BAD_PASSWORD
|
|
|| err == WN_ACCESS_DENIED
|
|
)
|
|
{
|
|
// Retry with password dialog box.
|
|
err = WNetAddConnection3(hwndOwner, pnr, NULL, NULL,
|
|
CONNECT_TEMPORARY | CONNECT_INTERACTIVE);
|
|
|
|
if (err == WN_SUCCESS)
|
|
{
|
|
// Retry WNetOpenEnum.
|
|
err = WNetOpenEnum(dwScope, dwType,
|
|
RESOURCEUSAGE_ALL, pnr, phEnum);
|
|
|
|
if (err!=WN_SUCCESS) {
|
|
DebugMsg(DM_TRACE, TEXT("sh TR - _OER: 2nd WNetOpenEnum failed (%d)"), err);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("sh TR - _OER: WNetAddConnection3 failed (%d)"), err);
|
|
}
|
|
}
|
|
} while (SHEnumErrorMessageBox(hwndOwner, idTemplate, err,
|
|
pnr? pnr->lpRemoteName : NULL, TRUE, MB_OK|MB_ICONHAND)==IDRETRY);
|
|
|
|
return err;
|
|
}
|
|
|
|
HRESULT CNetRes_CreateInstance(LPCITEMIDLIST pidlAbs,
|
|
REFIID riid, LPVOID * ppvOut)
|
|
{
|
|
HRESULT hres = E_INVALIDARG;
|
|
if (!ILIsEmpty(pidlAbs))
|
|
{
|
|
LPNETRES pnet = (void*)LocalAlloc(LPTR, SIZEOF(CNetRes));
|
|
hres = E_OUTOFMEMORY;
|
|
if (pnet)
|
|
{
|
|
LPCIDNETRESOURCE pidnLast;
|
|
|
|
pnet->sf.lpVtbl = &c_NetResVtbl;
|
|
pnet->cRef = 1;
|
|
pnet->psf = &pnet->sf; // by default, no remote items
|
|
pnet->bRemote = FALSE;
|
|
|
|
pidnLast = (LPCIDNETRESOURCE)ILFindLastID(pidlAbs);
|
|
if (NET_GetDisplayType(pidnLast) == RESOURCEDISPLAYTYPE_SERVER)
|
|
{
|
|
// This is a remote computer. See if there are any remote
|
|
// computer registry items. If so, aggregate with the registry
|
|
// class.
|
|
|
|
HKEY hkRegItems = SHGetExplorerSubHkey(HKEY_LOCAL_MACHINE, c_szRemoteComputerNameSpace, FALSE);
|
|
if (NULL != hkRegItems)
|
|
{
|
|
// There are remote items... add them
|
|
|
|
TCHAR szComputer[MAX_PATH]; // BUGBUG: max_computername_len?
|
|
|
|
REGITEMSINFO remoteComputerRegInfo =
|
|
{
|
|
&pnet->sf,
|
|
NULL,
|
|
TEXT(':'),
|
|
SHID_NET_REGITEM,
|
|
NULL,
|
|
-1,
|
|
SFGAO_FOLDER | SFGAO_CANLINK,
|
|
0, // no required reg items
|
|
NULL
|
|
};
|
|
|
|
remoteComputerRegInfo.hkRegItems = hkRegItems;
|
|
|
|
remoteComputerRegInfo.pidlThis = ILClone(pidlAbs);
|
|
if (NULL == remoteComputerRegInfo.pidlThis)
|
|
{
|
|
RegCloseKey(remoteComputerRegInfo.hkRegItems);
|
|
LocalFree(pnet);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
NET_CopyResName(pidnLast, szComputer, ARRAYSIZE(szComputer));
|
|
hres = RegItems_AddToShellFolderRemote(&remoteComputerRegInfo, szComputer, &pnet->psf);
|
|
if (FAILED(hres))
|
|
{
|
|
ILFree((LPITEMIDLIST)remoteComputerRegInfo.pidlThis);
|
|
RegCloseKey(remoteComputerRegInfo.hkRegItems);
|
|
LocalFree(pnet);
|
|
return hres;
|
|
}
|
|
|
|
//
|
|
// Now decrement our reference count. We need to do this
|
|
// because now RegItems has a reference to us, and
|
|
// the client will call RegItems' Release rather than
|
|
// ours (so we'll have a reference leak).
|
|
//
|
|
// Conceptually, when clients create the object, we
|
|
// create a RegItems that owns (via containment) a
|
|
// NetRes. The refcount on NetRes is 1, since the
|
|
// RegItems (not the client) owns it. The client only
|
|
// owns RegItems, and has a pointer to RegItems. The
|
|
// client is only responsible for calling Release
|
|
// on RegItems.
|
|
//
|
|
// In reality, we create a NetRes first, so we set
|
|
// the refcount to 1 (since we expect the caller
|
|
// to own it). Then determine whether it should be
|
|
// contained by a RegItems. If this is the case, we
|
|
// pass it to RegItems, which grabs a reference to
|
|
// NetRes (incremented to 2). The client then gets
|
|
// a RegItems rather than a NetRes, so they will call
|
|
// Release only on RegItems. Now we must release
|
|
// the original reference to NetRes, since the client
|
|
// won't own it.
|
|
//
|
|
// This is a side effect of passing around a RegItems
|
|
// when the callee really expects a NetRes. Everywhere
|
|
// the callee must call RegItems_GetInnerShellFolder
|
|
// to get NetRes.
|
|
//
|
|
// I suspect other users of RegItems will have the
|
|
// same problems (ultrootx.c's ReleaseRootFolders
|
|
// must release both pointers too, but at destruction
|
|
// time rather than now). [AlbertT]
|
|
//
|
|
pnet->cRef--;
|
|
|
|
// save these for later destruction
|
|
pnet->bRemote = TRUE;
|
|
pnet->hkRegItems = remoteComputerRegInfo.hkRegItems;
|
|
pnet->pidlRemote = remoteComputerRegInfo.pidlThis;
|
|
}
|
|
}
|
|
|
|
pnet->pidl = ILClone(pidlAbs);
|
|
if (pnet->pidl)
|
|
{
|
|
// use the regitem queryinterface
|
|
hres = pnet->psf->lpVtbl->QueryInterface(pnet->psf, riid, ppvOut);
|
|
}
|
|
|
|
pnet->psf->lpVtbl->Release(pnet->psf);
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
// CNetwork: Member
|
|
//===========================================================================
|
|
|
|
//
|
|
// ShellFolder
|
|
//
|
|
STDMETHODIMP CNetRes_SF_QueryInterface(LPSHELLFOLDER psf, REFIID riid, LPVOID * ppvObj)
|
|
{
|
|
LPNETRES this = IToClass(CNetRes, sf, psf);
|
|
|
|
if (IsEqualIID(riid, &IID_IUnknown)
|
|
|| IsEqualIID(riid, &IID_IShellFolder))
|
|
{
|
|
// do funky stuff to get the "aggregated" regitems
|
|
*ppvObj = this->psf;
|
|
this->psf->lpVtbl->AddRef(this->psf);
|
|
return S_OK;
|
|
}
|
|
|
|
if (IsEqualIID(riid, &IID_IPersistFolder))
|
|
{
|
|
*ppvObj = &this->pf;
|
|
this->pf.lpVtbl->AddRef(&this->pf);
|
|
return S_OK;
|
|
}
|
|
|
|
*ppvObj = NULL;
|
|
|
|
return(E_NOINTERFACE);
|
|
}
|
|
|
|
//
|
|
// AddRef
|
|
//
|
|
STDMETHODIMP_(ULONG) CNetRes_AddRef(LPSHELLFOLDER psf)
|
|
{
|
|
LPNETRES this = IToClass(CNetRes, sf, psf);
|
|
|
|
this->cRef++;
|
|
return this->cRef;
|
|
}
|
|
|
|
//
|
|
// Release
|
|
//
|
|
STDMETHODIMP_(ULONG) CNetRes_Release(LPSHELLFOLDER psf)
|
|
{
|
|
LPNETRES this = IToClass(CNetRes, sf, psf);
|
|
|
|
this->cRef--;
|
|
if (this->cRef > 0)
|
|
{
|
|
return this->cRef;
|
|
}
|
|
|
|
if (this->pidl)
|
|
{
|
|
ILFree((LPITEMIDLIST)this->pidl);
|
|
}
|
|
|
|
if (this->bRemote)
|
|
{
|
|
Assert(NULL != this->hkRegItems);
|
|
Assert(NULL != this->pidlRemote);
|
|
|
|
RegCloseKey(this->hkRegItems);
|
|
ILFree((LPITEMIDLIST)this->pidlRemote);
|
|
}
|
|
|
|
LocalFree((HLOCAL)this);
|
|
return 0;
|
|
}
|
|
|
|
|
|
//=======================================================================
|
|
// Create a pidl from a network resource
|
|
//=======================================================================
|
|
LPITEMIDLIST _CNetwork_CreatePidlFromNetResource(LPARAM lParam,
|
|
NETRESOURCE *pnr, BOOL fKeepProviderName, BOOL fKeepComment)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
LPCTSTR pszName;
|
|
LPCTSTR pszProvider;
|
|
LPCTSTR pszComment;
|
|
LPTSTR psz;
|
|
LPBYTE pb;
|
|
UINT cchName;
|
|
UINT cchProvider;
|
|
UINT cchComment;
|
|
UINT cbmkid;
|
|
UINT cbToAdd = 0;
|
|
LPIDNETRESOURCE pidn;
|
|
WORD wNetType = 0;
|
|
#ifdef UNICODE
|
|
BOOL fUnicode = FALSE;
|
|
LPSTR lpNameBuffer;
|
|
LPSTR lpProviderBuffer;
|
|
LPSTR lpCommentBuffer;
|
|
LPWSTR lpUnicodeBuffer;
|
|
UINT cchAnsiName;
|
|
UINT cchAnsiProvider;
|
|
UINT cchAnsiComment;
|
|
UINT cchMax;
|
|
#endif
|
|
|
|
switch (pnr->dwDisplayType) {
|
|
case RESOURCEDISPLAYTYPE_NETWORK:
|
|
pszName = pnr->lpProvider;
|
|
break;
|
|
case RESOURCEDISPLAYTYPE_ROOT:
|
|
pszName = pnr->lpComment;
|
|
break;
|
|
default:
|
|
pszName = pnr->lpRemoteName;
|
|
// move pointer past "\\"
|
|
for (psz = pnr->lpRemoteName; *psz && *psz == TEXT('\\'); psz++);
|
|
PathMakePretty(psz);
|
|
break;
|
|
}
|
|
|
|
if (!pszName)
|
|
{
|
|
// For now put in an empty string...
|
|
pszName = c_szNULL;
|
|
}
|
|
|
|
pszProvider = (fKeepProviderName) ? pnr->lpProvider : NULL;
|
|
if (pszProvider)
|
|
{
|
|
DWORD dwRes;
|
|
DWORD dwType;
|
|
INT i;
|
|
|
|
cbToAdd = SIZEOF(WORD);
|
|
dwRes = WNetGetProviderType( pszProvider, &dwType );
|
|
if (dwRes == WN_SUCCESS)
|
|
{
|
|
wNetType = HIWORD(dwType);
|
|
for (i=0; i < ARRAYSIZE(aChiProv); i++)
|
|
{
|
|
if (aChiProv[i].wNetType == wNetType)
|
|
{
|
|
pszProvider = aChiProv[i].lpName;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pszComment = (fKeepComment?pnr->lpComment:NULL);
|
|
cchName = lstrlen(pszName)+1;
|
|
cchProvider = 0;
|
|
cchComment = 0;
|
|
|
|
if (pszProvider) cchProvider = lstrlen(pszProvider)+1;
|
|
if (pszComment) cchComment = lstrlen(pszComment)+1;
|
|
|
|
#ifdef UNICODE
|
|
cchAnsiProvider = 0;
|
|
cchAnsiComment = 0;
|
|
cchMax = cchName+1;
|
|
if ( cchProvider > cchMax ) cchMax = cchProvider;
|
|
if ( cchComment > cchMax ) cchMax = cchComment;
|
|
|
|
// Allocate space for all ansi strings + buffer for unicode comparison
|
|
lpNameBuffer = (LPSTR)LocalAlloc(LPTR, (cchName+cchProvider+cchComment)*2+cchMax*SIZEOF(TCHAR));
|
|
if (!lpNameBuffer)
|
|
{
|
|
return NULL; // Error indication
|
|
}
|
|
lpProviderBuffer = lpNameBuffer + cchName*2; // 2 for DBCS
|
|
lpCommentBuffer = lpProviderBuffer + cchProvider*2; // 2 for DBCS
|
|
lpUnicodeBuffer = (LPWSTR)(lpCommentBuffer + cchComment*2); // 2 for DBCS
|
|
|
|
cchAnsiName = WideCharToMultiByte(CP_ACP, 0,
|
|
pszName, cchName,
|
|
lpNameBuffer, cchName*2, // DBCS
|
|
NULL, NULL);
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
lpNameBuffer, cchAnsiName,
|
|
lpUnicodeBuffer, cchMax);
|
|
fUnicode |= lstrcmp(lpUnicodeBuffer, pszName);
|
|
|
|
if (pszProvider)
|
|
{
|
|
cchAnsiProvider = WideCharToMultiByte(CP_ACP, 0,
|
|
pszProvider, cchProvider,
|
|
lpProviderBuffer, cchProvider*2,
|
|
NULL, NULL);
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
lpProviderBuffer, cchAnsiProvider,
|
|
lpUnicodeBuffer, cchMax);
|
|
fUnicode |= lstrcmp(lpUnicodeBuffer,pszProvider);
|
|
}
|
|
if (pszComment)
|
|
{
|
|
cchAnsiComment = WideCharToMultiByte(CP_ACP, 0,
|
|
pszComment, cchComment,
|
|
lpCommentBuffer, cchComment*2,
|
|
NULL, NULL);
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
lpCommentBuffer, cchAnsiComment,
|
|
lpUnicodeBuffer, cchMax);
|
|
fUnicode |= lstrcmp(lpUnicodeBuffer,pszComment);
|
|
}
|
|
cbmkid = SIZEOF(IDNETRESOURCE) - 1 + cbToAdd
|
|
+ cchAnsiName + cchAnsiProvider + cchAnsiComment;
|
|
//
|
|
// fUnicode now inidicates whether the name needs to be stored in unicode
|
|
//
|
|
if (fUnicode)
|
|
{
|
|
cbmkid += (cchName+cchProvider+cchComment)*SIZEOF(TCHAR);
|
|
}
|
|
#else
|
|
cbmkid = SIZEOF(IDNETRESOURCE) - 1 + cbToAdd
|
|
+ (cchName+cchProvider+cchComment) * SIZEOF(TCHAR);
|
|
#endif
|
|
|
|
|
|
pidl = _ILCreate(cbmkid + SIZEOF(USHORT));
|
|
if (!pidl)
|
|
{
|
|
#ifdef UNICODE
|
|
LocalFree(lpNameBuffer);
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
if (lParam)
|
|
CDefEnum_SetReturn(lParam, pidl);
|
|
|
|
pidn = (LPIDNETRESOURCE)pidl;
|
|
pidn->cb = cbmkid;
|
|
pidn->bFlags = (BYTE)(SHID_NET | (pnr->dwDisplayType & 0x0f));
|
|
pidn->uType = (BYTE)(pnr->dwType & 0x0f);
|
|
pidn->uUsage = (BYTE)(pnr->dwUsage & 0x0f);
|
|
if ((pnr->dwDisplayType == RESOURCEDISPLAYTYPE_SHARE ||
|
|
pnr->dwDisplayType == RESOURCEDISPLAYTYPE_SHAREADMIN) &&
|
|
!(pnr->dwUsage & RESOURCEUSAGE_CONTAINER))
|
|
{
|
|
pidn->bFlags |= (BYTE)SHID_JUNCTION;
|
|
}
|
|
pb = pidn->szNetResName;
|
|
#ifdef UNICODE
|
|
lstrcpynA(pb, lpNameBuffer, cchAnsiName);
|
|
pb += cchAnsiName;
|
|
#else
|
|
lstrcpy(pb, pszName);
|
|
pb += cchName;
|
|
#endif
|
|
|
|
// See if we need to keep the provider name
|
|
if (pszProvider)
|
|
{
|
|
pidn->uUsage |= NET_HASPROVIDER;
|
|
#ifdef UNICODE
|
|
lstrcpynA(pb, lpProviderBuffer, cchAnsiProvider);
|
|
pb += cchAnsiProvider;
|
|
#else
|
|
lstrcpy(pb, pszProvider);
|
|
pb += cchProvider;
|
|
#endif
|
|
}
|
|
|
|
if (pszComment)
|
|
{
|
|
pidn->uUsage |= NET_HASCOMMENT;
|
|
#ifdef UNICODE
|
|
lstrcpynA(pb, lpCommentBuffer, cchAnsiComment);
|
|
pb += cchAnsiComment;
|
|
#else
|
|
lstrcpy(pb, pszComment);
|
|
#endif
|
|
}
|
|
#ifdef UNICODE
|
|
if (fUnicode)
|
|
{
|
|
pidn->uUsage |= NET_UNICODE;
|
|
ualstrcpyn((LPWSTR)pb, pszName, cchName);
|
|
pb += cchName * SIZEOF(WCHAR);
|
|
if (pszProvider)
|
|
{
|
|
ualstrcpyn((LPWSTR)pb, pszProvider, cchProvider);
|
|
pb += cchProvider * SIZEOF(WCHAR);
|
|
}
|
|
if (pszComment)
|
|
{
|
|
ualstrcpyn((LPWSTR)pb, pszComment, cchComment);
|
|
}
|
|
}
|
|
LocalFree(lpNameBuffer);
|
|
#endif
|
|
|
|
if (cbToAdd)
|
|
{
|
|
//
|
|
// Store the provider type as well...
|
|
//
|
|
pb = (LPBYTE)pidn + pidn->cb;
|
|
pb -= SIZEOF(WORD);
|
|
|
|
*((UNALIGNED WORD *)pb) = wNetType;
|
|
}
|
|
Assert(pidl->mkid.cb == pidn->cb);
|
|
|
|
return pidl;
|
|
}
|
|
|
|
|
|
/* This function adds a provider name to an IDLIST that doesn't already have one. */
|
|
/* A new IDLIST pointer is returned; the old pointer is no longer valid. */
|
|
LPITEMIDLIST _CNetwork_AddProviderToPidl(LPITEMIDLIST pidl, LPCTSTR lpProvider)
|
|
{
|
|
LPIDNETRESOURCE pidn = (LPIDNETRESOURCE)pidl;
|
|
LPITEMIDLIST pidlNew;
|
|
LPSTR lpProviderSpace;
|
|
LPTSTR pszProvider = (LPTSTR)lpProvider;
|
|
UINT cbIDL = ILGetSize(pidl);
|
|
UINT cchAnsiName;
|
|
UINT cchAnsiComment;
|
|
UINT cchProvider = 0;
|
|
UINT cbAddition;
|
|
WORD wNetType = 0;
|
|
LPBYTE pb;
|
|
DWORD dwRes;
|
|
DWORD dwType;
|
|
INT i;
|
|
#ifdef UNICODE
|
|
UINT cchAnsiProvider;
|
|
LPSTR lpAnsiBuffer;
|
|
LPWSTR lpUnicodeBuffer;
|
|
BOOL fWasUnicode = NET_IsUnicode(pidn);
|
|
BOOL fNowUnicode = fWasUnicode;
|
|
#endif
|
|
|
|
if (NET_FHasProvider(pidn))
|
|
return pidl; /* already got a provider */
|
|
|
|
dwRes = WNetGetProviderType( pszProvider, &dwType );
|
|
if (dwRes == WN_SUCCESS)
|
|
{
|
|
wNetType = HIWORD(dwType);
|
|
for (i=0; i < ARRAYSIZE(aChiProv); i++)
|
|
{
|
|
if (aChiProv[i].wNetType == wNetType)
|
|
{
|
|
pszProvider = (LPTSTR)aChiProv[i].lpName;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
cchProvider = lstrlen(pszProvider)+1;
|
|
cchAnsiName = lstrlenA(pidn->szNetResName) + 1;
|
|
cchAnsiComment = 0;
|
|
if (NET_FHasComment(pidn))
|
|
{
|
|
cchAnsiComment = lstrlenA(pidn->szNetResName+cchAnsiName)+1;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
// Enough space for DBCS provider and copy of unicode provider
|
|
lpAnsiBuffer = (LPSTR)LocalAlloc(LPTR,
|
|
cchProvider*2 + cchProvider*SIZEOF(TCHAR));
|
|
if (!lpAnsiBuffer)
|
|
{
|
|
return pidl;
|
|
}
|
|
cchAnsiProvider = WideCharToMultiByte(CP_ACP, 0,
|
|
pszProvider, cchProvider,
|
|
lpAnsiBuffer, cchProvider*2,
|
|
NULL,NULL);
|
|
if (!fWasUnicode)
|
|
{
|
|
lpUnicodeBuffer = (LPWSTR)(lpAnsiBuffer + cchProvider*2);
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
lpAnsiBuffer, cchProvider,
|
|
lpUnicodeBuffer, cchProvider);
|
|
fNowUnicode |= lstrcmp(lpUnicodeBuffer,pszProvider);
|
|
}
|
|
cbAddition = cchAnsiProvider;
|
|
if (fNowUnicode)
|
|
{
|
|
cbAddition += cchProvider*SIZEOF(WCHAR);
|
|
if (!fWasUnicode)
|
|
{
|
|
cbAddition += cchAnsiName*SIZEOF(WCHAR);
|
|
cbAddition += cchAnsiComment*SIZEOF(WCHAR);
|
|
}
|
|
}
|
|
#else
|
|
cbAddition = cchProvider;
|
|
#endif
|
|
|
|
// SIZEOF(WORD) is for wNetType
|
|
cbAddition += SIZEOF(WORD);
|
|
pidlNew = _ILResize(pidl, cbIDL + cbAddition, 0);
|
|
if (pidlNew == NULL)
|
|
{
|
|
pidlNew = pidl;
|
|
goto ExitAndFree;
|
|
}
|
|
|
|
pidn = (LPIDNETRESOURCE)pidlNew;
|
|
|
|
lpProviderSpace = pidn->szNetResName + cchAnsiName;
|
|
MoveMemory(lpProviderSpace + cchProvider + SIZEOF(WORD), lpProviderSpace,
|
|
cbIDL - (lpProviderSpace - (LPBYTE)pidn));
|
|
pb = lpProviderSpace + cchProvider + cchAnsiComment;
|
|
#ifdef UNICODE
|
|
lstrcpyA(lpProviderSpace, lpAnsiBuffer);
|
|
if (fNowUnicode)
|
|
{
|
|
// BUGBUG Not sure if MAX_PATH is the true maximum
|
|
|
|
if (!fWasUnicode)
|
|
{
|
|
WCHAR wszTmp[MAX_PATH];
|
|
pb += MultiByteToWideChar(CP_ACP, 0,
|
|
pidn->szNetResName, cchAnsiName,
|
|
wszTmp, cchAnsiName) * SIZEOF(WCHAR);
|
|
ualstrcpy((LPNWSTR)pb, wszTmp);
|
|
}
|
|
ualstrcpy((LPNWSTR)pb,pszProvider);
|
|
pb += cchProvider*SIZEOF(WCHAR);
|
|
if (!fWasUnicode)
|
|
{
|
|
DWORD dwSize;
|
|
WCHAR wszTmp[MAX_PATH];
|
|
dwSize = MultiByteToWideChar(CP_ACP, 0,
|
|
pidn->szNetResName+cchAnsiName+
|
|
cchAnsiProvider+cchAnsiComment, cchAnsiComment,
|
|
wszTmp, cchAnsiComment);
|
|
ualstrcpy((LPNWSTR)pb, wszTmp);
|
|
pb += dwSize;
|
|
}
|
|
}
|
|
#else
|
|
lstrcpy(lpProviderSpace, pszProvider);
|
|
#endif
|
|
pidn->uUsage |= NET_HASPROVIDER;
|
|
pidn->cb += cbAddition;
|
|
|
|
//
|
|
// Store provider type
|
|
//
|
|
*((UNALIGNED WORD *)pb) = wNetType;
|
|
ExitAndFree:
|
|
#ifdef UNICODE
|
|
// Make sure we free our buffer...
|
|
LocalFree(lpAnsiBuffer);
|
|
#endif
|
|
|
|
return pidlNew;
|
|
}
|
|
|
|
//
|
|
// Copy the provider name from an IDNETRESOURCE
|
|
// Parameters:
|
|
// pidnRel -- Specifies the IDNETRESOURCE structure
|
|
// pszBuff -- Buffer for the copy
|
|
// cchBuff -- Size of buffer in chars.
|
|
//
|
|
LPTSTR NET_CopyResName(LPCIDNETRESOURCE pidn, LPTSTR pszBuff, UINT cchBuff)
|
|
{
|
|
LPBYTE pb;
|
|
VDATEINPUTBUF(pszBuff, TCHAR, cchBuff);
|
|
|
|
pb = (LPBYTE)pidn->szNetResName;
|
|
#ifdef UNICODE
|
|
if (NET_IsUnicode(pidn))
|
|
{
|
|
pb += lstrlenA((LPSTR)pb) + 1; // Skip over ansi net name
|
|
if (NET_FHasProvider(pidn))
|
|
pb += lstrlenA((LPSTR)pb) + 1; // Skip over ansi provider
|
|
if (NET_FHasComment(pidn))
|
|
pb += lstrlenA((LPSTR)pb) + 1; // Skip over comment
|
|
ualstrcpyn(pszBuff, (LPNWSTR)pb, cchBuff);
|
|
}
|
|
else
|
|
{
|
|
MultiByteToWideChar(CP_ACP, 0, // Convert the ansi string to
|
|
(LPSTR)pb, -1, // unicode
|
|
pszBuff, cchBuff);
|
|
}
|
|
#else
|
|
lstrcpyn(pszBuff, pb, cchBuff );
|
|
#endif
|
|
return pszBuff;
|
|
}
|
|
|
|
//
|
|
// Copy the provider name from an IDNETRESOURCE
|
|
// Parameters:
|
|
// pidnRel -- Specifies the IDNETRESOURCE structure
|
|
// pszBuff -- Buffer for the copy
|
|
// cchBuff -- Size of buffer in chars.
|
|
//
|
|
LPTSTR NET_CopyProviderName(LPCIDNETRESOURCE pidnRel, LPTSTR pszBuff, UINT cchBuff)
|
|
{
|
|
CONST BYTE far *pb;
|
|
DWORD dwNetType,dwRes;
|
|
VDATEINPUTBUF(pszBuff, TCHAR, cchBuff);
|
|
|
|
|
|
if (!NET_FHasProvider(pidnRel))
|
|
{
|
|
pszBuff[0] = '\0';
|
|
return(NULL);
|
|
}
|
|
|
|
//
|
|
// First try the wNetType at the end of the pidl
|
|
//
|
|
|
|
pb = (LPBYTE)pidnRel + pidnRel->cb;
|
|
pb -= SIZEOF(WORD);
|
|
dwNetType = *((UNALIGNED WORD *)pb) << 16;
|
|
|
|
if (dwNetType && (dwNetType <= WNNC_NET_LARGEST))
|
|
{
|
|
dwRes = WNetGetProviderName( dwNetType, pszBuff, (LPDWORD)&cchBuff );
|
|
if (dwRes == WN_SUCCESS)
|
|
{
|
|
return pszBuff;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Try the old way...
|
|
//
|
|
|
|
pb = pidnRel->szNetResName;
|
|
pb += lstrlenA((LPSTR)pb) + 1; // Skip over ansi net name
|
|
#ifdef UNICODE
|
|
if (NET_IsUnicode(pidnRel))
|
|
{
|
|
|
|
pb += lstrlenA((LPSTR)pb) + 1; // Skip over ansi provider
|
|
if (NET_FHasComment(pidnRel))
|
|
pb += lstrlenA((LPSTR)pb) + 1; // Skip over comment
|
|
pb += (ualstrlen((LPNWSTR)pb) + 1) * SIZEOF(WCHAR); // skip over unicode net name
|
|
ualstrcpyn(pszBuff, (LPNWSTR)pb, cchBuff);
|
|
}
|
|
else
|
|
{
|
|
MultiByteToWideChar(CP_ACP, 0, // Convert the ansi string to
|
|
(LPSTR)pb, -1, // unicode
|
|
pszBuff, cchBuff);
|
|
}
|
|
#else
|
|
lstrcpyn(pszBuff, pb, cchBuff );
|
|
#endif
|
|
|
|
//
|
|
// Map from Win95 net provider name if possible...
|
|
//
|
|
|
|
{
|
|
INT i;
|
|
|
|
for (i = 0; i < ARRAYSIZE(aChiProv); i++)
|
|
{
|
|
if (lstrcmp(pszBuff, (LPTSTR)aChiProv[i].lpName)==0)
|
|
{
|
|
DWORD dwNetType = aChiProv[i].wNetType << 16;
|
|
if (dwNetType && (dwNetType <= WNNC_NET_LARGEST))
|
|
{
|
|
*pszBuff = TEXT('\0');
|
|
WNetGetProviderName( dwNetType, pszBuff, (LPDWORD)&cchBuff );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return pszBuff;
|
|
}
|
|
|
|
//
|
|
// This is going to be one very expensive operation, but
|
|
// we will need it to handle cases where the user types in \\pyrex\user\foo
|
|
//
|
|
|
|
STDMETHODIMP CNetwork_ParseDisplayName(LPSHELLFOLDER psf, HWND hwndOwner, LPBC pbc,
|
|
LPOLESTR pwszDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidlOut, DWORD *pdwAttributes)
|
|
{
|
|
|
|
LPNETRES this = IToClass(CNetRes, sf, psf);
|
|
NETRESOURCE nr={0};
|
|
DWORD dwRes;
|
|
DWORD dwBuf;
|
|
LPITEMIDLIST pidl;
|
|
LPOLESTR pwszSlash;
|
|
HRESULT hres;
|
|
LPITEMIDLIST pidlT;
|
|
BOOL fStuffFollows = FALSE;
|
|
int cSlash;
|
|
LPTSTR pEnd;
|
|
LPTSTR pszFSPart;
|
|
LPITEMIDLIST pidlCombined;
|
|
LPOLESTR pwszSlash4 = NULL;
|
|
LPOLESTR pwszReg = NULL;
|
|
INT iLen = 0;
|
|
#ifdef UNICODE
|
|
// make it big in case we're talking to a server that likes really long
|
|
// paths...
|
|
TCHAR szFilePart[ MAX_PATH*2 ];
|
|
#endif
|
|
|
|
// Keep the stuff off the stack.
|
|
struct {
|
|
TCHAR szPath[MAX_PATH];
|
|
TCHAR szProvider[MAX_PATH];
|
|
union
|
|
{
|
|
NETRESOURCE nrOut;
|
|
TCHAR buf[1024];
|
|
};
|
|
} *pbuf = (void*)LocalAlloc(LPTR, SIZEOF(*pbuf));
|
|
|
|
*ppidlOut = NULL; // assume error
|
|
|
|
if (!pbuf)
|
|
return E_OUTOFMEMORY;
|
|
|
|
// Get string length of pwszDisplayName
|
|
for (pwszSlash = pwszDisplayName, cSlash = 0; *pwszSlash != 0;
|
|
pwszSlash++)
|
|
{
|
|
// Look for back slashes.
|
|
if (*pwszSlash == L'\\')
|
|
{
|
|
cSlash++;
|
|
|
|
// Look for a regitem after the slash, like "\\machine\::{...}"
|
|
if (cSlash == 3 && *(pwszSlash+1) == L':' && *(pwszSlash+2) == L':')
|
|
{
|
|
pwszReg = pwszSlash;
|
|
}
|
|
|
|
if (cSlash == 4)
|
|
{
|
|
pwszSlash4 = pwszSlash;
|
|
}
|
|
}
|
|
iLen++;
|
|
}
|
|
|
|
// Point pwszSlash4 to the end of the string if there wasn't a 4th slash
|
|
if (!pwszSlash4)
|
|
{
|
|
pwszSlash4 = pwszSlash;
|
|
}
|
|
|
|
// don't copy the traling '\' if there is one...ntlanman chokes on net paths
|
|
// with a trailing '\'..
|
|
if (pwszSlash > pwszDisplayName)
|
|
{
|
|
if (*(pwszSlash-1) == L'\\')
|
|
{
|
|
pwszSlash--;
|
|
}
|
|
}
|
|
|
|
// if there was a regitem, the point pwszslash to it...
|
|
if (pwszReg)
|
|
{
|
|
pwszSlash = pwszReg;
|
|
}
|
|
|
|
SHGetPathFromIDList(this->pidl, pbuf->szPath);
|
|
pEnd = PathAddBackslash(pbuf->szPath);
|
|
pEnd += OleStrToStrN(pEnd, ARRAYSIZE(pbuf->szPath) - (pEnd - pbuf->szPath), pwszDisplayName, pwszSlash - pwszDisplayName);
|
|
*pEnd = 0; // we need to terminate ourselves
|
|
|
|
// DebugMsg(DM_TRACE, "Net::ParseDisplayName(%s)", pbuf->szPath);
|
|
|
|
nr.lpRemoteName = pbuf->szPath;
|
|
nr.lpProvider = NET_CopyProviderNameAbs(this->pidl,
|
|
pbuf->szProvider,
|
|
ARRAYSIZE(pbuf->szProvider));
|
|
nr.dwType = RESOURCETYPE_ANY;
|
|
|
|
pidl = NULL;
|
|
|
|
// Need to only ask for resource information once to make sure the
|
|
// object exists...
|
|
//
|
|
dwBuf = SIZEOF(pbuf->buf);
|
|
dwRes = WNetGetResourceInformation(&nr, (PVOID)&pbuf->nrOut, &dwBuf,
|
|
&pszFSPart);
|
|
|
|
// Lets get the real scoop about this network resource
|
|
if (dwRes != WN_SUCCESS && pwszSlash4 != NULL)
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("Net::PDN.gri Failed(%x)"), dwRes);
|
|
|
|
*(pbuf->szPath+(pwszSlash4-pwszDisplayName)) = TEXT('\0');
|
|
|
|
dwRes = WNetGetResourceInformation(&nr, (PVOID)&pbuf->nrOut, &dwBuf, &pszFSPart);
|
|
|
|
*(pbuf->szPath+(pwszSlash4-pwszDisplayName)) = TEXT('\\');
|
|
}
|
|
|
|
if (dwRes != WN_SUCCESS)
|
|
{
|
|
// Cleanup our buffer
|
|
LocalFree((HLOCAL)pbuf);
|
|
|
|
// return the error
|
|
return HRESULT_FROM_WIN32(dwRes);
|
|
}
|
|
|
|
//
|
|
// Check return from WNetGetResourceInformation --
|
|
// the pszFSPart parameter should split up the path into net and file system
|
|
// parts for us. If this was a regitem, then there wouldn't have been
|
|
// any filesystem part, and pszFSPart would be NULL...
|
|
if (pszFSPart && !pwszReg)
|
|
{
|
|
// make sure pszFSPart is somewhere within our buffer!
|
|
if ( ((DWORD)pszFSPart >= (DWORD)pbuf) &&
|
|
((DWORD)pszFSPart <= ((DWORD)pbuf)+SIZEOF(*pbuf))
|
|
)
|
|
{
|
|
#ifdef UNICODE
|
|
szFilePart[0] = 0;
|
|
// Since we re-use pbuf->nr.out, we need to copy this info
|
|
// out to somewhere safe...
|
|
lstrcpyn( szFilePart, pszFSPart, ARRAYSIZE(szFilePart) );
|
|
// ensure NULL termination of the string...
|
|
szFilePart[ ARRAYSIZE(szFilePart) - 1 ] = TEXT('\0');
|
|
pwszSlash = szFilePart;
|
|
#else
|
|
// We assume that the pszFSPart is at the end of pwszDisplayName
|
|
// BUGBUG: This doesn't work for DBCS!!!!
|
|
pwszSlash = pwszDisplayName + iLen - lstrlen(pszFSPart);
|
|
#endif
|
|
// Setup to get the next parent up
|
|
lstrcpy(pbuf->szPath, pbuf->nrOut.lpRemoteName);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// looks like we got a random pszFSPart pointer, so find the
|
|
// 4th backslash as our backup...
|
|
|
|
pwszSlash = pwszSlash4;
|
|
|
|
}
|
|
}
|
|
|
|
fStuffFollows = (*pwszSlash && pwszSlash[1]);
|
|
|
|
for (; ; )
|
|
{
|
|
#if 0
|
|
DebugMsg(DM_TRACE, TEXT("Net::PDN.gri t=%d d=%d u=%d r=%s p=%s"),
|
|
pbuf->nrOut.dwType, pbuf->nrOut.dwDisplayType,
|
|
pbuf->nrOut.dwUsage, pbuf->nrOut.lpRemoteName,
|
|
pbuf->nrOut.lpProvider);
|
|
#endif
|
|
|
|
//
|
|
// Two rather gross hacks to work around MPR limitations and bugs.
|
|
// First is that the current ms Novel client does not not return the
|
|
// right display type for share point (returns network directory).
|
|
// Also in the multinet case, we can not rely on the data coming
|
|
// back for which network it is a member of, so we should do an
|
|
// enum on the first call to fill it in properly...
|
|
//
|
|
// BUGBUG:: Remove after VLAD fixes the netware provider.
|
|
if (pbuf->nrOut.dwDisplayType == RESOURCEDISPLAYTYPE_DIRECTORY)
|
|
{
|
|
pbuf->nrOut.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
|
|
pbuf->nrOut.dwUsage = RESOURCEUSAGE_CONNECTABLE;
|
|
}
|
|
|
|
// Also make sure that if we have a Share point that it is
|
|
// returned as Usage of DISK instead of any...
|
|
if ((pbuf->nrOut.dwDisplayType == RESOURCEDISPLAYTYPE_SHARE) &&
|
|
(pbuf->nrOut.dwType == RESOURCETYPE_ANY))
|
|
pbuf->nrOut.dwType = RESOURCETYPE_DISK;
|
|
|
|
pidlT= _CNetwork_CreatePidlFromNetResource(0, &pbuf->nrOut,
|
|
FALSE, !fStuffFollows);
|
|
if (!pidlT)
|
|
break;
|
|
|
|
if (!pidl)
|
|
pidl = pidlT;
|
|
else
|
|
{
|
|
pidlCombined = ILCombine(pidlT, pidl);
|
|
ILFree(pidlT);
|
|
ILFree(pidl);
|
|
pidl = pidlCombined;
|
|
if (!pidl)
|
|
break;
|
|
}
|
|
|
|
if (pbuf->nrOut.lpRemoteName == NULL)
|
|
{
|
|
break; // in case we failed to add a provider field above
|
|
}
|
|
|
|
//
|
|
// See if we have not saved away the provider and we now have
|
|
// one to use.
|
|
//
|
|
if ((nr.lpProvider == NULL) && (pbuf->nrOut.lpProvider) &&
|
|
(*pbuf->nrOut.lpProvider))
|
|
{
|
|
lstrcpy(pbuf->szProvider, pbuf->nrOut.lpProvider);
|
|
nr.lpProvider = pbuf->szProvider;
|
|
}
|
|
|
|
dwBuf = SIZEOF(pbuf->buf);
|
|
|
|
// Move some of the fields from our Getinformation into
|
|
// our query network resource
|
|
nr.dwType = pbuf->nrOut.dwType;
|
|
nr.dwDisplayType = pbuf->nrOut.dwDisplayType;
|
|
nr.dwUsage = pbuf->nrOut.dwUsage;
|
|
dwRes = WNetGetResourceParent(&nr, (PVOID)&pbuf->nrOut, &dwBuf);
|
|
if (dwRes != WN_SUCCESS)
|
|
break;
|
|
#if 0
|
|
DebugMsg(DM_TRACE, TEXT("Net::PDN.grp '%s' -> %s(%d)"),
|
|
pbuf->szPath, pbuf->nrOut.lpRemoteName, pbuf->nrOut.dwType);
|
|
#endif
|
|
|
|
// When a NULL remote name is reached, we're at the Entire Network.
|
|
// If we've determined the provider that owns the resource, we have
|
|
// to add it to the IDLIST now (since we didn't know last time around
|
|
// that it was the last one). If we don't know the provider yet,
|
|
// we'll probably end up building a network-object IDLIST element
|
|
// and break out later.
|
|
if (pbuf->nrOut.lpRemoteName == NULL)
|
|
{
|
|
if (nr.lpProvider != NULL) {
|
|
pidl = _CNetwork_AddProviderToPidl(pidl, nr.lpProvider);
|
|
break; // we are at the root of our things up to now.
|
|
}
|
|
}
|
|
|
|
|
|
// Now setup to get the next parent up
|
|
lstrcpy(pbuf->szPath, pbuf->nrOut.lpRemoteName);
|
|
nr.dwType = pbuf->nrOut.dwType;
|
|
}
|
|
// Now if the pidl is set convert into moniker
|
|
if (pidl)
|
|
{
|
|
// We need to add the Rest of network entry. This is psuedo
|
|
// bogus, as we should either always do it ourself or have
|
|
// MPR always do it, but here it goes...
|
|
LoadString(HINST_THISDLL, IDS_RESTOFNET, pbuf->szPath, ARRAYSIZE(pbuf->szPath));
|
|
nr.dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
|
|
nr.dwType = RESOURCETYPE_ANY;
|
|
nr.dwUsage = RESOURCEUSAGE_CONTAINER;
|
|
nr.lpComment = pbuf->szPath;
|
|
|
|
pidlT = _CNetwork_CreatePidlFromNetResource(0, &nr, FALSE, FALSE);
|
|
// BUGBUG: check alloc failure
|
|
pidlCombined = ILCombine(pidlT, pidl);
|
|
ILFree(pidl);
|
|
ILFree(pidlT);
|
|
pidl = pidlCombined;
|
|
}
|
|
|
|
// Cleanup our buffer
|
|
LocalFree((HLOCAL)pbuf);
|
|
|
|
#ifdef DEBUG
|
|
pbuf = NULL;
|
|
#endif
|
|
|
|
if (!pidl)
|
|
return E_OUTOFMEMORY;
|
|
|
|
|
|
if (fStuffFollows)
|
|
{
|
|
IShellFolder *psfSub;
|
|
//
|
|
// We pass this off to the share points shell folder.
|
|
// Since we do not add the Net root object at the start we
|
|
// pass this ID List to the Net root to process it.
|
|
|
|
if (SUCCEEDED(hres = c_netRoot.psf->lpVtbl->BindToObject(
|
|
c_netRoot.psf, pidl, NULL, &IID_IShellFolder, &psfSub)))
|
|
{
|
|
LPITEMIDLIST pidlSubDir;
|
|
ULONG chEaten;
|
|
if (SUCCEEDED(hres = psfSub->lpVtbl->ParseDisplayName(psfSub,
|
|
hwndOwner, pbc, pwszSlash + 1, &chEaten, &pidlSubDir,
|
|
pdwAttributes)))
|
|
{
|
|
hres = SHILCombine(pidl, pidlSubDir, ppidlOut);
|
|
ILFree(pidlSubDir);
|
|
}
|
|
psfSub->lpVtbl->Release(psfSub);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pdwAttributes)
|
|
{
|
|
LPCITEMIDLIST apidlLast[1] = { ILFindLastID(pidl) };
|
|
CNetwork_GetAttributesOf(psf, 1, apidlLast, pdwAttributes);
|
|
}
|
|
|
|
hres = SHILClone(pidl, ppidlOut);
|
|
}
|
|
|
|
|
|
ILFree(pidl);
|
|
|
|
return(hres);
|
|
|
|
}
|
|
|
|
//
|
|
// Resolving non-UNC share names to UNC style names
|
|
//
|
|
// returns:
|
|
// TRUE translated the name
|
|
// FALSE didn't translate (maybe error case)
|
|
//
|
|
|
|
BOOL _CNetwork_JunctionToFSPath(LPCIDNETRESOURCE pidn, LPTSTR pszPath)
|
|
{
|
|
|
|
DWORD err;
|
|
NETRESOURCE nr;
|
|
TCHAR szAccessName[MAX_PATH];
|
|
TCHAR szRemoteName[MAX_PATH];
|
|
TCHAR szProviderName[MAX_PATH];
|
|
DWORD dwRedir;
|
|
DWORD dwResult;
|
|
UINT cbAccessName;
|
|
|
|
NET_CopyResName(pidn,szRemoteName,ARRAYSIZE(szRemoteName));
|
|
|
|
//
|
|
// To be safe: UNC prefix implies that name is available using FS access
|
|
// Theoretically it also should be routed to MPR, but it is late to do this
|
|
//
|
|
|
|
if (PathIsUNC(szRemoteName))
|
|
{
|
|
lstrcpy(pszPath, szRemoteName);
|
|
return FALSE;
|
|
}
|
|
|
|
// Check cache
|
|
ENTERCRITICAL;
|
|
if (lstrcmpi(g_szLastAttemptedJunctionName, szRemoteName) == 0)
|
|
{
|
|
// cache hit
|
|
lstrcpy(pszPath, g_szLastResolvedJunctionName);
|
|
|
|
LEAVECRITICAL;
|
|
return TRUE;
|
|
}
|
|
LEAVECRITICAL;
|
|
|
|
_fmemset(&nr, 0, SIZEOF(NETRESOURCE));
|
|
|
|
nr.lpRemoteName = (LPTSTR)szRemoteName;
|
|
|
|
if (NET_FHasProvider(pidn))
|
|
{
|
|
NET_CopyProviderName(pidn,szProviderName,ARRAYSIZE(szProviderName));
|
|
nr.lpProvider = szProviderName;
|
|
}
|
|
|
|
nr.dwType = NET_GetType(pidn) ;
|
|
nr.dwUsage = NET_GetUsage(pidn) ;
|
|
nr.dwDisplayType = NET_GetDisplayType(pidn);
|
|
|
|
dwRedir = CONNECT_TEMPORARY;
|
|
|
|
// Prepare access name buffer and net resource request buffer
|
|
cbAccessName = SIZEOF(szAccessName); // BUGBUG verify this is cb, not cch
|
|
szAccessName[0] = 0;
|
|
|
|
// dwRedir |= CONNECT_INTERACTIVE;
|
|
|
|
err = WNetUseConnection(NULL, &nr, NULL, NULL, dwRedir,
|
|
szAccessName, &cbAccessName, &dwResult);
|
|
|
|
if ((WN_SUCCESS != err) || !szAccessName[0])
|
|
{
|
|
lstrcpy(pszPath, szRemoteName);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the return name
|
|
lstrcpy(pszPath, szAccessName);
|
|
|
|
// Update cache entry
|
|
// BUGBUG We also want to record insuccessful resolution, although
|
|
// it is not really important, as we come to resolving code often
|
|
// only if it succeeded at least once.
|
|
|
|
ENTERCRITICAL;
|
|
|
|
lstrcpy(g_szLastAttemptedJunctionName, szRemoteName);
|
|
lstrcpy(g_szLastResolvedJunctionName, szAccessName);
|
|
|
|
LEAVECRITICAL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Helper function to allow external callers to query information from a
|
|
// network pidl...
|
|
//
|
|
// NOTE NOTE - This function returns a NETRESOURCE structure whose string
|
|
// pointers are not valid. On Win95 they were pointers back into the pidl's
|
|
// strings (even though the strings were copied into the supplied pv buffer.)
|
|
// Now we make the pointers really point into the buffer.
|
|
//
|
|
HRESULT CNET_GetNetResourceForPidl(LPSHELLFOLDER psf, LPCITEMIDLIST pidl,
|
|
PVOID pv, UINT cb)
|
|
{
|
|
TCHAR szStrings[3][MAX_PATH];
|
|
LPTSTR lpsz[3] = {NULL, NULL, NULL};
|
|
LPNETRES this;
|
|
NETRESOURCE *pnr = pv;
|
|
LPTSTR psz;
|
|
UINT cchT;
|
|
LPIDNETRESOURCE pidn = (LPIDNETRESOURCE)pidl;
|
|
UINT i;
|
|
|
|
if (!((psf->lpVtbl == &c_NetRootVtbl) || (psf->lpVtbl == &c_NetResVtbl)) ||
|
|
!NET_IsValidID(pidl) || cb < SIZEOF(*pnr))
|
|
return E_INVALIDARG;
|
|
|
|
this = IToClass(CNetRes, sf, psf);
|
|
|
|
#define szRemoteName szStrings[0]
|
|
#define szComment szStrings[1]
|
|
#define szProvider szStrings[2]
|
|
|
|
NET_CopyResName(pidn, szRemoteName, ARRAYSIZE(szRemoteName));
|
|
NET_CopyComment(pidn, szComment, ARRAYSIZE(szComment));
|
|
NET_CopyProviderName(pidn, szProvider, ARRAYSIZE(szProvider));
|
|
if (szProvider[0] == TEXT('\0'))
|
|
{
|
|
NET_CopyProviderNameRelative(pidl,szProvider,ARRAYSIZE(szProvider));
|
|
}
|
|
|
|
#undef szRemoteName
|
|
#undef szComment
|
|
#undef szProvider
|
|
|
|
// Fill in some of the stuff first.
|
|
pnr->dwScope = 0;
|
|
pnr->dwType = NET_GetType(pidn);
|
|
pnr->dwDisplayType = NET_GetDisplayType(pidn);
|
|
pnr->dwUsage = NET_GetUsage(pidn);
|
|
pnr->lpLocalName = NULL;
|
|
|
|
// Now lets copy the strings into the buffer and make the pointers
|
|
// relative to the buffer...
|
|
psz = (LPTSTR)(pnr + 1);
|
|
cb -= SIZEOF(*pnr);
|
|
|
|
for (i = 0; i < ARRAYSIZE(szStrings); i++)
|
|
{
|
|
if (*szStrings[i])
|
|
{
|
|
if ((cchT = lstrlen(szStrings[i]) + 1)*SIZEOF(TCHAR) <= cb)
|
|
{
|
|
lstrcpy(psz, szStrings[i]);
|
|
lpsz[i] = psz;
|
|
psz += cchT;
|
|
cb -= cchT*SIZEOF(TCHAR);
|
|
}
|
|
else
|
|
{
|
|
// A hint that the structure is ok,
|
|
// but the strings are missing
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
}
|
|
}
|
|
|
|
pnr->lpRemoteName = lpsz[0];
|
|
pnr->lpComment = lpsz[1];
|
|
pnr->lpProvider = lpsz[2];
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// PersistFolder
|
|
//
|
|
STDMETHODIMP CNetRoot_PF_QueryInterface(LPPERSISTFOLDER fld, REFIID riid, LPVOID * ppvObj)
|
|
{
|
|
LPNETRES this = IToClass(CNetRes, pf, fld);
|
|
|
|
return(this->sf.lpVtbl->QueryInterface(&this->sf, riid, ppvObj));
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CNetRoot_PF_AddRef(LPPERSISTFOLDER fld)
|
|
{
|
|
LPNETRES this = IToClass(CNetRes, pf, fld);
|
|
|
|
return(this->sf.lpVtbl->AddRef(&this->sf));
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CNetRoot_PF_Release(LPPERSISTFOLDER fld)
|
|
{
|
|
LPNETRES this = IToClass(CNetRes, pf, fld);
|
|
|
|
return(this->sf.lpVtbl->Release(&this->sf));
|
|
}
|
|
|
|
STDMETHODIMP CNetRoot_PF_GetClassID(LPPERSISTFOLDER fld, LPCLSID lpClassID)
|
|
{
|
|
*lpClassID = CLSID_ShellNetwork;
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP CNetRoot_PF_Initialize(LPPERSISTFOLDER fld, LPCITEMIDLIST pidl)
|
|
{
|
|
// Only allow the Drives root on the desktop
|
|
if (!CDesktop_IsMyNetwork(pidl) || !ILIsEmpty(_ILNext(pidl)))
|
|
{
|
|
return(E_INVALIDARG);
|
|
}
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
//
|
|
// ShellFolder
|
|
//
|
|
STDMETHODIMP CNetRoot_SF_QueryInterface(LPSHELLFOLDER psf, REFIID riid, LPVOID * ppvObj)
|
|
{
|
|
LPNETRES this = IToClass(CNetRes, sf, psf);
|
|
|
|
if (IsEqualIID(riid, &IID_IUnknown)
|
|
|| IsEqualIID(riid, &IID_IShellFolder))
|
|
{
|
|
*ppvObj = psf;
|
|
psf->lpVtbl->AddRef(psf);
|
|
return S_OK;
|
|
}
|
|
|
|
if (IsEqualIID(riid, &IID_IPersistFolder))
|
|
{
|
|
*ppvObj = &this->pf;
|
|
this->pf.lpVtbl->AddRef(&this->pf);
|
|
return S_OK;
|
|
}
|
|
|
|
*ppvObj = NULL;
|
|
|
|
return(E_NOINTERFACE);
|
|
}
|
|
|
|
typedef struct _EnumNetwork // enet
|
|
{
|
|
HANDLE hEnum;
|
|
BOOL fKeepProviderName;
|
|
DWORD grfFlags;
|
|
DWORD cItems; // Count of items in buffer
|
|
DWORD iItem; // Current index of the item in the buffer
|
|
DWORD dwRemote;
|
|
union {
|
|
NETRESOURCE anr[0];
|
|
BYTE szBuffer[8192];
|
|
};
|
|
// Following used for enumerating persistent links
|
|
LPENUMIDLIST peunk;
|
|
|
|
} EnumNetwork, * LPENUMNETWORK;
|
|
|
|
// Flags for the dwRemote field
|
|
#define RMF_CONTEXT 0x00000001 // Entire network is being enumerated
|
|
#define RMF_SHOWREMOTE 0x00000002 // Return Remote Services for next enumeration
|
|
#define RMF_REMOTESHOWN 0x00000004 // Return Remote Services for next enumeration
|
|
#define RMF_STOP_ENUM 0x00000008 // Stop enumeration
|
|
#define RMF_SHOWLINKS 0x00000010 // Hoodlinks need to be shown
|
|
|
|
//
|
|
// To be called back from within SHCreateEnumObjects
|
|
//
|
|
// lParam - LPDEFENUM
|
|
// pvData - pointer to ENUMNETWORK constructed by CNetRoot_EnumObjects
|
|
// ecid - enumeration command (event)
|
|
// index - LPDEFENUM->iCur (unused)
|
|
|
|
|
|
HRESULT CALLBACK CNetwork_EnumCallBack(LPARAM lParam, LPVOID pvData, UINT ecid, UINT index)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
LPENUMNETWORK penet = (LPENUMNETWORK)pvData;
|
|
|
|
if (ecid == ECID_SETNEXTID)
|
|
{
|
|
// Time to stop enumeration?
|
|
if (penet->dwRemote & RMF_STOP_ENUM)
|
|
return S_FALSE; // Yes
|
|
|
|
if (penet->dwRemote & RMF_SHOWLINKS)
|
|
{
|
|
if (penet->peunk)
|
|
{
|
|
ULONG celtFetched;
|
|
LPITEMIDLIST pidl;
|
|
|
|
hres = penet->peunk->lpVtbl->Next(penet->peunk, 1, &pidl, &celtFetched);
|
|
if (hres == S_OK && celtFetched == 1)
|
|
{
|
|
Assert(pidl);
|
|
CDefEnum_SetReturn(lParam, pidl);
|
|
return S_OK; // Added link
|
|
}
|
|
}
|
|
penet->dwRemote &= ~RMF_SHOWLINKS; // Done enumerating links
|
|
}
|
|
|
|
hres = S_OK;
|
|
|
|
// Do we add the remote folder?
|
|
// (Note: as a hack to ensure that the remote folder is added
|
|
// to the 'hood despite what MPR says, RMF_SHOWREMOTE can be
|
|
// set without RMF_CONTEXT set.)
|
|
if ((penet->dwRemote & RMF_SHOWREMOTE) && !(penet->dwRemote & RMF_REMOTESHOWN))
|
|
{
|
|
|
|
// Yes
|
|
// Only try to put the remote entry in once.
|
|
penet->dwRemote |= RMF_REMOTESHOWN;
|
|
|
|
// Is this not the Context container?
|
|
// (See note above as to why we are asking this question.)
|
|
if ( !(penet->dwRemote & RMF_CONTEXT) ) {
|
|
// Yes; stop after the next time
|
|
penet->dwRemote |= RMF_STOP_ENUM;
|
|
}
|
|
|
|
// We have fallen thru because the remote services is not
|
|
// installed.
|
|
|
|
// Is this not the Context container AND the remote folder
|
|
// is not installed?
|
|
if ( !(penet->dwRemote & RMF_CONTEXT) ) {
|
|
// Yes; nothing else to enumerate
|
|
return S_FALSE;
|
|
}
|
|
}
|
|
while (TRUE)
|
|
{
|
|
ULONG err = WN_SUCCESS;
|
|
LPNETRESOURCE pnr;
|
|
if (penet->iItem >= penet->cItems)
|
|
{
|
|
DWORD dwSize = SIZEOF(penet->szBuffer);
|
|
|
|
// Figure that on average no item over 128 bytes...
|
|
//penet->cItems = sizeof(penet->szBuffer) >> 7;
|
|
penet->cItems = 0xffffffff;
|
|
penet->iItem = 0;
|
|
|
|
// BUGBUG (DavePl)
|
|
err = WNetEnumResource(penet->hEnum, &penet->cItems,
|
|
penet->szBuffer, &dwSize);
|
|
DebugMsg(DM_TRACE, TEXT("Net EnumCallback: err=%d Count=%d"),
|
|
err, penet->cItems);
|
|
}
|
|
|
|
pnr = &penet->anr[penet->iItem++];
|
|
// Output some debug messages to help us track
|
|
#ifdef NET_TRACE
|
|
DebugMsg(DM_TRACE, TEXT("Net EnumCallback: err=%d s=%d, t=%d, dt=%d, u=%d, %s"),
|
|
err, pnr->dwScope, pnr->dwType, pnr->dwDisplayType,
|
|
pnr->dwUsage, pnr->lpRemoteName ? pnr->lpRemoteName : TEXT("[NULL]"));
|
|
#endif //NET_TRACE
|
|
// Note: the <= below is correct as we already incremented the index...
|
|
if (err==WN_SUCCESS && (penet->iItem <= penet->cItems))
|
|
{
|
|
ULONG grfFlags = ((pnr->dwUsage & RESOURCEUSAGE_CONTAINER) || (pnr->dwType==RESOURCETYPE_DISK)) ?
|
|
SHCONTF_FOLDERS : SHCONTF_NONFOLDERS;
|
|
|
|
// If this is the context enumeration, we want to insert the
|
|
// Remote Services after the first container.
|
|
// Remember that we need to return the Remote Services
|
|
// in the next iteration.
|
|
//
|
|
if ((pnr->dwUsage & RESOURCEUSAGE_CONTAINER) &&
|
|
(penet->dwRemote & RMF_CONTEXT))
|
|
{
|
|
penet->dwRemote |= RMF_SHOWREMOTE;
|
|
}
|
|
|
|
// Check if we found requested type of net resource.
|
|
if (penet->grfFlags & grfFlags)
|
|
{
|
|
// Yes.
|
|
Assert(lParam); // else we leak here
|
|
|
|
_CNetwork_CreatePidlFromNetResource(lParam,
|
|
pnr, penet->fKeepProviderName,
|
|
(penet->grfFlags & SHCONTF_NONFOLDERS));
|
|
|
|
break;
|
|
}
|
|
}
|
|
else if (err == WN_NO_MORE_ENTRIES) {
|
|
hres = S_FALSE; // no more element
|
|
break;
|
|
}
|
|
else {
|
|
DebugMsg(DM_ERROR, TEXT("sh ER - WNetEnumResource failed (%lx)"), err);
|
|
hres = E_FAIL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (ecid == ECID_RELEASE)
|
|
{
|
|
if (penet->peunk)
|
|
penet->peunk->lpVtbl->Release(penet->peunk);
|
|
|
|
WNetCloseEnum(penet->hEnum);
|
|
LocalFree((HLOCAL)penet);
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
//
|
|
// CNetRoot::GetPIDL
|
|
//
|
|
LPITEMIDLIST CNetRoot_GetPIDL(HWND hwnd)
|
|
{
|
|
if (!c_netHood.pidlNetHood) {
|
|
c_netHood.pidlNetHood = SHCloneSpecialIDList( hwnd, CSIDL_NETHOOD, TRUE);
|
|
}
|
|
return c_netHood.pidlNetHood;
|
|
}
|
|
|
|
//
|
|
// CNetRoot::GetPSF
|
|
//
|
|
LPSHELLFOLDER CNetRoot_GetPSF(HWND hwnd)
|
|
{
|
|
if (!c_netHood.psfNetHood)
|
|
{
|
|
LPITEMIDLIST pidlNetHood = CNetRoot_GetPIDL(hwnd);
|
|
|
|
if (pidlNetHood)
|
|
{
|
|
|
|
#ifdef USE_OLEDB
|
|
|
|
//
|
|
// We're binding to a COFSFolder
|
|
//
|
|
|
|
HRESULT hres = COFSFolder_CreateFromIDList(c_netHood.pidlNetHood, &IID_IShellFolder, &c_netHood.psfNetHood);
|
|
|
|
|
|
#else
|
|
//
|
|
// We're binding to a standard CFSFolder
|
|
//
|
|
|
|
HRESULT hres = CFSFolder_CreateFromIDList(c_netHood.pidlNetHood, &IID_IShellFolder, &c_netHood.psfNetHood);
|
|
#endif
|
|
|
|
if (FAILED(hres)) {
|
|
// cleanup ILFree(c_netHood.pidlNetHood);
|
|
// c_netHood.pidlNetHood = NULL;
|
|
DebugMsg(DM_TRACE, TEXT("Failed to create hood IShellFolder!"));
|
|
}
|
|
}
|
|
}
|
|
return c_netHood.psfNetHood;
|
|
}
|
|
|
|
//
|
|
//
|
|
// CNetRoot::EnumObjects
|
|
//
|
|
STDMETHODIMP CNetRoot_EnumObjects( LPSHELLFOLDER psf, HWND hwndOwner,
|
|
DWORD grfFlags, LPENUMIDLIST * ppenumUnknown)
|
|
{
|
|
LPNETRES this = IToClass(CNetRes, sf, psf);
|
|
HRESULT hres = E_OUTOFMEMORY;
|
|
LPENUMNETWORK penet = (void*)LocalAlloc(LPTR, SIZEOF(EnumNetwork));
|
|
|
|
if (penet)
|
|
{
|
|
// Always try to enum links.
|
|
LPSHELLFOLDER psfNetHood = CNetRoot_GetPSF(hwndOwner);
|
|
DWORD err;
|
|
|
|
penet->dwRemote = 0;
|
|
penet->peunk = NULL;
|
|
penet->cItems = 0;
|
|
penet->iItem = 0;
|
|
|
|
if (psfNetHood) {
|
|
psfNetHood->lpVtbl->EnumObjects(psfNetHood, NULL, // BUGBUG: need to assign HWND
|
|
grfFlags, &(penet->peunk));
|
|
}
|
|
if (penet->peunk)
|
|
penet->dwRemote |= RMF_SHOWLINKS;
|
|
|
|
err = _OpenEnumRetry(hwndOwner,
|
|
(grfFlags & SHCONTF_NETPRINTERSRCH) ? RESOURCETYPE_PRINT : RESOURCETYPE_ANY,
|
|
NULL, &penet->hEnum);
|
|
|
|
Assert(ILIsEqual(this->pidl, GetSpecialFolderIDList(NULL, CSIDL_NETWORK, FALSE)));
|
|
|
|
// Always add the remote folder to the 'hood
|
|
|
|
// Hack: Did WNetOpenEnum fail because of bogus reasons
|
|
// (read: bugs)?
|
|
if (WN_SUCCESS != err)
|
|
{
|
|
// Yes; still show remote anyway (only)
|
|
penet->dwRemote |= RMF_SHOWREMOTE;
|
|
}
|
|
else
|
|
{
|
|
// No; allow everything to be enumerated in the 'hood.
|
|
penet->dwRemote |= RMF_CONTEXT;
|
|
}
|
|
|
|
penet->grfFlags = grfFlags;
|
|
penet->fKeepProviderName = TRUE;
|
|
hres = SHCreateEnumObjects(hwndOwner, penet, CNetwork_EnumCallBack, ppenumUnknown);
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
|
|
void CNetRes_FillNetResource(LPCITEMIDLIST pidlAbs, LPNETRESOURCE pnr,
|
|
LPTSTR pszProviderBuff, UINT cchProviderBuff,
|
|
LPTSTR pszRemoteBuff, UINT cchRemoteBuff)
|
|
{
|
|
LPCIDNETRESOURCE pidnLast = (LPCIDNETRESOURCE)ILFindLastID(pidlAbs);
|
|
|
|
// Set the provider name from the first ID
|
|
pnr->lpProvider = NET_CopyProviderNameAbs(pidlAbs,pszProviderBuff,cchProviderBuff);
|
|
pnr->lpRemoteName = NULL;
|
|
|
|
// Set the remote name
|
|
if (NET_GetDisplayType(pidnLast)!=RESOURCEDISPLAYTYPE_ROOT &&
|
|
NET_GetDisplayType(pidnLast)!=RESOURCEDISPLAYTYPE_NETWORK)
|
|
{
|
|
pnr->lpRemoteName = NET_CopyResName(pidnLast,
|
|
pszRemoteBuff,
|
|
cchRemoteBuff);
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP CNetRes_EnumObjects( LPSHELLFOLDER psf, HWND hwndOwner,
|
|
DWORD grfFlags, LPENUMIDLIST * ppenumUnknown)
|
|
{
|
|
LPNETRES this = IToClass(CNetRes, sf, psf);
|
|
HRESULT hres = E_OUTOFMEMORY;
|
|
// We should always create enum objects with this helper call.
|
|
LPENUMNETWORK penet = (LPENUMNETWORK)LocalAlloc(LPTR, SIZEOF(EnumNetwork));
|
|
if (penet)
|
|
{
|
|
TCHAR szProvider[MAX_PATH];
|
|
TCHAR szRemote[MAX_PATH];
|
|
DWORD err;
|
|
LPCIDNETRESOURCE pidnLast;
|
|
|
|
CNetRes_FillNetResource(this->pidl, &penet->anr[0],
|
|
szProvider, ARRAYSIZE(szProvider),
|
|
szRemote, ARRAYSIZE(szRemote));
|
|
penet->dwRemote = 0;
|
|
penet->peunk = NULL;
|
|
penet->cItems = 0;
|
|
penet->iItem = 0;
|
|
|
|
err = _OpenEnumRetry(hwndOwner,
|
|
(grfFlags & SHCONTF_NETPRINTERSRCH) ? RESOURCETYPE_PRINT : RESOURCETYPE_ANY,
|
|
&penet->anr[0], &penet->hEnum);
|
|
|
|
if (err==WN_SUCCESS)
|
|
{
|
|
penet->grfFlags = grfFlags;
|
|
penet->fKeepProviderName = penet->anr[0].lpProvider == NULL;
|
|
hres = SHCreateEnumObjects(hwndOwner, penet, CNetwork_EnumCallBack, ppenumUnknown);
|
|
}
|
|
else
|
|
{
|
|
hres = HRESULT_FROM_WIN32(err);
|
|
}
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
STDMETHODIMP CNetwork_BindToObject(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPBC pbc,
|
|
REFIID riid, LPVOID * ppvOut)
|
|
{
|
|
LPNETRES this = IToClass(CNetRes, sf, psf);
|
|
|
|
HRESULT hres=E_INVALIDARG;
|
|
if (NET_IsValidID(pidl))
|
|
{
|
|
// Is this the Remote Services?
|
|
if (NET_IsRemoteFld((LPIDNETRESOURCE)pidl))
|
|
{
|
|
// Yes; get the interface from the registry
|
|
LPITEMIDLIST pidlAbs = ILCombine(this->pidl, pidl);
|
|
if (pidlAbs)
|
|
{
|
|
IPersistFolder * ppf;
|
|
|
|
// There is a special CLSID for this folder. Attempt
|
|
// to get the IPersistFolder interface to it.
|
|
hres = SHCoCreateInstance(NULL, &CLSID_Remote, NULL, &IID_IPersistFolder, &ppf);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = ppf->lpVtbl->Initialize(ppf, pidlAbs);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = ppf->lpVtbl->QueryInterface(ppf, riid, ppvOut);
|
|
}
|
|
ppf->lpVtbl->Release(ppf);
|
|
}
|
|
ILFree(pidlAbs);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LPITEMIDLIST pidlAbs = ILCombine(this->pidl, pidl);
|
|
if (pidlAbs)
|
|
{
|
|
LPITEMIDLIST pidlT;
|
|
LPITEMIDLIST pidlFound = NULL;
|
|
LPITEMIDLIST pidlRight = NULL;
|
|
hres = S_OK; // assume no error
|
|
|
|
// Search for a server or junction point after "this" one.
|
|
// Servers get their own IShellFolder since they are
|
|
// aggregated with the registry item object for
|
|
// remote computer items.
|
|
|
|
for ( pidlT=_ILSkip(pidlAbs, ILGetSize(this->pidl)-SIZEOF(USHORT))
|
|
; !ILIsEmpty(pidlT)
|
|
; pidlT=_ILNext(pidlT))
|
|
{
|
|
if ((NET_GetFlags((LPCIDNETRESOURCE)pidlT) & SHID_JUNCTION)
|
|
|| (NET_GetDisplayType((LPIDNETRESOURCE)pidlT) == RESOURCEDISPLAYTYPE_SERVER)
|
|
)
|
|
{
|
|
// We found a server or junction point.
|
|
// Separate the IDList into two.
|
|
pidlFound = pidlT;
|
|
pidlT = _ILNext(pidlT);
|
|
pidlRight = ILClone(pidlT); // copy the right portion
|
|
pidlT->mkid.cb = 0; // truncate the left.
|
|
if (pidlRight==NULL) {
|
|
hres = E_OUTOFMEMORY;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
LPSHELLFOLDER psf;
|
|
|
|
// Check if we found something (junction point == share, or server)
|
|
if (pidlRight)
|
|
{
|
|
// Yes, now what did we find?
|
|
|
|
if (NET_GetDisplayType((LPIDNETRESOURCE)pidlFound) == RESOURCEDISPLAYTYPE_SERVER)
|
|
{
|
|
if (ILIsEmpty(pidlRight))
|
|
{
|
|
hres = CNetRes_CreateInstance(pidlAbs, riid, ppvOut);
|
|
}
|
|
else
|
|
{
|
|
hres = CNetRes_CreateInstance(pidlAbs, &IID_IShellFolder, &psf);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = psf->lpVtbl->BindToObject(psf, pidlRight, pbc, riid, ppvOut);
|
|
psf->lpVtbl->Release(psf);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Assert(NET_GetFlags((LPCIDNETRESOURCE)pidlFound) & SHID_JUNCTION);
|
|
// a junction point, share
|
|
|
|
if (ILIsEmpty(pidlRight))
|
|
{
|
|
// REVIEW: If we want to support INI binding at the
|
|
// share point, we should do something else here.
|
|
#ifdef USE_OLEDB
|
|
hres = COFSFolder_CreateFromIDList(pidlAbs, riid, ppvOut);
|
|
#else
|
|
hres = CFSFolder_CreateFromIDList(pidlAbs, riid, ppvOut);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// REVIEW: If we want to support INI binding at the
|
|
// share point, we should do something else here.
|
|
LPSHELLFOLDER psf;
|
|
#ifdef USE_OLEDB
|
|
hres = COFSFolder_CreateFromIDList(pidlAbs, &IID_IShellFolder, &psf);
|
|
#else
|
|
hres = CFSFolder_CreateFromIDList(pidlAbs, &IID_IShellFolder, &psf);
|
|
#endif
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = psf->lpVtbl->BindToObject(psf, pidlRight, pbc, riid, ppvOut);
|
|
psf->lpVtbl->Release(psf);
|
|
}
|
|
}
|
|
}
|
|
|
|
ILFree(pidlRight);
|
|
}
|
|
else
|
|
{
|
|
// Didn't find a server or junction point
|
|
hres = CNetRes_CreateInstance(pidlAbs, riid, ppvOut);
|
|
}
|
|
}
|
|
|
|
ILFree(pidlAbs);
|
|
}
|
|
else
|
|
{
|
|
hres = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
LONG CNetRoot_GetPIDLType(LPCITEMIDLIST pidl)
|
|
{
|
|
// Take a pidl and return its place in a collating sequence
|
|
// based upon its type.
|
|
// The following code is aware of the different valid types,
|
|
// but not the precise collating order.
|
|
|
|
if (NET_IsValidID(pidl)) {
|
|
if (NET_IsRemoteFld((LPIDNETRESOURCE)pidl)) {
|
|
return HOOD_COL_REMOTE;
|
|
}
|
|
if (NET_GetDisplayType((LPIDNETRESOURCE)pidl) == RESOURCEDISPLAYTYPE_ROOT) {
|
|
return HOOD_COL_RON;
|
|
}
|
|
return HOOD_COL_NET;
|
|
}
|
|
return HOOD_COL_FILE;
|
|
}
|
|
|
|
STDMETHODIMP CNetRoot_CompareIDs(LPSHELLFOLDER psf, LPARAM iCol, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
|
|
{
|
|
HRESULT hres = E_INVALIDARG;
|
|
|
|
// First obtain the collate type of the pidls and their respective
|
|
// collate order.
|
|
|
|
LONG iColateType1 = CNetRoot_GetPIDLType(pidl1);
|
|
LONG iColateType2 = CNetRoot_GetPIDLType(pidl2);
|
|
|
|
if (iColateType1 == iColateType2) {
|
|
|
|
// pidls are of same type.
|
|
|
|
if (iColateType1 == HOOD_COL_FILE) {
|
|
|
|
// pidls are both of type file, so pass on to the IShellFolder
|
|
// interface for the hoods custom directory.
|
|
|
|
psf = CNetRoot_GetPSF(NULL);
|
|
if (psf) {
|
|
return psf->lpVtbl->CompareIDs(psf, iCol, pidl1, pidl2);
|
|
}
|
|
}
|
|
else {
|
|
|
|
// pidls same and are not of type file,
|
|
// so both must be a type understood
|
|
// by the CNetwork class - pass on to compare.
|
|
|
|
return CNetwork_CompareIDs(psf, iCol, pidl1, pidl2);
|
|
}
|
|
}
|
|
else {
|
|
|
|
// pidls are not of same type, so have already been correctly
|
|
// collated (consequently, sorting is first by type and
|
|
// then by subfield).
|
|
|
|
return ResultFromShort(((iColateType2 - iColateType1) > 0) ? -1 : 1);
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
STDMETHODIMP CNetwork_CompareIDs(LPSHELLFOLDER psf, LPARAM iCol, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
|
|
{
|
|
HRESULT hres = E_INVALIDARG;
|
|
|
|
// BUGBUG (DavePl) We really shouldn't need to test pidl1 and pidl2,
|
|
// since they should be guaranteed to be non-NULL by the time they
|
|
// get here. Unfortunately, there are so many holes in the error
|
|
// checking leading up to this call that its the most practical
|
|
// place to do it.
|
|
|
|
if (pidl1 && pidl2 && NET_IsValidID(pidl1) && NET_IsValidID(pidl2))
|
|
{
|
|
TCHAR szBuff1[MAX_PATH];
|
|
TCHAR szBuff2[MAX_PATH];
|
|
LPTSTR psz1;
|
|
LPTSTR psz2;
|
|
LPIDNETRESOURCE pidn1 = (LPIDNETRESOURCE)pidl1;
|
|
LPIDNETRESOURCE pidn2 = (LPIDNETRESOURCE)pidl2;
|
|
|
|
switch (iCol)
|
|
{
|
|
case ICOL_COMMENT:
|
|
{
|
|
LPTSTR pszComment1 = NET_CopyComment(pidn1,szBuff1,ARRAYSIZE(szBuff1));
|
|
LPTSTR pszComment2 = NET_CopyComment(pidn2,szBuff2,ARRAYSIZE(szBuff2));
|
|
|
|
// The GetComment function handled cases of null
|
|
// strings so we can go directo to Lstrcmp..
|
|
|
|
hres = ResultFromShort(lstrcmpi(pszComment1, pszComment2));
|
|
if (hres != 0)
|
|
return hres;
|
|
}
|
|
|
|
// Ok to Fall through to name here.
|
|
case ICOL_NAME:
|
|
// Compare by name. This is the one case where we need to handle
|
|
// simple ids in either place. We will try to resync the items
|
|
// if we find a case of this before do the compares.
|
|
// Check for relative IDs. In particular if one item is at
|
|
// a server and the other is at RestOfNet then try to resync
|
|
// the two
|
|
//
|
|
if (NET_GetFlags(pidn2)==SHID_NET)
|
|
{
|
|
while((NET_GetFlags(pidn1)==SHID_NET_RESTOFNET) ||
|
|
(NET_GetFlags(pidn1)==SHID_NET_DOMAIN))
|
|
{
|
|
// Need to advance pidl1
|
|
pidl1 = _ILNext(pidl1);
|
|
pidn1 = (LPIDNETRESOURCE)pidl1;
|
|
}
|
|
}
|
|
|
|
if (NET_GetFlags(pidn1)==SHID_NET)
|
|
{
|
|
while((NET_GetFlags(pidn2)==SHID_NET_RESTOFNET) ||
|
|
(NET_GetFlags(pidn2)==SHID_NET_DOMAIN))
|
|
{
|
|
// Need to advance pidl2
|
|
pidl2 = _ILNext(pidl2);
|
|
pidn2 = (LPIDNETRESOURCE)pidl2;
|
|
}
|
|
}
|
|
|
|
psz1 = NET_CopyResName(pidn1,szBuff1,ARRAYSIZE(szBuff1));
|
|
psz2 = NET_CopyResName(pidn2,szBuff2,ARRAYSIZE(szBuff2));
|
|
|
|
hres = ResultFromShort(lstrcmpi(psz1,psz2));
|
|
|
|
|
|
// If they identical, compare the rest of IDs.
|
|
if (hres==0)
|
|
{
|
|
hres = ILCompareRelIDs(psf, pidl1, pidl2);
|
|
}
|
|
|
|
// If they're still identical, compare provider names.
|
|
if (hres==0)
|
|
{
|
|
LPTSTR pszProv1;
|
|
LPTSTR pszProv2;
|
|
|
|
pszProv1 = NET_CopyProviderNameRelative(pidl1,szBuff1,ARRAYSIZE(szBuff1));
|
|
pszProv2 = NET_CopyProviderNameRelative(pidl2,szBuff2,ARRAYSIZE(szBuff2));
|
|
|
|
if (pszProv1 && pszProv2)
|
|
hres = ResultFromShort(lstrcmp(pszProv1, pszProv2));
|
|
else
|
|
{
|
|
if (pszProv1 || pszProv2)
|
|
hres = ResultFromShort(pszProv1 ? 1 : -1);
|
|
else
|
|
hres = ResultFromShort(0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// To be called back from within CDefFolderMenu
|
|
//
|
|
HRESULT CALLBACK CNetwork_DFMCallBackBG(LPSHELLFOLDER psf, HWND hwndOwner,
|
|
LPDATAOBJECT pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
LPNETRES this;
|
|
|
|
psf = RegItems_GetInnerShellFolder(psf); // returns same vtbl if not a reg item
|
|
this = IToClass(CNetRes, sf, psf);
|
|
|
|
switch(uMsg)
|
|
{
|
|
case DFM_MERGECONTEXTMENU:
|
|
CDefFolderMenu_MergeMenu(HINST_THISDLL, POPUP_NETWORK_BACKGROUND,
|
|
POPUP_NETWORK_POPUPMERGE, (LPQCMINFO)lParam);
|
|
break;
|
|
|
|
case DFM_GETHELPTEXT:
|
|
LoadStringA(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPSTR)lParam, HIWORD(wParam));
|
|
break;
|
|
|
|
case DFM_GETHELPTEXTW:
|
|
LoadStringW(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPWSTR)lParam, HIWORD(wParam));
|
|
break;
|
|
|
|
case DFM_INVOKECOMMAND:
|
|
switch(wParam)
|
|
{
|
|
case FSIDM_SORTBYNAME:
|
|
case FSIDM_SORTBYCOMMENT:
|
|
ShellFolderView_ReArrange(hwndOwner, (wParam == FSIDM_SORTBYNAME) ? 0 : 1);
|
|
break;
|
|
|
|
case FSIDM_PROPERTIESBG:
|
|
hres = SHPropertiesForPidl(hwndOwner, this->pidl, (LPCTSTR)lParam);
|
|
break;
|
|
|
|
default:
|
|
// This is one of view menu items, use the default code.
|
|
hres = S_FALSE;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
hres = E_NOTIMPL;
|
|
break;
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
const struct
|
|
{
|
|
UINT uType;
|
|
LPCTSTR pszValName;
|
|
} c_sNetCols[] =
|
|
{
|
|
// { SHID_ROOT_REGITEM , "NetHoodCols" }, // Only one
|
|
// { SHID_NET_NETWORK , "NetNetworkCols" }, // OK to be different
|
|
{ SHID_NET_DOMAIN , TEXT("NetDomainCols") },
|
|
{ SHID_NET_SERVER , TEXT("NetServerCols") },
|
|
// { SHID_NET_SHARE , "NetShareCols" }, // Uses FS view
|
|
// { SHID_NET_DIRECTORY, "NetDirectoryCols" }, // Uses FS view
|
|
// { SHID_NET_PRINTER , "NetPrinterCols" }, // Uses no view
|
|
// { SHID_NET_RESTOFNET, "NetRestOfNetCols" }, // Only one
|
|
// { SHID_NET_SHAREADMIN, "NetShareAdminCols" }, // Uses FS view
|
|
} ;
|
|
|
|
|
|
//
|
|
// Callback from SHCreateShellFolderViewEx
|
|
//
|
|
HRESULT CALLBACK CNetwork_FNVCallBack(LPSHELLVIEW psvOuter,
|
|
LPSHELLFOLDER psf,
|
|
HWND hwndOwner,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
HRESULT hres = S_OK; // assume no error
|
|
LPNETRES this;
|
|
|
|
psf = RegItems_GetInnerShellFolder(psf); // returns same vtbl if not a reg item
|
|
this = IToClass(CNetRes, sf, psf);
|
|
|
|
switch(uMsg)
|
|
{
|
|
case DVM_MERGEMENU:
|
|
CDefFolderMenu_MergeMenu(HINST_THISDLL, 0, POPUP_NETWORK_POPUPMERGE, (LPQCMINFO)lParam);
|
|
break;
|
|
|
|
case DVM_INVOKECOMMAND:
|
|
hres = CNetwork_DFMCallBackBG(psf, hwndOwner, NULL, DFM_INVOKECOMMAND, wParam, lParam);
|
|
break;
|
|
|
|
case DVM_GETHELPTEXT:
|
|
#ifdef UNICODE
|
|
hres = CNetwork_DFMCallBackBG(psf, hwndOwner, NULL, DFM_GETHELPTEXTW, wParam, lParam);
|
|
#else
|
|
hres = CNetwork_DFMCallBackBG(psf, hwndOwner, NULL, DFM_GETHELPTEXT, wParam, lParam);
|
|
#endif
|
|
break;
|
|
|
|
case DVM_BACKGROUNDENUM:
|
|
hres = S_OK;
|
|
break;
|
|
|
|
case DVM_GETCOLSAVESTREAM:
|
|
{
|
|
int i;
|
|
UINT uType;
|
|
|
|
uType = (UINT)((LPCIDNETRESOURCE)ILFindLastID(this->pidl))->bFlags;
|
|
|
|
for (i = 0; ; ++i)
|
|
{
|
|
if (i >= ARRAYSIZE(c_sNetCols))
|
|
{
|
|
// Must be one where per-folder settings is OK
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (uType == c_sNetCols[i].uType)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
*(LPSTREAM *)lParam = OpenRegStream(HKEY_CURRENT_USER, c_szRegExplorer,
|
|
c_sNetCols[i].pszValName, wParam);
|
|
return lParam ? S_OK : E_FAIL;
|
|
}
|
|
|
|
default:
|
|
hres = E_FAIL;
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
STDMETHODIMP CNetRoot_CreateViewObject(LPSHELLFOLDER psf, HWND hwnd, REFIID riid, LPVOID * ppvOut)
|
|
{
|
|
LPNETRES this = IToClass(CNetRes, sf, psf);
|
|
|
|
if (IsEqualIID(riid, &IID_IShellView))
|
|
{
|
|
LPCITEMIDLIST pidl = CNetRoot_GetPIDL(hwnd);
|
|
if (pidl)
|
|
{
|
|
CSFV csfv = {
|
|
SIZEOF(CSFV), // cbSize
|
|
this->psf, // pshf
|
|
NULL, // psvOuter
|
|
pidl, // pidl
|
|
SHCNE_RENAME|SHCNE_CREATE|SHCNE_DELETE|SHCNE_UPDATEDIR|SHCNE_UPDATEITEM, // lEvents
|
|
CNetwork_FNVCallBack, // pfnCallback
|
|
0,
|
|
};
|
|
return SHCreateShellFolderViewEx(&csfv, (LPSHELLVIEW *)ppvOut);
|
|
}
|
|
}
|
|
else if (IsEqualIID(riid, &IID_IDropTarget))
|
|
{
|
|
return CIDLDropTarget_Create(hwnd, &c_CNetRootTargetVtbl,
|
|
this->pidl, (LPDROPTARGET *)ppvOut);
|
|
}
|
|
|
|
return CNetwork_CreateViewObject(psf, hwnd, riid, ppvOut);
|
|
}
|
|
|
|
STDMETHODIMP CNetwork_CreateViewObject(LPSHELLFOLDER psf, HWND hwnd, REFIID riid, LPVOID * ppvOut)
|
|
{
|
|
LPNETRES this = IToClass(CNetRes, sf, psf);
|
|
|
|
if (IsEqualIID(riid, &IID_IShellView))
|
|
{
|
|
CSFV csfv = {
|
|
SIZEOF(CSFV), // cbSize
|
|
this->psf, // pshf
|
|
NULL, // psvOuter
|
|
this->pidl, // pidl (pidlMonitor)
|
|
SHCNE_RENAMEITEM|SHCNE_RENAMEFOLDER|SHCNE_CREATE|SHCNE_DELETE|SHCNE_UPDATEDIR|SHCNE_UPDATEITEM, // lEvents
|
|
CNetwork_FNVCallBack, // pfnCallback
|
|
0,
|
|
};
|
|
return SHCreateShellFolderViewEx(&csfv, (LPSHELLVIEW *)ppvOut);
|
|
}
|
|
else if (IsEqualIID(riid, &IID_IShellDetails))
|
|
{
|
|
return CNETDetails_Create(hwnd, ppvOut);
|
|
}
|
|
else if (IsEqualIID(riid, &IID_IContextMenu))
|
|
{
|
|
return CDefFolderMenu_Create(this->pidl, hwnd,
|
|
0, NULL, this->psf, CNetwork_DFMCallBackBG,
|
|
NULL, NULL, (LPCONTEXTMENU *)ppvOut);
|
|
}
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
HRESULT CALLBACK CNetRoot_GAOCallback(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, ULONG* prgfInOut)
|
|
{
|
|
if (NET_IsValidID(pidl))
|
|
{
|
|
return CNetwork_GetAttributesOf(psf, 1, &pidl, prgfInOut);
|
|
}
|
|
|
|
psf = CNetRoot_GetPSF(NULL);
|
|
return psf->lpVtbl->GetAttributesOf(psf, 1, &pidl, prgfInOut);
|
|
}
|
|
|
|
STDMETHODIMP CNetRoot_GetAttributesOf(LPSHELLFOLDER psf, UINT cidl,
|
|
LPCITEMIDLIST * apidl, ULONG * prgfInOut)
|
|
{
|
|
HRESULT hres;
|
|
Assert(psf);
|
|
|
|
if (cidl == 0)
|
|
{
|
|
//
|
|
// The user can rename links in the hood.
|
|
//
|
|
hres = CNetwork_GetAttributesOf(psf, cidl, apidl, prgfInOut);
|
|
*prgfInOut |= SFGAO_CANRENAME;
|
|
}
|
|
else
|
|
{
|
|
hres = Multi_GetAttributesOf(psf, cidl, apidl, prgfInOut, CNetRoot_GAOCallback);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CALLBACK CNetwork_GAOCallback(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, ULONG* prgfInOut)
|
|
{
|
|
|
|
// As Netware objects have property sheet pages we
|
|
// currently enable them. There is a problem that MSNET objects as
|
|
// well as other providers may not have prop sheets. We should deal
|
|
// with this somehow...
|
|
// Standard attributes. Note that property sheets are
|
|
// not supported by default.
|
|
ULONG rgfOut = (SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_HASSUBFOLDER |
|
|
SFGAO_FOLDER | SFGAO_FILESYSANCESTOR);
|
|
// ULONG rgfOut = (SFGAO_CANLINK | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR);
|
|
|
|
LPCIDNETRESOURCE pidn = (LPCIDNETRESOURCE)pidl;
|
|
|
|
/* note, no longer display SHARE hand for ordinary shares in the net
|
|
* hierarchy, since it's very distracting.
|
|
* -- gregj/billv, 02/22/94
|
|
*/
|
|
#if 0
|
|
if (NET_GetDisplayType(pidn)==RESOURCEDISPLAYTYPE_SHAREADMIN)
|
|
{
|
|
rgfOut |= SFGAO_SHARE;
|
|
}
|
|
#endif
|
|
if (NET_GetFlags(pidn) & SHID_JUNCTION)
|
|
{
|
|
if (NET_GetType(pidn) == RESOURCETYPE_DISK)
|
|
rgfOut |= SFGAO_FILESYSTEM|SFGAO_DROPTARGET;
|
|
else
|
|
rgfOut &= ~SFGAO_FILESYSANCESTOR;
|
|
}
|
|
|
|
// printers are drop targets for printing
|
|
if (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_SHARE
|
|
&& NET_GetType(pidn) == RESOURCETYPE_PRINT)
|
|
{
|
|
rgfOut |= SFGAO_DROPTARGET;
|
|
}
|
|
|
|
if (NET_IsRemoteFld(pidn))
|
|
{
|
|
rgfOut &= ~(SFGAO_FILESYSANCESTOR|SFGAO_FILESYSTEM);
|
|
}
|
|
|
|
*prgfInOut = rgfOut;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CNetwork_GetAttributesOf(LPSHELLFOLDER psf, UINT cidl,
|
|
LPCITEMIDLIST * apidl, ULONG * prgfInOut)
|
|
{
|
|
HRESULT hres;
|
|
if (cidl==0)
|
|
{
|
|
*prgfInOut &= (SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_HASSUBFOLDER |
|
|
SFGAO_FOLDER | SFGAO_FILESYSANCESTOR);
|
|
hres = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hres = Multi_GetAttributesOf(psf, cidl, apidl, prgfInOut, CNetwork_GAOCallback);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
//===========================================================================
|
|
// CNETIDLData : Implementation
|
|
//===========================================================================
|
|
|
|
STDMETHODIMP CNETIDLData_QueryGetData(LPDATAOBJECT pdtobj, LPFORMATETC pformatetc)
|
|
{
|
|
if (pformatetc->tymed & TYMED_HGLOBAL)
|
|
{
|
|
if (pformatetc->cfFormat == g_cfNetResource)
|
|
return CNETIDLData_GetNetResource(pdtobj, NULL);
|
|
|
|
if (pformatetc->cfFormat == CF_HDROP)
|
|
return CNETIDLData_GetHDrop(pdtobj, NULL);
|
|
}
|
|
|
|
return CIDLData_QueryGetData(pdtobj, pformatetc);
|
|
}
|
|
|
|
STDMETHODIMP CNETIDLData_GetData(LPDATAOBJECT pdtobj, LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)
|
|
{
|
|
if (pformatetc->tymed & TYMED_HGLOBAL)
|
|
{
|
|
if (pformatetc->cfFormat == g_cfNetResource)
|
|
return CNETIDLData_GetNetResource(pdtobj, pmedium);
|
|
|
|
if (pformatetc->cfFormat == CF_HDROP)
|
|
return CNETIDLData_GetHDrop(pdtobj, pmedium);
|
|
}
|
|
|
|
return CIDLData_GetData(pdtobj, pformatetc, pmedium);
|
|
}
|
|
|
|
IDataObjectVtbl c_CNETIDLDataVtbl = {
|
|
CIDLData_QueryInterface,
|
|
CIDLData_AddRef,
|
|
CIDLData_Release,
|
|
CNETIDLData_GetData,
|
|
CIDLData_GetDataHere,
|
|
CNETIDLData_QueryGetData,
|
|
CIDLData_GetCanonicalFormatEtc,
|
|
CIDLData_SetData,
|
|
CIDLData_EnumFormatEtc,
|
|
CIDLData_Advise,
|
|
CIDLData_Unadvise,
|
|
CIDLData_EnumAdvise
|
|
};
|
|
|
|
static ICONMAP c_aicmpNet[] = {
|
|
{ SHID_NET_NETWORK , II_NETWORK },
|
|
{ SHID_NET_DOMAIN , II_GROUP },
|
|
{ SHID_NET_SERVER , II_SERVER },
|
|
{ SHID_NET_SHARE , II_FOLDER },
|
|
{ SHID_NET_DIRECTORY , II_FOLDER },
|
|
{ SHID_NET_PRINTER , II_PRINTER },
|
|
{ SHID_NET_RESTOFNET , II_WORLD },
|
|
{ SHID_NET_SHAREADMIN , II_DRIVEFIXED },
|
|
{ SHID_NET_TREE , II_TREE },
|
|
{ SHID_NET_NDSCONTAINER, II_NDSCONTAINER },
|
|
};
|
|
|
|
typedef struct {
|
|
LPNETRES this;
|
|
LPDATAOBJECT pdtobj;
|
|
LPCTSTR pStartPage;
|
|
} NETPROPSTUFF;
|
|
|
|
TCHAR const c_szNetworkClass[] = TEXT("Network");
|
|
|
|
// the offset of the "Folder" key
|
|
#define NET_KEY_FOLDER 3
|
|
|
|
HRESULT Net_OpenKeys(HKEY ahkeys[4], LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlRel)
|
|
{
|
|
LPITEMIDLIST pidlAbs = ILCombine(pidlFolder, pidlRel);
|
|
if (pidlAbs)
|
|
{
|
|
ahkeys[0] = ahkeys[1] = ahkeys[2] = ahkeys[3] = NULL;
|
|
|
|
ahkeys[0] = CNetwork_OpenProviderTypeKey(pidlAbs);
|
|
ahkeys[1] = CNetwork_OpenProviderKey(pidlAbs);
|
|
SHRegOpenKey(HKEY_CLASSES_ROOT, c_szNetworkClass, &ahkeys[2]);
|
|
SHRegOpenKey(HKEY_CLASSES_ROOT, c_szFolderClass, &ahkeys[3]);
|
|
ILFree(pidlAbs);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// REVIEW: Almost identical code in fstreex.c
|
|
//
|
|
DWORD CALLBACK _CNetwork_PropertiesThreadProc(NETPROPSTUFF * pps)
|
|
{
|
|
|
|
HRESULT hres = E_UNEXPECTED;
|
|
STGMEDIUM medium;
|
|
LPIDA pida = DataObj_GetHIDA(pps->pdtobj, &medium);
|
|
|
|
Assert(medium.hGlobal);
|
|
|
|
if (pida)
|
|
{
|
|
// Yes, do context menu.
|
|
HKEY ahkeys[4];
|
|
hres = Net_OpenKeys(ahkeys, pps->this->pidl, IDA_GetIDListPtr(pida, 0));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
LPTSTR pszCaption = SHGetCaption(medium.hGlobal);
|
|
SHOpenPropSheet(pszCaption, ahkeys, ARRAYSIZE(ahkeys),
|
|
&CLSID_ShellNetDefExt,
|
|
pps->pdtobj, NULL, pps->pStartPage);
|
|
if (pszCaption)
|
|
SHFree(pszCaption);
|
|
|
|
SHRegCloseKeys(ahkeys, ARRAYSIZE(ahkeys));
|
|
}
|
|
|
|
HIDA_ReleaseStgMedium(pida, &medium);
|
|
}
|
|
|
|
pps->pdtobj->lpVtbl->Release(pps->pdtobj);
|
|
pps->this->sf.lpVtbl->Release(&pps->this->sf);
|
|
LocalFree((HLOCAL)pps);
|
|
|
|
return hres;
|
|
}
|
|
|
|
BOOL WINAPI Net_AddPages(LPVOID lp, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
|
|
{
|
|
//
|
|
// Shell has no default page for network object. Drives_AddPages
|
|
// will add a "drive" property sheet page to all the shares (if it
|
|
// supports UNC).
|
|
//
|
|
return Drives_AddPages(lp, lpfnAddPage, lParam);
|
|
}
|
|
|
|
HRESULT CNetwork_Properties(LPNETRES this, LPDATAOBJECT pdtobj, LPCTSTR pStartPage)
|
|
{
|
|
HANDLE hThread;
|
|
DWORD idThread;
|
|
UINT cbStartPage = HIWORD(pStartPage) ? lstrlen(pStartPage) * SIZEOF(TCHAR) + SIZEOF(TCHAR) : 0;
|
|
NETPROPSTUFF *pps = (NETPROPSTUFF *)LocalAlloc(LPTR, SIZEOF(NETPROPSTUFF) + cbStartPage);
|
|
if (pps)
|
|
{
|
|
pps->pdtobj = pdtobj;
|
|
pps->this = this;
|
|
pdtobj->lpVtbl->AddRef(pdtobj);
|
|
this->sf.lpVtbl->AddRef(&this->sf);
|
|
pps->pStartPage = pStartPage;
|
|
if (HIWORD(pStartPage))
|
|
{
|
|
pps->pStartPage = (LPTSTR)(pps+1);
|
|
lstrcpy((LPTSTR)(pps->pStartPage), pStartPage);
|
|
}
|
|
|
|
hThread = CreateThread(NULL, 0, _CNetwork_PropertiesThreadProc, pps, 0, &idThread);
|
|
|
|
if (hThread) {
|
|
CloseHandle(hThread);
|
|
return S_OK;
|
|
} else {
|
|
pdtobj->lpVtbl->Release(pdtobj);
|
|
this->sf.lpVtbl->Release(&this->sf);
|
|
LocalFree((HLOCAL)pps);
|
|
return E_UNEXPECTED;
|
|
}
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
// CNETDetails : Column definitions
|
|
//===========================================================================
|
|
#define ICOL_FIRST ICOL_NAME
|
|
|
|
|
|
const COL_DATA s_net_cols[] = {
|
|
{ICOL_NAME, IDS_NAME_COL, 30, LVCFMT_LEFT},
|
|
{ICOL_COMMENT, IDS_COMMENT_COL, 30, LVCFMT_LEFT}
|
|
};
|
|
|
|
|
|
//===========================================================================
|
|
// CNETDetails : Vtable
|
|
//===========================================================================
|
|
|
|
STDMETHODIMP CNETDetails_GetDetailsOf(IShellDetails * psd, LPCITEMIDLIST pidl, UINT iCol, LPSHELLDETAILS lpDetails);
|
|
STDMETHODIMP CNETDetails_ColumnClick(IShellDetails * psd, UINT iColumn);
|
|
|
|
IShellDetailsVtbl c_NETDetailVtbl =
|
|
{
|
|
SH32Unknown_QueryInterface,
|
|
SH32Unknown_AddRef,
|
|
SH32Unknown_Release,
|
|
CNETDetails_GetDetailsOf,
|
|
CNETDetails_ColumnClick,
|
|
};
|
|
|
|
typedef struct _CNETDetails
|
|
{
|
|
SH32Unknown SH32Unk;
|
|
|
|
HWND hwndMain;
|
|
} CNETDetails;
|
|
|
|
|
|
HRESULT CNETDetails_Create(HWND hwndMain, LPVOID * ppvOut)
|
|
{
|
|
HRESULT hres = E_OUTOFMEMORY;
|
|
CNETDetails *psd = (void*)LocalAlloc(LPTR, SIZEOF(CNETDetails));
|
|
if (!psd)
|
|
{
|
|
goto Error1;
|
|
}
|
|
|
|
psd->SH32Unk.unk.lpVtbl = (IUnknownVtbl *)&c_NETDetailVtbl;
|
|
psd->SH32Unk.cRef = 1;
|
|
psd->SH32Unk.riid = &IID_IShellDetails;
|
|
|
|
psd->hwndMain = hwndMain;
|
|
|
|
*ppvOut = psd;
|
|
|
|
return(S_OK);
|
|
|
|
Error1:;
|
|
return(hres);
|
|
}
|
|
|
|
|
|
//
|
|
// Note: we may someday want to expand this to include more information...
|
|
|
|
STDMETHODIMP CNETDetails_GetDetailsOf(IShellDetails * psd, LPCITEMIDLIST pidl,
|
|
UINT iColumn, LPSHELLDETAILS lpDetails)
|
|
{
|
|
CNETDetails * this = IToClass(CNETDetails, SH32Unk.unk, psd);
|
|
LPIDNETRESOURCE pidn = (LPIDNETRESOURCE)pidl;
|
|
#ifdef UNICODE
|
|
TCHAR szTemp[MAX_PATH];
|
|
UINT cchLen;
|
|
#endif
|
|
|
|
if (iColumn >= ICOL_MAX)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
lpDetails->str.uType = STRRET_CSTR;
|
|
lpDetails->str.cStr[0] = '\0';
|
|
|
|
if (!pidn)
|
|
{
|
|
#ifdef UNICODE
|
|
LoadString(HINST_THISDLL, s_net_cols[iColumn].ids,
|
|
szTemp, ARRAYSIZE(szTemp));
|
|
lpDetails->str.pOleStr = SHAlloc((lstrlen(szTemp)+1)*SIZEOF(TCHAR));
|
|
if (lpDetails->str.pOleStr == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
lpDetails->str.uType = STRRET_OLESTR;
|
|
lstrcpy(lpDetails->str.pOleStr,szTemp);
|
|
}
|
|
#else
|
|
LoadString(HINST_THISDLL, s_net_cols[iColumn].ids,
|
|
lpDetails->str.cStr, ARRAYSIZE(lpDetails->str.cStr));
|
|
#endif
|
|
lpDetails->fmt = s_net_cols[iColumn].iFmt;
|
|
lpDetails->cxChar = s_net_cols[iColumn].cchCol;
|
|
return(NOERROR);
|
|
}
|
|
|
|
switch (iColumn)
|
|
{
|
|
case ICOL_NAME:
|
|
if (NET_IsValidID(pidl))
|
|
{
|
|
if (NET_IsReg(pidn))
|
|
{
|
|
// NOTE: RegItems_GetName doesn't use remoteComputerRegInfo
|
|
// except to look at the registry key and possibly
|
|
// notice that required reg items = 0
|
|
|
|
HRESULT hres;
|
|
REGITEMSINFO remoteComputerRegInfo =
|
|
{
|
|
NULL,
|
|
NULL,
|
|
TEXT(':'),
|
|
SHID_NET_REGITEM,
|
|
NULL,
|
|
-1,
|
|
SFGAO_FOLDER | SFGAO_CANLINK,
|
|
0, // no required reg items
|
|
NULL
|
|
};
|
|
remoteComputerRegInfo.hkRegItems = SHGetExplorerSubHkey(HKEY_LOCAL_MACHINE, c_szRemoteComputerNameSpace, FALSE);
|
|
hres = RegItems_GetName(&remoteComputerRegInfo, (LPITEMIDLIST)pidn, &lpDetails->str);
|
|
RegCloseKey(remoteComputerRegInfo.hkRegItems);
|
|
return hres;
|
|
}
|
|
else
|
|
{
|
|
#ifdef UNICODE
|
|
if (NET_IsUnicode(pidn))
|
|
{
|
|
NET_CopyResName(pidn,szTemp,ARRAYSIZE(szTemp));
|
|
cchLen = lstrlen(szTemp)+1;
|
|
lpDetails->str.pOleStr = (LPWSTR)SHAlloc(cchLen*SIZEOF(TCHAR));
|
|
if (lpDetails->str.pOleStr)
|
|
{
|
|
lstrcpyn(lpDetails->str.pOleStr,szTemp,cchLen);
|
|
lpDetails->str.uType = STRRET_OLESTR;
|
|
}
|
|
else
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
lpDetails->str.uType = STRRET_OFFSET;
|
|
lpDetails->str.uOffset = (LPBYTE)pidn->szNetResName - (LPBYTE)(pidn);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FS_GetDetailsOf(NULL, pidl, FS_ICOL_NAME, lpDetails);
|
|
}
|
|
break;
|
|
|
|
case ICOL_COMMENT:
|
|
if (NET_IsValidID(pidl))
|
|
{
|
|
if (NET_IsReg(pidn))
|
|
{
|
|
#ifdef UNICODE
|
|
LoadString(HINST_THISDLL, IDS_DRIVES_REGITEM, szTemp, ARRAYSIZE(szTemp));
|
|
cchLen = lstrlen(szTemp)+1;
|
|
lpDetails->str.pOleStr = (LPWSTR)SHAlloc(cchLen*SIZEOF(TCHAR));
|
|
if (lpDetails->str.pOleStr)
|
|
{
|
|
lstrcpyn(lpDetails->str.pOleStr,szTemp,cchLen);
|
|
lpDetails->str.uType = STRRET_OLESTR;
|
|
}
|
|
else
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
#else
|
|
lpDetails->str.uType = STRRET_CSTR;
|
|
LoadString(HINST_THISDLL, IDS_DRIVES_REGITEM, lpDetails->str.cStr, ARRAYSIZE(lpDetails->str.cStr));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef UNICODE
|
|
if (NET_IsUnicode(pidn))
|
|
{
|
|
NET_CopyComment(pidn,szTemp,ARRAYSIZE(szTemp));
|
|
cchLen = lstrlen(szTemp)+1;
|
|
lpDetails->str.pOleStr = (LPWSTR)SHAlloc(cchLen*SIZEOF(TCHAR));
|
|
if (lpDetails->str.pOleStr)
|
|
{
|
|
lstrcpyn(lpDetails->str.pOleStr,szTemp,cchLen);
|
|
lpDetails->str.uType = STRRET_OLESTR;
|
|
}
|
|
else
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
if (NET_FHasComment(pidn))
|
|
{
|
|
LPBYTE pb;
|
|
pb = pidn->szNetResName;
|
|
pb += lstrlenA((LPSTR)pb) + 1; // Skip over name;
|
|
if (NET_FHasProvider(pidn))
|
|
{
|
|
pb += lstrlenA((LPSTR)pb) + 1; // Skip over provider;
|
|
}
|
|
lpDetails->str.uOffset = pb - (LPBYTE)pidn;
|
|
lpDetails->str.uType = STRRET_OFFSET;
|
|
}
|
|
else
|
|
{
|
|
// Do nothing, return empty string
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lpDetails->str.cStr[0] = '\0';
|
|
lpDetails->str.uType = STRRET_CSTR;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CNETDetails_ColumnClick(IShellDetails * psd, UINT iColumn)
|
|
{
|
|
CNETDetails * this = IToClass(CNETDetails, SH32Unk.unk, psd);
|
|
|
|
if (iColumn >= ICOL_MAX)
|
|
{
|
|
return(E_NOTIMPL);
|
|
}
|
|
|
|
ShellFolderView_ReArrange(this->hwndMain, iColumn);
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
//
|
|
// To be called back from within CDefFolderMenu
|
|
//
|
|
HRESULT CALLBACK CNetwork_DFMCallBack(LPSHELLFOLDER psf, HWND hwndOwner,
|
|
LPDATAOBJECT pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
LPNETRES this;
|
|
|
|
psf = RegItems_GetInnerShellFolder(psf); // returns same vtbl if not a reg item
|
|
this = IToClass(CNetRes, sf, psf);
|
|
|
|
switch(uMsg)
|
|
{
|
|
case DFM_MERGECONTEXTMENU:
|
|
|
|
//
|
|
// This is from JoeB. We should treat all the menuitems (Format, Eject, ...)
|
|
// as verbs.
|
|
//
|
|
#if 0
|
|
if (!(wParam & CMF_VERBSONLY) && !(wParam & CMF_DVFILE))
|
|
#endif
|
|
{
|
|
LPQCMINFO pqcm = (LPQCMINFO)lParam;
|
|
if (pdtobj)
|
|
{
|
|
STGMEDIUM medium;
|
|
LPIDA pida;
|
|
UINT idCmdBase = pqcm->idCmdFirst; // must be called before merge
|
|
CDefFolderMenu_MergeMenu(HINST_THISDLL, POPUP_NETWORK_ITEM, 0, pqcm);
|
|
|
|
pida = DataObj_GetHIDA(pdtobj, &medium);
|
|
if (pida)
|
|
{
|
|
if (pida->cidl > 0)
|
|
{
|
|
LPIDNETRESOURCE pidn = (LPIDNETRESOURCE)IDA_GetIDListPtr(pida, 0);
|
|
|
|
// Only enable "connect" command if the first one is a share.
|
|
if (pidn)
|
|
{
|
|
ULONG rgf = 0;
|
|
if (NET_GetFlags(pidn) & SHID_JUNCTION)
|
|
{
|
|
EnableMenuItem(pqcm->hmenu, idCmdBase + FSIDM_CONNECT,
|
|
MF_CHECKED|MF_BYCOMMAND);
|
|
}
|
|
}
|
|
}
|
|
HIDA_ReleaseStgMedium(pida, &medium);
|
|
}
|
|
|
|
// BUGBUG: We should gray out the Properties selection if there
|
|
// are no property sheet pages. Messy to check... but default.
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DFM_GETHELPTEXT:
|
|
LoadStringA(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPSTR)lParam, HIWORD(wParam));
|
|
break;
|
|
|
|
case DFM_GETHELPTEXTW:
|
|
LoadStringW(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPWSTR)lParam, HIWORD(wParam));
|
|
break;
|
|
|
|
case DFM_INVOKECOMMAND:
|
|
switch(wParam)
|
|
{
|
|
case DFM_CMD_PROPERTIES:
|
|
|
|
hres = CNetwork_Properties(this, pdtobj, (LPCTSTR)lParam);
|
|
break;
|
|
|
|
case DFM_CMD_LINK:
|
|
if (psf->lpVtbl == &c_NetRootVtbl)
|
|
{
|
|
// net hood special case. in this case we want to create the shortuct
|
|
// in the net hood, not offer to put this on the desktop
|
|
|
|
LPSHELLFOLDER psf = CNetRoot_GetPSF(hwndOwner);
|
|
if (psf)
|
|
hres = FS_CreateLinks(hwndOwner, psf, pdtobj, (LPCTSTR)lParam);
|
|
else
|
|
hres = E_UNEXPECTED;
|
|
break;
|
|
}
|
|
else
|
|
hres = S_FALSE; // do the default shortcut crap
|
|
break;
|
|
|
|
case FSIDM_CONNECT:
|
|
if (pdtobj)
|
|
{
|
|
STGMEDIUM medium;
|
|
LPIDA pida = DataObj_GetHIDA(pdtobj, &medium);
|
|
if (pida)
|
|
{
|
|
UINT iidl;
|
|
for (iidl = 0; iidl < pida->cidl; iidl++)
|
|
{
|
|
LPIDNETRESOURCE pidn = (LPIDNETRESOURCE)IDA_GetIDListPtr(pida, iidl);
|
|
|
|
// Only execute "connect" on shares.
|
|
if (NET_GetFlags(pidn) & SHID_JUNCTION)
|
|
{
|
|
TCHAR szName[MAX_PATH];
|
|
LPTSTR pszName;
|
|
DWORD err;
|
|
pszName = NET_CopyResName(pidn,szName,ARRAYSIZE(szName));
|
|
err = SHStartNetConnectionDialog(hwndOwner,
|
|
pszName,
|
|
RESOURCETYPE_DISK);
|
|
DebugMsg(DM_TRACE, TEXT("sh TR - CNet FSIDM_CONNECT (%s, %x)"),
|
|
szName, err);
|
|
|
|
// events will get generated automatically
|
|
}
|
|
}
|
|
HIDA_ReleaseStgMedium(pida, &medium);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// This is one of view menu items, use the default code.
|
|
hres = S_FALSE;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
hres = E_NOTIMPL;
|
|
break;
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CALLBACK CNetwork_PrinterDFMCallBack(LPSHELLFOLDER psf, HWND hwndOwner,
|
|
LPDATAOBJECT pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
LPNETRES this;
|
|
|
|
psf = RegItems_GetInnerShellFolder(psf); // returns same vtbl if not a reg item
|
|
this = IToClass(CNetRes, sf, psf);
|
|
|
|
switch(uMsg)
|
|
{
|
|
case DFM_MERGECONTEXTMENU:
|
|
//
|
|
// Returning S_FALSE indicates no need to get verbs from
|
|
// extensions.
|
|
//
|
|
hres = S_FALSE;
|
|
break;
|
|
|
|
// if anyone hooks our context menu, we want to be on top (Open)
|
|
case DFM_MERGECONTEXTMENU_TOP:
|
|
if (pdtobj)
|
|
{
|
|
LPQCMINFO pqcm = (LPQCMINFO)lParam;
|
|
|
|
// insert verbs
|
|
CDefFolderMenu_MergeMenu(HINST_THISDLL, POPUP_NETWORK_PRINTER, 0, pqcm);
|
|
#ifndef WINNT
|
|
//
|
|
// WINNT does not support Capturing print ports, so no
|
|
// need to check.
|
|
//
|
|
if (!(GetSystemMetrics(SM_NETWORK) && RNC_NETWORKS))
|
|
{
|
|
// remove "map" if no net
|
|
DeleteMenu(pqcm->hmenu, pqcm->idCmdFirst + FSIDM_CONNECT_PRN, MF_BYCOMMAND);
|
|
}
|
|
#endif
|
|
SetMenuDefaultItem(pqcm->hmenu, 0, MF_BYPOSITION);
|
|
}
|
|
break;
|
|
|
|
case DFM_GETHELPTEXT:
|
|
LoadStringA(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPSTR)lParam, HIWORD(wParam));
|
|
break;
|
|
|
|
case DFM_GETHELPTEXTW:
|
|
LoadStringW(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPWSTR)lParam, HIWORD(wParam));
|
|
break;
|
|
|
|
case DFM_INVOKECOMMAND:
|
|
switch(wParam)
|
|
{
|
|
case DFM_CMD_PROPERTIES:
|
|
hres = CNetwork_Properties(this, pdtobj, (LPCTSTR)lParam);
|
|
break;
|
|
|
|
case DFM_CMD_LINK:
|
|
// do the default create shortcut crap
|
|
return S_FALSE;
|
|
|
|
case FSIDM_OPENPRN:
|
|
case FSIDM_NETPRN_INSTALL:
|
|
#ifndef WINNT
|
|
case FSIDM_CONNECT_PRN:
|
|
#endif
|
|
{
|
|
STGMEDIUM medium;
|
|
LPIDA pida = DataObj_GetHIDA(pdtobj, &medium);
|
|
if (pida)
|
|
{
|
|
UINT action, i;
|
|
|
|
// set up the operation we are going to perform
|
|
switch (wParam) {
|
|
case FSIDM_OPENPRN:
|
|
action = PRINTACTION_OPENNETPRN;
|
|
break;
|
|
case FSIDM_NETPRN_INSTALL:
|
|
action = PRINTACTION_NETINSTALL;
|
|
break;
|
|
default: // FSIDM_CONNECT_PRN
|
|
action = (UINT)-1;
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < pida->cidl; i++)
|
|
{
|
|
LPIDNETRESOURCE pidn = (LPIDNETRESOURCE)IDA_GetIDListPtr(pida, i);
|
|
|
|
// Only execute command for a net print share
|
|
if (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_SHARE
|
|
&& NET_GetType(pidn) == RESOURCETYPE_PRINT)
|
|
{
|
|
TCHAR szName[MAX_PATH];
|
|
NET_CopyResName(pidn,szName,ARRAYSIZE(szName));
|
|
|
|
#ifndef WINNT // PRINTQ
|
|
if (action == (UINT)-1)
|
|
{
|
|
SHNetConnectionDialog(hwndOwner,
|
|
szName, RESOURCETYPE_PRINT);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
Printers_DoCommand(hwndOwner, action,
|
|
szName, NULL);
|
|
}
|
|
}
|
|
} // for (i...
|
|
HIDA_ReleaseStgMedium(pida, &medium);
|
|
} // if (medium.hGlobal)
|
|
break;
|
|
} // case ID_NETWORK_PRINTER_INSTALL, FSIDM_CONNECT_PRN
|
|
|
|
} // switch(wparam)
|
|
break;
|
|
|
|
default:
|
|
hres = E_NOTIMPL;
|
|
break;
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// IDropTarget stuff (I guess we're subclassing the CPrintObjs IDropTarget)
|
|
//
|
|
|
|
//
|
|
// This is the entry of "drop thread"
|
|
//
|
|
DWORD WINAPI CPrintDropTarget_DropThreadInit(LPVOID pv)
|
|
{
|
|
LPPRNTHREADPARAM pthp = (LPPRNTHREADPARAM)pv;
|
|
LPCIDNETRESOURCE pidn = (LPCIDNETRESOURCE)pthp->pidl;
|
|
LPITEMIDLIST pidl;
|
|
TCHAR szName[MAX_PATH];
|
|
|
|
NET_CopyResName(pidn,szName,ARRAYSIZE(szName));
|
|
|
|
// we need to convert pthp->pidl from a network share to
|
|
// a printer driver connected to that network share
|
|
|
|
pidl = Printers_GetInstalledNetPrinter(szName);
|
|
if (!pidl)
|
|
{
|
|
LPCTSTR pTitle;
|
|
int i;
|
|
|
|
if (pthp->hwndOwner)
|
|
{
|
|
SetForegroundWindow(pthp->hwndOwner);
|
|
pTitle = NULL;
|
|
}
|
|
else
|
|
{
|
|
pTitle = MAKEINTRESOURCE(IDS_PRINTERS);
|
|
}
|
|
i = ShellMessageBox(HINST_THISDLL,
|
|
pthp->hwndOwner,
|
|
MAKEINTRESOURCE(IDS_INSTALLNETPRINTER), pTitle,
|
|
MB_YESNO|MB_ICONINFORMATION,
|
|
szName);
|
|
if (i == IDYES)
|
|
{
|
|
pidl = Printers_PrinterSetup(pthp->hwndOwner,
|
|
MSP_NETPRINTER, szName, NULL);
|
|
}
|
|
}
|
|
if (pidl)
|
|
{
|
|
ILFree(pthp->pidl);
|
|
pthp->pidl = pidl;
|
|
|
|
// now that pthp->pidl points to a printer driver,
|
|
// CPrintObjs can handle the rest
|
|
return CPrintObjs_DT_DropThreadInit(pv);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
STDMETHODIMP CPrintDropTarget_Drop(LPDROPTARGET pdt, LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
|
|
{
|
|
HRESULT hres = _CPrintObjs_DT_Drop(pdt, pDataObj, grfKeyState, pt, pdwEffect, CPrintDropTarget_DropThreadInit);
|
|
CIDLDropTarget_DragLeave(pdt);
|
|
return hres;
|
|
}
|
|
|
|
//
|
|
// CNetRootDropTarget::DragEnter
|
|
//
|
|
STDMETHODIMP CNetRootDropTarget_DragEnter(LPDROPTARGET pdropt, LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
|
|
{
|
|
LPIDLDROPTARGET this = IToClass(CIDLDropTarget, dropt, pdropt);
|
|
|
|
// let the base-class process it first.
|
|
CIDLDropTarget_DragEnter(pdropt, pDataObj, grfKeyState, pt, pdwEffect);
|
|
|
|
if ((this->dwData & (DTID_NETRES | DTID_HIDA)) == (DTID_NETRES | DTID_HIDA))
|
|
*pdwEffect &= DROPEFFECT_LINK;
|
|
else
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
this->dwEffectLastReturned = *pdwEffect;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CNetRootDropTarget_Drop(IDropTarget *pdropt, IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
|
|
{
|
|
HRESULT hres = S_OK;
|
|
LPIDLDROPTARGET this = IToClass(CIDLDropTarget, dropt, pdropt);
|
|
|
|
if ((this->dwData & (DTID_NETRES|DTID_HIDA)) == (DTID_NETRES|DTID_HIDA))
|
|
{
|
|
//
|
|
// Cache pdtgArg, if not yet cached.
|
|
//
|
|
if (!this->pdtgAgr)
|
|
{
|
|
LPSHELLFOLDER psf = CNetRoot_GetPSF(NULL);
|
|
if (psf) {
|
|
hres = psf->lpVtbl->CreateViewObject(psf, this->hwndOwner, &IID_IDropTarget, &this->pdtgAgr);
|
|
} else {
|
|
hres = E_INVALIDARG;
|
|
*pdwEffect = 0;
|
|
}
|
|
}
|
|
|
|
if (hres == S_OK)
|
|
{
|
|
// Only allow links in the nethood, not real objects.
|
|
*pdwEffect &= ~(DROPEFFECT_COPY | DROPEFFECT_MOVE);
|
|
|
|
//
|
|
// Note that we need to pass this->grfKeyStateLast so that Drop will
|
|
// use it to handle right-drag correctly with OLE.
|
|
//
|
|
hres = this->pdtgAgr->lpVtbl->DragEnter(this->pdtgAgr, pdtobj, this->grfKeyStateLast, pt, pdwEffect);
|
|
|
|
if (SUCCEEDED(hres) && *pdwEffect) {
|
|
hres = this->pdtgAgr->lpVtbl->Drop(this->pdtgAgr, pdtobj, grfKeyState, pt, pdwEffect);
|
|
} else {
|
|
this->pdtgAgr->lpVtbl->DragLeave(this->pdtgAgr);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pdwEffect = 0;
|
|
}
|
|
|
|
CIDLDropTarget_DragLeave(pdropt);
|
|
return hres;
|
|
}
|
|
|
|
IDropTargetVtbl c_CPrintDropTargetVtbl =
|
|
{
|
|
CIDLDropTarget_QueryInterface,
|
|
CIDLDropTarget_AddRef,
|
|
CIDLDropTarget_Release,
|
|
CPrintObjs_DT_DragEnter,
|
|
CIDLDropTarget_DragOver,
|
|
CIDLDropTarget_DragLeave,
|
|
CPrintDropTarget_Drop,
|
|
};
|
|
|
|
//
|
|
// This function opens a reg. database key based on the network provider type.
|
|
// The type is a number that is not localized, as opposed to the provider name
|
|
// which may be localized.
|
|
//
|
|
// Arguments:
|
|
// pidlAbs -- Absolute IDList to a network resource object.
|
|
//
|
|
// Returns: hkey
|
|
//
|
|
// Notes:
|
|
// The caller is responsible to close the key by calling RegCloseKey().
|
|
//
|
|
|
|
TCHAR const c_szNetworkType[] = TEXT("Network\\Type\\");
|
|
|
|
HKEY CNetwork_OpenProviderTypeKey(LPCITEMIDLIST pidlAbs)
|
|
{
|
|
HKEY hkeyProgID = NULL;
|
|
TCHAR szProvider[MAX_PATH];
|
|
LPTSTR psz;
|
|
DWORD err;
|
|
|
|
psz = NET_CopyProviderNameAbs(pidlAbs,szProvider,ARRAYSIZE(szProvider));
|
|
if (psz == NULL)
|
|
{
|
|
return NULL; // We will handle this later.
|
|
}
|
|
else
|
|
{
|
|
// Now that we've got the provider name, get the provider id.
|
|
DWORD dwType;
|
|
err = WNetGetProviderType(szProvider, &dwType);
|
|
if (err != WN_SUCCESS)
|
|
{
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
// convert nis.wNetType to a string, and then open the key
|
|
// HKEY_CLASSES_ROOT\Network\Type\<type string>
|
|
|
|
TCHAR szRegValue[MAX_PATH];
|
|
wsprintf(szRegValue, TEXT("%s%d"), c_szNetworkType, HIWORD(dwType));
|
|
SHRegOpenKey(HKEY_CLASSES_ROOT, szRegValue, &hkeyProgID);
|
|
}
|
|
}
|
|
return hkeyProgID;
|
|
}
|
|
|
|
//
|
|
// This function opens a reg. database key based on the "network provider".
|
|
// Because a space character is invalid, we converts it to '_' before
|
|
// calling SHRegOpenKey.
|
|
//
|
|
// Arguments:
|
|
// pidlAbs -- Absolute IDList to a network resource object.
|
|
//
|
|
// Returns: hkey
|
|
//
|
|
// Notes:
|
|
// The caller is responsibe to close the key by calling RegCloseKey().
|
|
//
|
|
HKEY CNetwork_OpenProviderKey(LPCITEMIDLIST pidlAbs)
|
|
{
|
|
HKEY hkeyProgID = NULL;
|
|
TCHAR szProvider[MAX_PATH];
|
|
LPTSTR psz;
|
|
|
|
psz = NET_CopyProviderNameAbs(pidlAbs,szProvider,ARRAYSIZE(szProvider));
|
|
|
|
if (psz == NULL)
|
|
{
|
|
return NULL; // We will handle this later.
|
|
}
|
|
else
|
|
{
|
|
// Replace all the space characters in the provider name with '_'.
|
|
for (psz=szProvider; NULL != (psz=StrChr(psz, TEXT(' '))); psz++) // DBCS safe
|
|
{
|
|
*psz = TEXT('_');
|
|
}
|
|
SHRegOpenKey(HKEY_CLASSES_ROOT, szProvider, &hkeyProgID);
|
|
}
|
|
return hkeyProgID;
|
|
}
|
|
|
|
BOOL CNetRoot_MakeStripToLikeKinds(UINT *pcidl, LPCITEMIDLIST **papidl, BOOL fNetObjects)
|
|
{
|
|
LPITEMIDLIST *apidl = (LPITEMIDLIST*)*papidl;
|
|
int cidl = *pcidl;
|
|
|
|
int iidl;
|
|
LPITEMIDLIST *apidlHomo;
|
|
int cpidlHomo;
|
|
|
|
for (iidl = 0; iidl < cidl; iidl++)
|
|
{
|
|
if (NET_IsValidID(apidl[iidl]) != fNetObjects)
|
|
{
|
|
apidlHomo = (LPITEMIDLIST *)LocalAlloc(LPTR, SIZEOF(LPITEMIDLIST) * cidl);
|
|
if (!apidlHomo)
|
|
return FALSE;
|
|
|
|
cpidlHomo = 0;
|
|
for (iidl = 0; iidl < cidl; iidl++)
|
|
{
|
|
if (NET_IsValidID(apidl[iidl]) == fNetObjects)
|
|
apidlHomo[cpidlHomo++] = apidl[iidl];
|
|
}
|
|
|
|
// Setup to use the stripped version of the pidl array...
|
|
*pcidl = cpidlHomo;
|
|
*papidl = apidlHomo;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
STDMETHODIMP CNetRoot_GetUIObjectOf(LPSHELLFOLDER psf, HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl,
|
|
REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
|
|
{
|
|
// BUGBUG: only pass through if cidl > 1 and objects are all of same type
|
|
HRESULT hres;
|
|
BOOL fStriped;
|
|
|
|
// Boy this is a load of horse dung...
|
|
// We want the commands to only deal with links and or network things but not both at the same
|
|
// time.
|
|
|
|
|
|
if ((cidl != 0) && NET_IsValidID(apidl[0]))
|
|
{
|
|
fStriped = CNetRoot_MakeStripToLikeKinds(&cidl, &apidl, TRUE);
|
|
hres = CNetwork_GetUIObjectOf(psf, hwndOwner, cidl, apidl, riid, prgfInOut, ppvOut );
|
|
}
|
|
else
|
|
{
|
|
fStriped = CNetRoot_MakeStripToLikeKinds(&cidl, &apidl, FALSE);
|
|
psf = CNetRoot_GetPSF(hwndOwner);
|
|
hres = psf->lpVtbl->GetUIObjectOf(psf, hwndOwner, cidl, apidl, riid, prgfInOut, ppvOut );
|
|
}
|
|
|
|
|
|
if (fStriped)
|
|
LocalFree((HLOCAL)apidl);
|
|
return hres;
|
|
|
|
}
|
|
|
|
STDMETHODIMP CNetwork_GetUIObjectOf(LPSHELLFOLDER psf, HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl,
|
|
REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
|
|
{
|
|
LPNETRES this = IToClass(CNetRes, sf, psf);
|
|
HRESULT hres = E_INVALIDARG;
|
|
|
|
if (IsEqualIID(riid, &IID_IExtractIcon)
|
|
#ifdef UNICODE
|
|
|| IsEqualIID(riid, &IID_IExtractIconA)
|
|
#endif
|
|
)
|
|
{
|
|
if (( cidl==1 ) && ( NET_IsValidID(apidl[0]) ) )
|
|
{
|
|
LPIDNETRESOURCE pidnRel = (LPIDNETRESOURCE)apidl[0];
|
|
UINT iIndex = SILGetIconIndex(apidl[0], c_aicmpNet, ARRAYSIZE(c_aicmpNet));
|
|
|
|
//
|
|
// We need treat shares slightly different, because the display
|
|
// type is not sufficient to get the icon index.
|
|
//
|
|
if (NET_GetDisplayType(pidnRel) == RESOURCEDISPLAYTYPE_SHARE
|
|
&& NET_GetType(pidnRel) == RESOURCETYPE_PRINT)
|
|
{
|
|
iIndex = (UINT)EIRESID(IDI_PRINTER_NET);
|
|
}
|
|
|
|
// If this is the Remote Services, get its special icon
|
|
//
|
|
if (NET_IsRemoteFld(pidnRel))
|
|
{
|
|
iIndex = II_RNA;
|
|
}
|
|
|
|
hres = SHCreateDefExtIcon(NULL, // this DLL
|
|
iIndex, // normal icon
|
|
iIndex, // open icon (same)
|
|
GIL_PERCLASS, // meaningless
|
|
(LPEXTRACTICON *)ppvOut);
|
|
#ifdef UNICODE
|
|
if (SUCCEEDED(hres) && IsEqualIID(riid, &IID_IExtractIconA))
|
|
{
|
|
LPEXTRACTICON pxicon = *ppvOut;
|
|
hres = pxicon->lpVtbl->QueryInterface(pxicon,riid,ppvOut);
|
|
pxicon->lpVtbl->Release(pxicon);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else if (IsEqualIID(riid, &IID_IContextMenu))
|
|
{
|
|
HKEY hkeyBaseProgID = NULL;
|
|
HKEY hkeyProgID = NULL;
|
|
|
|
if (!cidl)
|
|
{
|
|
hres = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
HKEY ahkeys[4];
|
|
|
|
hres = Net_OpenKeys(ahkeys, this->pidl, apidl[0]);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
LPFNDFMCALLBACK fnDFMCB = CNetwork_DFMCallBack;
|
|
LPIDNETRESOURCE pidnRel = (LPIDNETRESOURCE)apidl[0];
|
|
|
|
if (NET_GetDisplayType(pidnRel) == RESOURCEDISPLAYTYPE_SHARE
|
|
&& NET_GetType(pidnRel) == RESOURCETYPE_PRINT)
|
|
{
|
|
// a printer is selected (dont inherit from "Folder")
|
|
fnDFMCB = CNetwork_PrinterDFMCallBack;
|
|
SHRegCloseKey(ahkeys[NET_KEY_FOLDER]);
|
|
ahkeys[NET_KEY_FOLDER] = NULL;
|
|
}
|
|
|
|
hres = CDefFolderMenu_Create2(this->pidl, hwndOwner,
|
|
cidl, apidl, this->psf, fnDFMCB, ARRAYSIZE(ahkeys), ahkeys,
|
|
(LPCONTEXTMENU *)ppvOut);
|
|
|
|
SHRegCloseKeys(ahkeys, ARRAYSIZE(ahkeys));
|
|
}
|
|
else
|
|
{
|
|
hres = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
}
|
|
else if (cidl>0 && IsEqualIID(riid, &IID_IDataObject))
|
|
{
|
|
// Point & Print printer installation assumes that the
|
|
// netresources from CNETIDLData_GetData and the
|
|
// pidls from CIDLData_GetData are in the same order.
|
|
// Keep it this way.
|
|
|
|
hres = CIDLData_CreateFromIDArray2(&c_CNETIDLDataVtbl,
|
|
this->pidl, cidl, apidl,
|
|
(LPDATAOBJECT *)ppvOut);
|
|
}
|
|
else if (cidl==1 && IsEqualIID(riid, &IID_IDropTarget))
|
|
{
|
|
LPIDNETRESOURCE pidn = (LPIDNETRESOURCE)apidl[0];
|
|
|
|
if (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_SHARE
|
|
&& NET_GetType(pidn) == RESOURCETYPE_PRINT)
|
|
{
|
|
hres = CIDLDropTarget_Create(hwndOwner, &c_CPrintDropTargetVtbl,
|
|
(LPITEMIDLIST)pidn, (LPDROPTARGET *)ppvOut);
|
|
}
|
|
else if (NET_GetFlags(pidn) & SHID_JUNCTION)
|
|
{
|
|
LPSHELLFOLDER psfT;
|
|
hres = CNetwork_BindToObject(psf, apidl[0], NULL, &IID_IShellFolder, &psfT);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = psfT->lpVtbl->CreateViewObject(psfT, hwndOwner, &IID_IDropTarget, ppvOut);
|
|
psfT->lpVtbl->Release(psfT);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
//
|
|
// CNetwork::GetFormatName (Non virtual function)
|
|
//
|
|
// This function retrieves the formatted name of the specified network object.
|
|
//
|
|
LPCTSTR CNetwork_GetFormatName(LPNETRES this, LPCIDNETRESOURCE pidn, LPSTRRET pStrRet)
|
|
{
|
|
LPCTSTR pszRet;
|
|
LPTSTR pszTemp;
|
|
LPTSTR pszProvider;
|
|
TCHAR szName[MAX_PATH];
|
|
UINT cchName;
|
|
|
|
// Assume we return the remote name as the display name
|
|
pStrRet->uType = STRRET_OFFSET;
|
|
pStrRet->uOffset = NET_DISPLAYNAMEOFFSET;
|
|
|
|
NET_CopyResName(pidn,szName,ARRAYSIZE(szName));
|
|
pszTemp = szName;
|
|
cchName = lstrlen(szName) + 1;
|
|
|
|
if ((NET_GetDisplayType(pidn) != RESOURCEDISPLAYTYPE_ROOT)
|
|
&& (NET_GetDisplayType(pidn) != RESOURCEDISPLAYTYPE_NETWORK))
|
|
{
|
|
TCHAR szDisplayName[MAX_PATH];
|
|
TCHAR szProvider[MAX_PATH];
|
|
DWORD bSize = ARRAYSIZE(szDisplayName);
|
|
|
|
pszProvider = NET_CopyProviderNameAbs(this->pidl,
|
|
szProvider,
|
|
ARRAYSIZE(szProvider));
|
|
|
|
// There are some containers whoe are a composit of multiple
|
|
// providers so in this case which the above returns NULL, see
|
|
// if the item has in incoded...
|
|
if (pszProvider == NULL)
|
|
pszProvider = NET_CopyProviderNameRelative((LPITEMIDLIST)pidn,
|
|
szProvider,
|
|
ARRAYSIZE(szProvider));
|
|
|
|
if (WNetFormatNetworkName(pszProvider,
|
|
szName,
|
|
szDisplayName, &bSize,
|
|
#ifdef WINNT
|
|
// Win95 net providers improperly implement spec, and shell does too
|
|
WNFMT_ABBREVIATED |
|
|
#endif // WINNT
|
|
WNFMT_INENUM, 8+1+3) == WN_SUCCESS)
|
|
{
|
|
// Check if the ID contains the display name (usually does)
|
|
int iDiff = (cchName - 1) - lstrlen(szDisplayName);
|
|
if (iDiff > 0 && lstrcmpi(szName + iDiff, szDisplayName) == 0)
|
|
#ifdef UNICODE
|
|
{
|
|
|
|
//
|
|
// Copy only the last bit of the name
|
|
//
|
|
pszTemp += iDiff;
|
|
cchName -= iDiff;
|
|
}
|
|
else
|
|
{
|
|
pszTemp = szDisplayName;
|
|
cchName = lstrlen(szDisplayName)+1;
|
|
}
|
|
#else
|
|
{
|
|
pStrRet->uOffset += iDiff;
|
|
pszRet = pidn->szNetResName + iDiff;
|
|
}
|
|
else
|
|
{
|
|
pStrRet->uType = STRRET_CSTR;
|
|
lstrcpy(pStrRet->cStr, szDisplayName);
|
|
pszRet = pStrRet->cStr;
|
|
}
|
|
return pszRet;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
pszRet = pStrRet->pOleStr = (LPWSTR)SHAlloc(cchName*SIZEOF(TCHAR));
|
|
if (!pStrRet->pOleStr)
|
|
{
|
|
return NULL;
|
|
}
|
|
lstrcpyn(pStrRet->pOleStr,pszTemp,cchName);
|
|
pStrRet->uType = STRRET_OLESTR;
|
|
#else
|
|
pszRet = pidn->szNetResName;
|
|
#endif
|
|
|
|
return pszRet;
|
|
}
|
|
|
|
STDMETHODIMP CNetRoot_GetDisplayNameOf(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, DWORD dwGDNFlags, LPSTRRET pStrRet)
|
|
{
|
|
if (pidl == NULL || ILIsEmpty(pidl) || !NET_IsValidID(pidl))
|
|
{
|
|
psf = CNetRoot_GetPSF(NULL);
|
|
return psf->lpVtbl->GetDisplayNameOf(psf, pidl, dwGDNFlags, pStrRet);
|
|
}
|
|
|
|
return CNetwork_GetDisplayNameOf(psf, pidl, dwGDNFlags, pStrRet);
|
|
}
|
|
|
|
STDMETHODIMP CNetwork_GetDisplayNameOf(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, DWORD dwGDNFlags, LPSTRRET pStrRet)
|
|
{
|
|
LPNETRES this = IToClass(CNetRes, sf, psf);
|
|
HRESULT hres = E_INVALIDARG;
|
|
if (NET_IsValidID(pidl))
|
|
{
|
|
LPCIDNETRESOURCE pidn = (LPCIDNETRESOURCE)pidl;
|
|
if (dwGDNFlags & SHGDN_FORPARSING)
|
|
{
|
|
if (!(dwGDNFlags & SHGDN_INFOLDER))
|
|
{
|
|
hres = SHGetPathHelper(this->pidl, pidl, pStrRet);
|
|
if (FAILED(hres) && hres!=E_OUTOFMEMORY) {
|
|
hres = E_NOTIMPL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We don't support parsing.
|
|
hres = E_NOTIMPL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hres = S_OK; // assume success
|
|
if (ILIsEmpty(_ILNext(pidl)))
|
|
{
|
|
CNetwork_GetFormatName(this, pidn, pStrRet);
|
|
}
|
|
else
|
|
{
|
|
LPCTSTR pszName, pszTemplate;
|
|
STRRET StrRetT;
|
|
|
|
if (NET_GetFlags(pidn) & SHID_JUNCTION)
|
|
{
|
|
pszName = CNetwork_GetFormatName(this, pidn, &StrRetT);
|
|
#ifndef UNICODE
|
|
Assert(StrRetT.uType != STRRET_OLESTR);
|
|
#endif
|
|
pszTemplate = MAKEINTRESOURCE(IDS_DSPTEMPLATE_WITH_BACKSLASH);
|
|
}
|
|
else
|
|
{
|
|
// No full path for network resources.
|
|
pszName = c_szNULL;
|
|
pszTemplate = NULL;
|
|
}
|
|
|
|
//
|
|
// Then, append the rest and put it in pStrRet.
|
|
//
|
|
hres = ILGetRelDisplayName(psf, pStrRet, pidl, pszName, pszTemplate);
|
|
#ifdef UNICODE
|
|
if (StrRetT.uType == STRRET_OLESTR)
|
|
SHFree(StrRetT.pOleStr);
|
|
#endif
|
|
|
|
}
|
|
|
|
// If junction is child of Hood - don;t prettify name, no sense
|
|
if (!(dwGDNFlags & SHGDN_INFOLDER) &&
|
|
(!ILIsEqual(this->pidl, GetSpecialFolderIDList(NULL, CSIDL_NETWORK, FALSE))) &&
|
|
(NET_GetFlags(pidn) & SHID_JUNCTION) )
|
|
{
|
|
extern void StrRetFormat(LPSTRRET pSTRRET, LPCITEMIDLIST pidlRel,
|
|
LPCTSTR pszTemplate, LPCTSTR pszAdd);
|
|
|
|
// Generate "user on foo" for "pyrex\user"
|
|
STRRET StrRetT;
|
|
LPCIDNETRESOURCE pidnParent;
|
|
LPCTSTR pszParent;
|
|
pidnParent = (LPCIDNETRESOURCE)ILFindLastID(this->pidl);
|
|
NET_IsValidID((LPCITEMIDLIST)pidnParent);
|
|
pszParent = CNetwork_GetFormatName(this, pidnParent, &StrRetT);
|
|
#ifndef UNICODE
|
|
Assert(StrRetT.uType != STRRET_OLESTR);
|
|
#endif
|
|
StrRetFormat(pStrRet, pidl, MAKEINTRESOURCE(IDS_DSPTEMPLATE_WITH_ON), pszParent);
|
|
#ifdef UNICODE
|
|
if (StrRetT.uType == STRRET_OLESTR)
|
|
SHFree(StrRetT.pOleStr);
|
|
#endif
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
STDMETHODIMP CNetRoot_SetNameOf(LPSHELLFOLDER psf, HWND hwndOwner,
|
|
LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD dwReserved, LPITEMIDLIST * ppidlOut)
|
|
{
|
|
if ((pidl == NULL) || ILIsEmpty(pidl) || !NET_IsValidID(pidl))
|
|
{
|
|
psf = CNetRoot_GetPSF(hwndOwner);
|
|
return psf->lpVtbl->SetNameOf(psf,hwndOwner, pidl, lpszName, dwReserved, ppidlOut);
|
|
}
|
|
|
|
return CNetwork_SetNameOf(psf,hwndOwner, pidl, lpszName, dwReserved, ppidlOut);
|
|
}
|
|
|
|
STDMETHODIMP CNetwork_SetNameOf(LPSHELLFOLDER psf, HWND hwndOwner,
|
|
LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD dwReserved, LPITEMIDLIST * ppidlOut)
|
|
{
|
|
if (ppidlOut) {
|
|
*ppidlOut = NULL;
|
|
}
|
|
|
|
return E_NOTIMPL; // not supported
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
// Network related helper functions
|
|
//===========================================================================
|
|
|
|
//
|
|
// Arguments:
|
|
// pszPath -- "\\*\*\...", fUNC==TRUE; "X:...", fUNC=FALSE
|
|
//
|
|
HANDLE _RetryNetwork(HWND hwndOwner, LPCTSTR pszPath, WIN32_FIND_DATA * pfinddata,
|
|
BOOL fUNC, BOOL* pfIsNet)
|
|
{
|
|
HANDLE hfile = INVALID_HANDLE_VALUE;
|
|
DWORD err;
|
|
TCHAR szT[MAX_PATH];
|
|
|
|
if (fUNC)
|
|
{
|
|
//
|
|
// We need to initialize all the valiables to help MPR marshalling it.
|
|
//
|
|
NETRESOURCE rc = { 0, RESOURCETYPE_ANY, 0, 0, NULL, szT, NULL, NULL} ;
|
|
|
|
lstrcpy(szT, pszPath);
|
|
PathStripToRoot(szT);
|
|
|
|
// We'll hit this assert, if somebody change the NETRESOURCE definition.
|
|
Assert(rc.lpRemoteName == szT);
|
|
Assert(rc.dwType == RESOURCETYPE_ANY);
|
|
|
|
err = WNetAddConnection3(hwndOwner, &rc, NULL, NULL, CONNECT_TEMPORARY | CONNECT_INTERACTIVE);
|
|
}
|
|
else
|
|
{
|
|
TCHAR szDrive[4];
|
|
|
|
szDrive[0] = pszPath[0];
|
|
szDrive[1] = TEXT(':');
|
|
szDrive[2] = TEXT('\0');
|
|
|
|
//
|
|
// Notes: This API will popup an error dialog box!
|
|
//
|
|
|
|
err = WNetRestoreConnection(hwndOwner, szDrive);
|
|
|
|
if (err == WN_SUCCESS)
|
|
{
|
|
// We should let the windows know that the New drive has
|
|
// arrived. This may not be necessary
|
|
szDrive[2] = TEXT('\\');
|
|
szDrive[3] = TEXT('\0');
|
|
|
|
// Make sure our knowledge about it being not avail is blown away
|
|
InvalidateDriveType(DRIVEID(szDrive));
|
|
SHChangeNotify(SHCNE_DRIVEADD, SHCNF_PATH, szDrive, NULL);
|
|
}
|
|
else if (err != ERROR_OUTOFMEMORY)
|
|
{
|
|
//
|
|
// NOTES: We need to translate all but OUTOFMEMORY error
|
|
// into WN_CANCEL here to avoid popping up another
|
|
// error message box from the shell. Ask LenS for detail.
|
|
// We must return ERROR_OUTOFMEMORY as-is to fallback
|
|
// nicely.
|
|
//
|
|
// (SatoNa)
|
|
//
|
|
err = WN_CANCEL;
|
|
}
|
|
}
|
|
|
|
DebugMsg(DM_TRACE, TEXT("_RetryNetwork - TRACE: WNetXXX returned (%lx)"), err);
|
|
#ifdef DEBUG
|
|
if (err == ERROR_EXTENDED_ERROR)
|
|
{
|
|
DWORD dwError;
|
|
TCHAR szErrorBuf[80];
|
|
TCHAR szNameBuf[80];
|
|
WNetGetLastError(&dwError, szErrorBuf, ARRAYSIZE(szErrorBuf),
|
|
szNameBuf, ARRAYSIZE(szNameBuf));
|
|
DebugMsg(DM_TRACE, TEXT("_Retry Net extended error(%lx), %s(%s)"),
|
|
dwError, szErrorBuf, szNameBuf);
|
|
}
|
|
#endif
|
|
|
|
if (err == WN_SUCCESS)
|
|
{
|
|
hfile = FindFirstFile(pszPath, pfinddata);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Signal outer level code that one of WNet API failed.
|
|
//
|
|
*pfIsNet = TRUE;
|
|
|
|
// signal outer level code that this was a user "cancel" operation
|
|
// (ie, don't continue to search/expand, etc)
|
|
|
|
SetLastError(err); // WN_ error code
|
|
}
|
|
|
|
return hfile;
|
|
}
|
|
|
|
//
|
|
// This function calls Dos/FindFirstFile. If it fails and the path name
|
|
// is UNC name (or redirected drive - not implemented yet), it calls
|
|
// WNetAddConnection3() to establish the connection. Then, it calls
|
|
// Dos/FindFirstFIle again.
|
|
//
|
|
// History:
|
|
// 06-12-93 SatoNa Created
|
|
//
|
|
HANDLE FindFirstFileRetry(HWND hwnd, LPCTSTR pszPath, WIN32_FIND_DATA * pfinddata, BOOL * pfIsNet)
|
|
{
|
|
BOOL fIsNet = FALSE;
|
|
HANDLE hfind = FindFirstFile(pszPath, pfinddata);
|
|
|
|
if (hfind == INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD err = GetLastError();
|
|
|
|
switch (err) {
|
|
case ERROR_NO_MORE_FILES: // what dos returns
|
|
case ERROR_FILE_NOT_FOUND: // win32 compatible
|
|
// an empty folder (probalby a root), this is cool
|
|
break;
|
|
|
|
default:
|
|
DebugMsg(DM_TRACE, TEXT("FindFirstFileRetry - TRACE: FindFirst failed (%lx, %s)"), err, pszPath);
|
|
|
|
if (PathIsUNC(pszPath))
|
|
{
|
|
hfind = _RetryNetwork(hwnd, pszPath, pfinddata, TRUE, &fIsNet);
|
|
}
|
|
else if (IsNetDrive(DRIVEID(pszPath))==2)
|
|
{
|
|
hfind = _RetryNetwork(hwnd, pszPath, pfinddata, FALSE, &fIsNet);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We need to set the original error, because IsNetDrive
|
|
// might have changed the error code.
|
|
//
|
|
SetLastError(err);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pfIsNet)
|
|
*pfIsNet = fIsNet;
|
|
|
|
return hfind;
|
|
}
|
|
|
|
//
|
|
// Get the path to the specified file system object.
|
|
//
|
|
// Parameters:
|
|
// pidlRel -- Specifies the relative IDList to the file system object
|
|
// pszPath -- Specifies the string buffer (MAX_PATH)
|
|
//
|
|
BOOL NET_GetPathFromIDList(LPCITEMIDLIST pidlRel, LPTSTR pszPath, UINT uOpts)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
// First, find the junction point, which is a share point.
|
|
// REVIVEW: We might be able to use SILFindJunctionNext
|
|
//
|
|
LPCITEMIDLIST pidlT;
|
|
LPCITEMIDLIST pidlLast = NULL;
|
|
|
|
for (pidlT=pidlRel; !ILIsEmpty(pidlT) ; pidlT=_ILNext(pidlT))
|
|
{
|
|
if (SIL_GetType(pidlT) & SHID_JUNCTION)
|
|
{
|
|
// We found the junction point (i.e., share)
|
|
// First, get the UNC name (e.g., "\\pyrex\user")
|
|
//
|
|
// Check if we have resolved UNC name for this resource.
|
|
// Original name could be non-UNC but when binding to this point
|
|
// we could possible resolve it.
|
|
_CNetwork_JunctionToFSPath((LPCIDNETRESOURCE)pidlT, pszPath);
|
|
|
|
//
|
|
// BUGBUG: Chris, you put this if statement above the lstrcpy and
|
|
// it broke the New->Printer wizard. Although I'm no sure why you
|
|
// put this if statement, I'm moving down here to fix that wizard
|
|
// bug. I also verified that this change won't break the change
|
|
// you made to links to a network printer (which you mentioned in
|
|
// the comment). --- Satona, 16-Dec-94
|
|
//
|
|
|
|
/* BUGBUG: In forcing this to be a RESOURCETYPE_DISK it breaks the
|
|
/ expansion of simple ID lists, as these fill in the type to
|
|
/ be RESOURCETYPE_ANY, therefore I am adding another check to see
|
|
/ if it matches either RESOURCETYPE_ANY or DISK. daviddv 2/18/96. */
|
|
|
|
if (NET_GetType((LPCIDNETRESOURCE)pidlT) == RESOURCETYPE_DISK ||
|
|
NET_GetType((LPCIDNETRESOURCE)pidlT) == RESOURCETYPE_ANY )
|
|
{
|
|
// Then, combine the rest - This will fail if this exceeds path limits...
|
|
fSuccess = FSFolder_CombinePath(_ILNext(pidlT), pszPath, uOpts & GPFIDL_ALTNAME);
|
|
}
|
|
else
|
|
fSuccess = TRUE;
|
|
|
|
break;
|
|
}
|
|
pidlLast = pidlT;
|
|
}
|
|
if (!fSuccess && (uOpts & GPFIDL_NONFSNAME) && pidlLast)
|
|
{
|
|
// see if this is a network server pidl...
|
|
|
|
if ((SIL_GetType(pidlLast) & (SHID_INGROUPMASK | SHID_NET)) ==
|
|
SHID_NET_SERVER)
|
|
{
|
|
NET_CopyResName((LPIDNETRESOURCE)pidlLast,pszPath,MAX_PATH);
|
|
fSuccess = TRUE;
|
|
}
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Get the provider name from a relative IDLIST.
|
|
// Parameters:
|
|
// pidlRelative -- Specifies the relative IDList to the network object
|
|
//
|
|
LPTSTR NET_CopyProviderNameRelative(LPCITEMIDLIST pidlRelative, LPTSTR pszBuffer, UINT cchBuffer )
|
|
{
|
|
LPIDNETRESOURCE pidn = (LPIDNETRESOURCE)pidlRelative;
|
|
VDATEINPUTBUF(pszBuffer, TCHAR, cchBuffer);
|
|
|
|
// If this guy is the REST of network item, we increment to the
|
|
// next IDLIST - If at root return NULL
|
|
if (pidn->cb == 0)
|
|
return(NULL);
|
|
|
|
//
|
|
// If the IDLIST starts with a ROOT_REGITEM, then skip to the
|
|
// next item in the list...
|
|
if (pidn->bFlags == SHID_ROOT_REGITEM)
|
|
{
|
|
pidn = (LPIDNETRESOURCE)_ILNext((LPITEMIDLIST)pidn);
|
|
if (pidn->cb == 0)
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// If the IDLIST includes Entire Network, the provider will be
|
|
// part of the next component.
|
|
if (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_ROOT)
|
|
{
|
|
pidn = (LPIDNETRESOURCE)_ILNext((LPITEMIDLIST)pidn);
|
|
if (pidn->cb == 0)
|
|
return NULL;
|
|
}
|
|
|
|
// If the next component after the 'hood or Entire Network is
|
|
// a network object, its name is the provider name, else the
|
|
// provider name comes after the remote name.
|
|
if (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_NETWORK)
|
|
{
|
|
// Simply return the name field back for the item.
|
|
return NET_CopyResName(pidn,pszBuffer,cchBuffer);
|
|
}
|
|
else
|
|
{
|
|
// Nope one of the items in the neighborhood view was selected
|
|
// The Provider name is stored after ther resource name
|
|
return NET_CopyProviderName(pidn,pszBuffer,cchBuffer);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the provider name from an absolute IDLIST.
|
|
// Parameters:
|
|
// pidlAbs -- Specifies the Absolute IDList to the file system object
|
|
//
|
|
LPTSTR NET_CopyProviderNameAbs(LPCITEMIDLIST pidlAbs, LPTSTR pszBuff, UINT cchBuff)
|
|
{
|
|
// No VDATEINPUTBUF here... let CorpProviderNameRelative worry about it
|
|
|
|
return NET_CopyProviderNameRelative(_ILNext(pidlAbs),pszBuff,cchBuff);
|
|
}
|
|
|
|
//
|
|
// Return the pointer to the comment field if the network id node or
|
|
// null string (actually last null char of display name if not.
|
|
// Parameters:
|
|
// pidlAbs -- Specifies the Absolute IDList to the file system object
|
|
//
|
|
LPTSTR NET_CopyComment(LPIDNETRESOURCE pidn, LPTSTR pszBuff, UINT cchBuff)
|
|
{
|
|
LPSTR pszT;
|
|
VDATEINPUTBUF(pszBuff, TCHAR, cchBuff);
|
|
|
|
pszBuff[0] = TEXT('\0');
|
|
|
|
pszT = pidn->szNetResName + lstrlenA(pidn->szNetResName)+1;
|
|
if (NET_FHasComment(pidn))
|
|
{
|
|
if (NET_FHasProvider(pidn))
|
|
pszT += lstrlenA(pszT) + 1;
|
|
#ifdef UNICODE
|
|
if (NET_IsUnicode(pidn))
|
|
{
|
|
pszT += lstrlenA(pszT) + 1; // Skip Ansi comment
|
|
pszT += (ualstrlen((LPNWSTR)pszT) + 1) * SIZEOF(TCHAR); // Skip Unicode Name
|
|
if (NET_FHasProvider(pidn))
|
|
pszT += (ualstrlen((LPNWSTR)pszT) + 1) * SIZEOF(TCHAR); // Skip Unicode Provider
|
|
ualstrcpyn(pszBuff,(LPNWSTR)pszT,cchBuff);
|
|
}
|
|
else
|
|
{
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
pszT, -1,
|
|
pszBuff, cchBuff);
|
|
}
|
|
#else
|
|
lstrcpyn(pszBuff,pszT,cchBuff);
|
|
#endif
|
|
}
|
|
|
|
return(pszBuff);
|
|
}
|
|
|
|
//===========================================================================
|
|
// HNRES related stuff
|
|
//===========================================================================
|
|
|
|
//
|
|
// Converts an offset to a string to a string pointer.
|
|
//
|
|
LPCTSTR _Offset2Ptr(LPTSTR pszBase, UINT offset, UINT * pcb)
|
|
{
|
|
LPTSTR pszRet;
|
|
if (offset==0) {
|
|
pszRet = NULL;
|
|
*pcb = 0;
|
|
} else {
|
|
pszRet = (LPTSTR)((LPBYTE)pszBase + offset);
|
|
*pcb = (lstrlen(pszRet) + 1) * SIZEOF(TCHAR);
|
|
}
|
|
return pszRet;
|
|
}
|
|
|
|
//
|
|
// pmedium == NULL if we are handling QueryGetData
|
|
//
|
|
HRESULT CNETIDLData_GetHDrop(IDataObject *pdtobj, LPSTGMEDIUM pmedium)
|
|
{
|
|
STGMEDIUM medium = { 0, NULL, NULL };
|
|
HRESULT hres = E_INVALIDARG; // assume error
|
|
LPIDA pida = DataObj_GetHIDA(pdtobj, &medium);
|
|
if (pida)
|
|
{
|
|
// Get the first one to see the type.
|
|
LPCIDNETRESOURCE pidn = (LPCIDNETRESOURCE)IDA_GetIDListPtr(pida, 0);
|
|
|
|
if ((NET_GetFlags(pidn) & SHID_JUNCTION)
|
|
&& (NET_GetType(pidn) == RESOURCETYPE_DISK))
|
|
{
|
|
//
|
|
// Get HDrop only if we are handling IDataObject::GetData
|
|
//
|
|
extern HRESULT CFSIDLData_GetHDrop(IDataObject *pdtobj, LPSTGMEDIUM pmedium, BOOL fAltName);
|
|
hres = pmedium ? CFSIDLData_GetHDrop(pdtobj, pmedium, FALSE) : S_OK;
|
|
}
|
|
|
|
HIDA_ReleaseStgMedium(pida, &medium);
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
//
|
|
// pmedium == NULL if we are handling QueryGetData
|
|
//
|
|
HRESULT CNETIDLData_GetNetResource(IDataObject *pdtobj, STGMEDIUM *pmedium)
|
|
{
|
|
HRESULT hres = E_OUTOFMEMORY;
|
|
LPITEMIDLIST pidl;
|
|
STGMEDIUM medium;
|
|
LPIDA pida = DataObj_GetHIDA(pdtobj, &medium);
|
|
|
|
Assert(pida && pida->cidl);
|
|
|
|
// First, get the provider name from the first one (assuming they are common).
|
|
pidl = IDA_ILClone(pida, 0);
|
|
if (pidl)
|
|
{
|
|
TCHAR szProvider[MAX_PATH];
|
|
LPCTSTR pszProvider = NET_CopyProviderNameAbs(pidl,
|
|
szProvider,
|
|
ARRAYSIZE(szProvider));
|
|
if (pmedium)
|
|
{
|
|
TCHAR szName[MAX_PATH];
|
|
UINT cbHeader = SIZEOF(NRESARRAY) - SIZEOF(NETRESOURCE) + SIZEOF(NETRESOURCE) * pida->cidl;
|
|
UINT cbRequired;
|
|
UINT iItem;
|
|
|
|
// Calculate required size
|
|
cbRequired = cbHeader;
|
|
if (pszProvider)
|
|
{
|
|
cbRequired+= lstrlen(pszProvider) * SIZEOF(TCHAR) + SIZEOF(TCHAR);
|
|
}
|
|
|
|
for (iItem = 0; iItem < pida->cidl; iItem++)
|
|
{
|
|
LPCIDNETRESOURCE pidn = (LPCIDNETRESOURCE)IDA_GetIDListPtr(pida, iItem);
|
|
NET_CopyResName(pidn,szName,ARRAYSIZE(szName));
|
|
cbRequired += lstrlen(szName) * SIZEOF(TCHAR) + SIZEOF(TCHAR);
|
|
}
|
|
|
|
//
|
|
// Indicate that the caller should release hmem.
|
|
//
|
|
pmedium->pUnkForRelease = NULL;
|
|
pmedium->tymed = TYMED_HGLOBAL;
|
|
pmedium->hGlobal = GlobalAlloc(GPTR, cbRequired);
|
|
if (pmedium->hGlobal)
|
|
{
|
|
LPNRESARRAY panr = (LPNRESARRAY)pmedium->hGlobal;
|
|
LPTSTR pszT = (LPTSTR)((LPBYTE)panr + cbHeader);
|
|
UINT offProvider = 0;
|
|
|
|
panr->cItems = pida->cidl;
|
|
|
|
// Copy the provider name. This is not necessary,
|
|
// if we are dragging providers.
|
|
if (pszProvider)
|
|
{
|
|
lstrcpy(pszT, pszProvider);
|
|
offProvider = PTROFFSET(panr, pszT);
|
|
pszT += lstrlen(pszT) + 1;
|
|
}
|
|
|
|
//
|
|
// For each item, fill each NETRESOURCE and append resource
|
|
// name at the end. Note that we should put offsets in
|
|
// lpProvider and lpRemoteName.
|
|
//
|
|
for (iItem = 0; iItem < pida->cidl; iItem++)
|
|
{
|
|
LPNETRESOURCE pnr = &panr->nr[iItem];
|
|
LPCIDNETRESOURCE pidn = (LPCIDNETRESOURCE)IDA_GetIDListPtr(pida, iItem);
|
|
|
|
Assert(pnr->dwScope == 0);
|
|
Assert(pnr->lpLocalName==NULL);
|
|
Assert(pnr->lpComment==NULL);
|
|
|
|
pnr->dwType = NET_GetType(pidn);
|
|
pnr->dwDisplayType = NET_GetDisplayType(pidn);
|
|
pnr->dwUsage = NET_GetUsage(pidn);
|
|
NET_CopyResName(pidn,pszT,MAX_PATH);
|
|
|
|
if (pnr->dwDisplayType == RESOURCEDISPLAYTYPE_ROOT)
|
|
{
|
|
pnr->lpProvider = NULL;
|
|
pnr->lpRemoteName = NULL;
|
|
}
|
|
else
|
|
if (pnr->dwDisplayType == RESOURCEDISPLAYTYPE_NETWORK)
|
|
{
|
|
*((UINT *) &pnr->lpProvider) = PTROFFSET(panr, pszT);
|
|
Assert(pnr->lpRemoteName == NULL);
|
|
}
|
|
else
|
|
{
|
|
*((UINT *) &pnr->lpProvider) = offProvider;
|
|
*((UINT *) &pnr->lpRemoteName) = PTROFFSET(panr, pszT);
|
|
}
|
|
pszT += lstrlen(pszT) + 1;
|
|
}
|
|
|
|
Assert((LPTSTR)((LPBYTE)panr + cbRequired) == pszT);
|
|
hres = S_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We are simply handing QueryGetData.
|
|
hres = S_OK;
|
|
}
|
|
|
|
ILFree(pidl);
|
|
}
|
|
|
|
HIDA_ReleaseStgMedium(pida, &medium);
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
HRESULT CNETIDLData_GetNetResourceForFS(IDataObject *pdtobj, STGMEDIUM *pmedium)
|
|
{
|
|
HRESULT hres = E_OUTOFMEMORY;
|
|
LPITEMIDLIST pidlAbs;
|
|
STGMEDIUM medium;
|
|
LPIDA pida = DataObj_GetHIDA(pdtobj, &medium);
|
|
|
|
Assert(pida && medium.hGlobal); // we created this...
|
|
|
|
//
|
|
// NOTES: Even though we may have multiple FS objects in this HIDA,
|
|
// we know that they share the root. Therefore, getting the pidl for
|
|
// the first item is always sufficient.
|
|
//
|
|
|
|
pidlAbs = IDA_ILClone(pida, 0);
|
|
if (pidlAbs)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
|
|
Assert(CDesktop_IsMyNetwork(pidlAbs));
|
|
|
|
//
|
|
// Look for the JUNCTION point (starting from the second ID)
|
|
//
|
|
for (pidl = _ILNext(pidlAbs); !ILIsEmpty(pidl); pidl = _ILNext(pidl))
|
|
{
|
|
LPIDNETRESOURCE pidn = (LPIDNETRESOURCE)pidl;
|
|
if (NET_GetFlags(pidn) & SHID_JUNCTION)
|
|
{
|
|
//
|
|
// We found the JUNCTION point (which is s share).
|
|
// Return the HNRES to it.
|
|
//
|
|
TCHAR szProvider[MAX_PATH];
|
|
TCHAR szRemote[MAX_PATH];
|
|
UINT cbRequired;
|
|
LPCTSTR pszProvider = NET_CopyProviderNameAbs(pidlAbs,
|
|
szProvider,
|
|
ARRAYSIZE(szProvider));
|
|
LPCTSTR pszRemoteName = NET_CopyResName(pidn,
|
|
szRemote,
|
|
ARRAYSIZE(szRemote));
|
|
UINT cbProvider = lstrlen(pszProvider) * SIZEOF(TCHAR) + SIZEOF(TCHAR);
|
|
|
|
//
|
|
// This should not be a provider node.
|
|
// This should not be the last ID in pidlAbs.
|
|
//
|
|
Assert(pszProvider != pszRemoteName);
|
|
Assert(!ILIsEmpty(_ILNext(pidl)));
|
|
|
|
cbRequired = SIZEOF(NRESARRAY) + cbProvider + lstrlen(pszRemoteName) * SIZEOF(TCHAR) + SIZEOF(TCHAR);
|
|
|
|
pmedium->pUnkForRelease = NULL;
|
|
pmedium->tymed = TYMED_HGLOBAL;
|
|
pmedium->hGlobal = GlobalAlloc(GPTR, cbRequired);
|
|
if (pmedium->hGlobal)
|
|
{
|
|
LPNRESARRAY panr = (LPNRESARRAY)pmedium->hGlobal;
|
|
LPNETRESOURCE pnr = &panr->nr[0];
|
|
LPTSTR pszT = (LPTSTR)(panr + 1);
|
|
|
|
Assert(pnr->dwScope == 0);
|
|
Assert(pnr->lpLocalName == NULL);
|
|
Assert(pnr->lpComment == NULL);
|
|
|
|
panr->cItems = 1;
|
|
|
|
pnr->dwType = NET_GetType(pidn);
|
|
pnr->dwDisplayType = NET_GetDisplayType(pidn);
|
|
pnr->dwUsage = NET_GetUsage(pidn);
|
|
|
|
*((UINT *) &pnr->lpProvider) = SIZEOF(NRESARRAY);
|
|
lstrcpy(pszT, pszProvider);
|
|
Assert(PTROFFSET(panr, pszT) == SIZEOF(NRESARRAY));
|
|
pszT += cbProvider / SIZEOF(TCHAR);
|
|
|
|
*((UINT *) &pnr->lpRemoteName) = SIZEOF(NRESARRAY) + cbProvider;
|
|
Assert(PTROFFSET(panr, pszT) == (int)SIZEOF(NRESARRAY) + (int)cbProvider);
|
|
lstrcpy(pszT, pszRemoteName);
|
|
|
|
Assert(((LPBYTE)panr) + cbRequired == (LPBYTE)pszT + (lstrlen(pszT) + 1) * SIZEOF(TCHAR));
|
|
hres = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hres = E_OUTOFMEMORY;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We should have found the junction point.
|
|
//
|
|
Assert(!ILIsEmpty(pidl));
|
|
|
|
|
|
ILFree(pidlAbs);
|
|
}
|
|
|
|
HIDA_ReleaseStgMedium(pida, &medium);
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
UINT WINAPI SHGetNetResource(HNRES hnres, UINT iItem, LPNETRESOURCE pnresOut, UINT cbMax)
|
|
{
|
|
UINT iRet = 0; // assume error
|
|
LPNRESARRAY panr = GlobalLock(hnres);
|
|
if (panr)
|
|
{
|
|
if (iItem==(UINT)-1)
|
|
{
|
|
iRet = panr->cItems;
|
|
}
|
|
else if (iItem < panr->cItems)
|
|
{
|
|
UINT cbProvider, cbRemoteName;
|
|
LPCTSTR pszProvider = _Offset2Ptr((LPTSTR)panr, (UINT)panr->nr[iItem].lpProvider, &cbProvider);
|
|
LPCTSTR pszRemoteName = _Offset2Ptr((LPTSTR)panr, (UINT)panr->nr[iItem].lpRemoteName, &cbRemoteName);
|
|
iRet = SIZEOF(NETRESOURCE) + cbProvider + cbRemoteName;
|
|
if (iRet <= cbMax)
|
|
{
|
|
LPTSTR psz = (LPTSTR)(pnresOut + 1);
|
|
*pnresOut = panr->nr[iItem];
|
|
if (pnresOut->lpProvider)
|
|
{
|
|
pnresOut->lpProvider = psz;
|
|
lstrcpy(psz, pszProvider);
|
|
psz += cbProvider / SIZEOF(TCHAR);
|
|
}
|
|
if (pnresOut->lpRemoteName)
|
|
{
|
|
pnresOut->lpRemoteName = psz;
|
|
lstrcpy(psz, pszRemoteName);
|
|
}
|
|
}
|
|
}
|
|
GlobalUnlock(hnres);
|
|
}
|
|
return iRet;
|
|
}
|
|
|
|
// BUGBUG Comment this unicode logic
|
|
HRESULT World_SimpleIDListFromPath(LPCTSTR pszPath, LPITEMIDLIST *ppidl)
|
|
{
|
|
UNALIGNED IDNETRESOURCE * pidnr;
|
|
UNALIGNED IDNETRESOURCE * pidnrNext;
|
|
|
|
LPCTSTR pszRest = pszPath + 2; // get beyond the first two \\ s
|
|
LPITEMIDLIST pidl, pidl2, pidlRight;
|
|
LPCITEMIDLIST pidlMapped = NULL;
|
|
LPTSTR pszMapped;
|
|
HRESULT hres;
|
|
UINT cbPath;
|
|
#ifdef UNICODE
|
|
BOOL fUnicode;
|
|
LPSTR lpAnsiBuffer;
|
|
LPWSTR lpUnicodeBuffer;
|
|
UINT cchAnsiPath;
|
|
UINT cchWidePath;
|
|
#endif
|
|
|
|
if (!PathIsUNC(pszPath))
|
|
return E_INVALIDARG;
|
|
|
|
#ifdef UNICODE
|
|
cbPath = lstrlen(pszPath); // Counting size of ANSI buffer to create
|
|
lpAnsiBuffer = (LPSTR)LocalAlloc(LPTR, (cbPath+1) * SIZEOF(TCHAR) * 2);
|
|
if (!lpAnsiBuffer)
|
|
return(E_OUTOFMEMORY);
|
|
lpUnicodeBuffer = (LPWSTR)(lpAnsiBuffer + (cbPath+1) * 2); // 2 for DBCS
|
|
|
|
cchAnsiPath = WideCharToMultiByte(CP_ACP, 0,
|
|
pszPath, cbPath+1,
|
|
lpAnsiBuffer, (cbPath+1),
|
|
NULL, NULL);
|
|
cchWidePath = MultiByteToWideChar(CP_ACP, 0,
|
|
lpAnsiBuffer, cchAnsiPath,
|
|
lpUnicodeBuffer, (cbPath+1)*2); // 2 for DBCS
|
|
cbPath = cchAnsiPath;
|
|
fUnicode = (0 == lstrcmp(lpUnicodeBuffer,pszPath)) ? FALSE : TRUE;
|
|
if (fUnicode)
|
|
{
|
|
cbPath += cchWidePath * SIZEOF(WCHAR);
|
|
}
|
|
#else
|
|
cbPath = lstrlen(pszPath); // Dealing with ANSI only...
|
|
#endif
|
|
// Allocate a buffer to use to create a simple id into.
|
|
|
|
while (*pszRest && *pszRest != TEXT('\\'))
|
|
pszRest = CharNext(pszRest);
|
|
// We may not need this part but we will see...
|
|
// I will be a little sloppy calculating size needed.
|
|
// {Server}{NET UNKNWON}\rest goes to fstree...
|
|
pidnrNext = pidnr = (IDNETRESOURCE *)LocalAlloc(LPTR, 2 * SIZEOF(IDNETRESOURCE)
|
|
+ (2 * cbPath) + SIZEOF(USHORT)); // BUGBUG why ushort? BUGBUG (Davepl) its size of mkid.cb, can't you see? Duh.
|
|
if (!pidnr)
|
|
{
|
|
#ifdef UNICODE
|
|
LocalFree(lpAnsiBuffer);
|
|
#endif
|
|
return(E_OUTOFMEMORY);
|
|
}
|
|
|
|
// Lets hope we get a mapping of at least the server
|
|
// See if we have a name translation we can use.
|
|
pszMapped = (LPTSTR)NPTMapNameToPidl(pszPath, &pidlMapped);
|
|
|
|
/* BUGBUG: We need to be very careful with 'simple ID lists', they
|
|
/ do not work well when compared against 'real ID lists' as they lack
|
|
/ elements (in the network case there is no NET provider). daviddv 2/19/1996 */
|
|
|
|
// This is sortof screwy I will remove the First ID off of the mapping
|
|
// as I want to make it relitive to me...
|
|
//
|
|
if (pszMapped)
|
|
{
|
|
pidlMapped = (LPCITEMIDLIST)_ILNext((LPITEMIDLIST)pidlMapped);
|
|
}
|
|
else
|
|
{
|
|
// Did not find any mapping. So this implies no mapping...
|
|
// We can now try to fill in the first part The server.
|
|
pidnr->cb = SIZEOF(IDNETRESOURCE) + (int)(pszRest-pszPath);
|
|
pidnr->bFlags = SHID_NET; // Assume that this is a server
|
|
pidnr->uType = 0; // Dont set as dont know...
|
|
pidnr->uUsage= 0;
|
|
#ifdef UNICODE
|
|
lstrcpynA(pidnr->szNetResName, lpAnsiBuffer, (int)(pszRest-pszPath)+1);
|
|
if (fUnicode)
|
|
{
|
|
LPNWSTR lpwstr;
|
|
pidnr->uUsage |= NET_UNICODE;
|
|
pidnr->cb += (int)(pszRest-pszPath+1) * SIZEOF(TCHAR);
|
|
|
|
lpwstr = (LPNWSTR)(pidnr->szNetResName+(pszRest-pszPath+1)); // no *TCHAR here, we're skipping over the ansi string
|
|
|
|
ualstrcpyn(lpwstr, pszPath, (int)(pszRest-pszPath)+1);
|
|
}
|
|
#else
|
|
lstrcpyn(pidnr->szNetResName, pszPath, (int)(pszRest-pszPath)+1);
|
|
#endif
|
|
|
|
// Now lets setup the share point side...
|
|
pidnrNext = (UNALIGNED IDNETRESOURCE *)((LPBYTE)pidnrNext + pidnrNext->cb);
|
|
}
|
|
|
|
//
|
|
// Now see if we need to fill in the share point.
|
|
// The <= should cover the NULL case also.
|
|
if ((pszMapped <= pszRest) && *pszRest)
|
|
{
|
|
pszRest++;
|
|
while (*pszRest && *pszRest != TEXT('\\'))
|
|
pszRest = CharNext(pszRest);
|
|
pidnrNext->cb = SIZEOF(IDNETRESOURCE) + (int)(pszRest-pszPath);
|
|
pidnrNext->bFlags = SHID_NET | SHID_JUNCTION; // we know it is net but...
|
|
pidnrNext->uType = 0; // Dont set as dont know...
|
|
pidnrNext->uUsage= 0;
|
|
#ifdef UNICODE
|
|
lstrcpynA(pidnrNext->szNetResName, lpAnsiBuffer, (int)(pszRest-pszPath)+1);
|
|
if (fUnicode)
|
|
{
|
|
LPNWSTR lpwstr;
|
|
pidnrNext->uUsage |= NET_UNICODE;
|
|
pidnrNext->cb += (int)(pszRest-pszPath+1) * SIZEOF(TCHAR);
|
|
lpwstr = (LPNWSTR)(pidnrNext->szNetResName+(pszRest-pszPath+1)); // no *TCHAR here, we're skipping over the ansi string
|
|
ualstrcpyn(lpwstr, pszPath, (int)(pszRest-pszPath)+1);
|
|
}
|
|
#else
|
|
lstrcpyn(pidnrNext->szNetResName, pszPath, (int)(pszRest-pszPath)+1);
|
|
#endif
|
|
|
|
pidnrNext = (LPIDNETRESOURCE)((LPBYTE)pidnrNext + pidnrNext->cb);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
LocalFree(lpAnsiBuffer);
|
|
#endif
|
|
|
|
// Set the lenght to null for the last element
|
|
pidnrNext->cb = 0;
|
|
|
|
// Was only the server or share sent in. In this case we simply
|
|
// need to clone or append our ids if we got a mapping.
|
|
// Clone the right size id list for this guy and free our temporary
|
|
if (*pszRest == TEXT('\0'))
|
|
{
|
|
// That was all that was passed in
|
|
if (pszMapped)
|
|
pidl = ILCombine(pidlMapped, (LPITEMIDLIST)pidnr);
|
|
else
|
|
pidl = ILClone((LPITEMIDLIST)pidnr);
|
|
LocalFree((HLOCAL)pidnr);
|
|
if (!pidl)
|
|
return(E_OUTOFMEMORY);
|
|
}
|
|
else
|
|
{
|
|
// Otherwise pass in the rest of the path to the fS simple
|
|
// path processing
|
|
|
|
if (pszMapped > pszRest)
|
|
pszRest = pszMapped;
|
|
|
|
hres = FSTree_SimpleIDListFromPath(pszRest+1, &pidlRight);
|
|
if (FAILED(hres))
|
|
{
|
|
LocalFree((HLOCAL)pidnr);
|
|
return(hres);
|
|
}
|
|
|
|
if (pszMapped)
|
|
{
|
|
pidl2 = ILCombine(pidlMapped, (LPITEMIDLIST)pidnr);
|
|
LocalFree((HLOCAL)pidnr);
|
|
if (!pidl2)
|
|
{
|
|
ILFree(pidlRight);
|
|
return(E_OUTOFMEMORY);
|
|
}
|
|
|
|
pidl = ILCombine(pidl2, pidlRight);
|
|
ILFree(pidl2);
|
|
}
|
|
else
|
|
{
|
|
pidl = ILCombine((LPITEMIDLIST)pidnr, pidlRight);
|
|
LocalFree((HLOCAL)pidnr);
|
|
}
|
|
|
|
if (!pidlRight)
|
|
{
|
|
ILFree(pidlRight);
|
|
return(E_OUTOFMEMORY);
|
|
}
|
|
}
|
|
|
|
// we got here so we have a valid ID list to return
|
|
*ppidl = pidl;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
//===========================================================================
|
|
// Here are some stub functions to demand load MPR only when we really
|
|
// really need it
|
|
//===========================================================================
|
|
//===========================================================================
|
|
// First define some types to use for each of our calls
|
|
// BUGBUG should these have APIENTRY????????
|
|
typedef DWORD (* PFNMULTINETGETCONNECTIONPERFORMANCE) (LPNETRESOURCE lpNetResource, LPNETCONNECTINFOSTRUCT lpNetConnectInfoStruct);
|
|
typedef DWORD (* PFNMULTINETGETERRORTEXT) (LPTSTR, LPDWORD, LPTSTR, LPDWORD);
|
|
typedef DWORD (* PFNWNETUSECONNECTION) (HWND hwndOwner, LPNETRESOURCE lpNetResource, LPCTSTR lpUserID, LPCTSTR lpPassword, DWORD dwFlags, LPTSTR lpAccessName, LPDWORD lpBufferSize, LPDWORD lpResult);
|
|
typedef DWORD (* PFNWNETADDCONNECTION3) (HWND hwndOwner, LPNETRESOURCE lpNetResource, LPCTSTR lpUserID, LPCTSTR lpPassword, DWORD dwFlags);
|
|
typedef DWORD (* PFNWNETCANCELCONNECTION) (LPCTSTR lpName, BOOL fForce);
|
|
typedef DWORD (* PFNWNETCLOSEENUM) (HANDLE hEnum);
|
|
#ifdef WNETCONNECTIONDIALOG1
|
|
typedef DWORD (* PFNWNETCONNECTIONDIALOG1) (LPCONNECTDLGSTRUCT);
|
|
#else
|
|
typedef DWORD (* PFNWNETADDCONNECTIONDIALOG) (HWND hParent, LPTSTR lpszRemoteName, DWORD dwType);
|
|
typedef DWORD (* PFNWNETCONNECTIONDIALOG) (HWND hwnd, DWORD dwType);
|
|
#endif
|
|
typedef DWORD (* PFNWNETDISCONNECTDIALOG) (HWND hwnd, DWORD dwType);
|
|
typedef DWORD (* PFNWNETDISCONNECTDIALOG1) (LPDISCDLGSTRUCT lpConnDlgStruct);
|
|
typedef DWORD (* PFNWNETENUMRESOURCE) (HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize);
|
|
typedef DWORD (* PFNWNETFORMATNETWORKNAME) (LPCTSTR lpProvider, LPCTSTR lpRemoteName, LPTSTR lpFormattedName, LPDWORD lpnLength, DWORD dwFlags, DWORD dwAveCharPerLine);
|
|
typedef DWORD (* PFNWNETGETCONNECTION) (LPCTSTR lpLocalName, LPTSTR lpRemoteName, LPDWORD lpnLength);
|
|
typedef DWORD (* PFNWNETGETCONNECTION3) (LPCTSTR lpLocalName, LPCTSTR lpProviderName, DWORD dwInfoLevel, LPVOID lpBuffer, LPDWORD lpcbBuffer);
|
|
typedef DWORD (* PFNWNETGETLASTERROR) (LPDWORD lpError, LPTSTR lpErrorBuf, DWORD nErrorBufSize, LPTSTR lpNameBuf, DWORD nNameBufSize);
|
|
typedef DWORD (* PFNWNETGETRESOURCEPARENT) (LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD cbBuffer);
|
|
typedef DWORD (* PFNWNETGETRESOURCEINFORMATION) (LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD cbBuffer, LPTSTR *lplpSystem);
|
|
typedef DWORD (* PFNWNETGETNETWORKINFORMATION) (LPCTSTR lpProvider, LPNETINFOSTRUCT lpNetInfoStruct);
|
|
#ifndef WINNT
|
|
typedef DWORD (* PFNWNETLOGON) (LPCTSTR lpProvider, HWND hwndOwner);
|
|
#endif // !WINNT
|
|
typedef DWORD (* PFNWNETOPENENUM) (DWORD dwScope, DWORD dwType, DWORD dwUsage, LPNETRESOURCE lpNetResource, LPHANDLE lphEnum);
|
|
typedef DWORD (* PFNWNETRESTORECONNECTION) (HWND hwndParent, LPCTSTR lpDevice);
|
|
typedef DWORD (* PFNWNETGETHOMEDIRECTORY)(LPCTSTR lpProviderName, LPTSTR lpDirectory, LPDWORD lpBufferSize);
|
|
typedef DWORD (* PFNWNETGETUSER)(LPCTSTR lpName,LPTSTR lpUserName, LPDWORD lpnLength);
|
|
typedef DWORD (* PFNWNETGETPROVIDERTYPE)(LPCTSTR lpProvider, LPDWORD lpType);
|
|
typedef DWORD (* PFNWNETGETPROVIDERNAME)(DWORD dwNetType, LPTSTR lpProvider, LPDWORD lpBufferSize);
|
|
|
|
//
|
|
// Per-instance Global data (16-bit/32-bit common)
|
|
//
|
|
#pragma data_seg(DATASEG_PERINSTANCE)
|
|
HINSTANCE s_hmodMPR = NULL;
|
|
PFNMULTINETGETCONNECTIONPERFORMANCE g_pfnMultinetGetConnectionPerformance = NULL;
|
|
PFNMULTINETGETERRORTEXT g_pfnMultinetGetErrorText = NULL;
|
|
PFNWNETADDCONNECTION3 g_pfnWNetAddConnection3 = NULL;
|
|
PFNWNETUSECONNECTION g_pfnWNetUseConnection = NULL;
|
|
PFNWNETCANCELCONNECTION g_pfnWNetCancelConnection = NULL;
|
|
PFNWNETCLOSEENUM g_pfnWNetCloseEnum = NULL;
|
|
#ifdef WNETCONNECTIONDIALOG1
|
|
PFNWNETCONNECTIONDIALOG1 g_pfnWNetConnectionDialog1 = NULL;
|
|
#else
|
|
PFNWNETADDCONNECTIONDIALOG g_pfnWNetAddConnectionDialog = NULL;
|
|
PFNWNETCONNECTIONDIALOG g_pfnWNetConnectionDialog = NULL;
|
|
#endif
|
|
PFNWNETDISCONNECTDIALOG g_pfnWNetDisconnectDialog = NULL;
|
|
PFNWNETDISCONNECTDIALOG1 g_pfnWNetDisconnectDialog1 = NULL;
|
|
PFNWNETENUMRESOURCE g_pfnWNetEnumResource = NULL;
|
|
PFNWNETFORMATNETWORKNAME g_pfnWNetFormatNetworkName = NULL;
|
|
PFNWNETGETCONNECTION g_pfnWNetGetConnection = NULL;
|
|
PFNWNETGETCONNECTION3 g_pfnWNetGetConnection3 = NULL;
|
|
PFNWNETGETLASTERROR g_pfnWNetGetLastError = NULL;
|
|
PFNWNETGETRESOURCEPARENT g_pfnWNetGetResourceParent = NULL;
|
|
PFNWNETGETRESOURCEINFORMATION g_pfnWNetGetResourceInformation = NULL;
|
|
PFNWNETGETNETWORKINFORMATION g_pfnWNetGetNetworkInformation = NULL;
|
|
PFNWNETGETPROVIDERTYPE g_pfnWNetGetProviderType = NULL;
|
|
PFNWNETGETPROVIDERNAME g_pfnWNetGetProviderName = NULL;
|
|
|
|
#ifndef WINNT
|
|
PFNWNETLOGON g_pfnWNetLogon = NULL;
|
|
#endif // !WINNT
|
|
PFNWNETOPENENUM g_pfnWNetOpenEnum = NULL;
|
|
PFNWNETRESTORECONNECTION g_pfnWNetRestoreConnection = NULL;
|
|
PFNWNETGETHOMEDIRECTORY g_pfnWNetGetHomeDirectory = NULL;
|
|
PFNWNETGETUSER g_pfnWNetGetUser = NULL;
|
|
#pragma data_seg()
|
|
|
|
// Define a MACRO that checks to see if MPR is loaded if not load it and if failure
|
|
// returns an error code.
|
|
// This also asserts if we own a critical section while making WNet calls (because
|
|
// they can be really slow).
|
|
#define CheckMprLoad \
|
|
ASSERTNONCRITICAL \
|
|
if (!IsDllLoaded(s_hmodMPR,TEXT("mpr"))) \
|
|
{ \
|
|
if (!MprDLL_Init()) \
|
|
return(WN_NOT_SUPPORTED); \
|
|
}
|
|
|
|
|
|
// Now for the Load and Unload Functions
|
|
BOOL MprDLL_Init()
|
|
{
|
|
HINSTANCE hmodMPR;
|
|
|
|
//
|
|
// First, check the global without entering the critical section.
|
|
//
|
|
if (s_hmodMPR != NULL)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
// WARNING: We MUST NOT call LoadLibrary from within critical section.
|
|
hmodMPR = LoadLibrary(TEXT("mpr.dll"));
|
|
if ((UINT)hmodMPR <= HINSTANCE_ERROR)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
// Now get all of the procedure addresses we need
|
|
#ifdef UNICODE
|
|
g_pfnMultinetGetConnectionPerformance = (PFNMULTINETGETCONNECTIONPERFORMANCE)GetProcAddress(hmodMPR, "MultinetGetConnectionPerformanceW");
|
|
g_pfnMultinetGetErrorText = (PFNMULTINETGETERRORTEXT)GetProcAddress(hmodMPR, "MultinetGetErrorTextW");
|
|
g_pfnWNetAddConnection3 = (PFNWNETADDCONNECTION3)GetProcAddress(hmodMPR, "WNetAddConnection3W");
|
|
g_pfnWNetUseConnection = (PFNWNETUSECONNECTION)GetProcAddress(hmodMPR, "WNetUseConnectionW");
|
|
g_pfnWNetCancelConnection = (PFNWNETCANCELCONNECTION)GetProcAddress(hmodMPR, "WNetCancelConnectionW");
|
|
g_pfnWNetCloseEnum = (PFNWNETCLOSEENUM)GetProcAddress(hmodMPR, "WNetCloseEnum");
|
|
#ifdef WNETCONNECTIONDIALOG1
|
|
g_pfnWNetConnectionDialog1 = (PFNWNETCONNECTIONDIALOG1)GetProcAddress(hmodMPR, "WNetConnectionDialog1W");
|
|
#else
|
|
g_pfnWNetAddConnectionDialog = (PFNWNETADDCONNECTIONDIALOG)GetProcAddress(hmodMPR, "WNetAddConnectionDialogW");
|
|
g_pfnWNetConnectionDialog = (PFNWNETCONNECTIONDIALOG)GetProcAddress(hmodMPR, "WNetConnectionDialog");
|
|
#endif
|
|
g_pfnWNetDisconnectDialog = (PFNWNETDISCONNECTDIALOG)GetProcAddress(hmodMPR, "WNetDisconnectDialog");
|
|
g_pfnWNetDisconnectDialog1 = (PFNWNETDISCONNECTDIALOG1)GetProcAddress(hmodMPR, "WNetDisconnectDialog1W");
|
|
g_pfnWNetEnumResource = (PFNWNETENUMRESOURCE)GetProcAddress(hmodMPR, "WNetEnumResourceW");
|
|
g_pfnWNetFormatNetworkName = (PFNWNETFORMATNETWORKNAME)GetProcAddress(hmodMPR, "WNetFormatNetworkNameW");
|
|
g_pfnWNetGetConnection = (PFNWNETGETCONNECTION)GetProcAddress(hmodMPR, "WNetGetConnectionW");
|
|
g_pfnWNetGetConnection3 = (PFNWNETGETCONNECTION3)GetProcAddress(hmodMPR, "WNetGetConnection3W");
|
|
g_pfnWNetGetLastError = (PFNWNETGETLASTERROR)GetProcAddress(hmodMPR, "WNetGetLastErrorW");
|
|
g_pfnWNetGetResourceParent = (PFNWNETGETRESOURCEPARENT)GetProcAddress(hmodMPR, "WNetGetResourceParentW");
|
|
g_pfnWNetGetResourceInformation = (PFNWNETGETRESOURCEINFORMATION)GetProcAddress(hmodMPR, "WNetGetResourceInformationW");
|
|
g_pfnWNetGetNetworkInformation = (PFNWNETGETNETWORKINFORMATION)GetProcAddress(hmodMPR, "WNetGetNetworkInformationW");
|
|
#ifndef WINNT
|
|
g_pfnWNetLogon = (PFNWNETLOGON)GetProcAddress(hmodMPR, "WNetLogonW");
|
|
#endif // !WINNT
|
|
g_pfnWNetOpenEnum = (PFNWNETOPENENUM)GetProcAddress(hmodMPR, "WNetOpenEnumW");
|
|
g_pfnWNetRestoreConnection = (PFNWNETRESTORECONNECTION)GetProcAddress(hmodMPR, "WNetRestoreConnectionW");
|
|
g_pfnWNetGetHomeDirectory = (PFNWNETGETHOMEDIRECTORY)GetProcAddress(hmodMPR, "WNetGetHomeDirectoryW");
|
|
g_pfnWNetGetUser = (PFNWNETGETUSER)GetProcAddress(hmodMPR, "WNetGetUserW");
|
|
g_pfnWNetGetProviderType = (PFNWNETGETPROVIDERTYPE)GetProcAddress(hmodMPR, "WNetGetProviderTypeW");
|
|
g_pfnWNetGetProviderName = (PFNWNETGETPROVIDERNAME)GetProcAddress(hmodMPR, "WNetGetProviderNameW");
|
|
#else
|
|
g_pfnWNetAddConnection3 = (PFNWNETADDCONNECTION3)GetProcAddress(hmodMPR, "WNetAddConnection3A");
|
|
g_pfnWNetUseConnection = (PFNWNETUSECONNECTION)GetProcAddress(hmodMPR, "WNetUseConnectionA");
|
|
g_pfnWNetCancelConnection = (PFNWNETCANCELCONNECTION)GetProcAddress(hmodMPR, "WNetCancelConnectionA");
|
|
g_pfnWNetCloseEnum = (PFNWNETCLOSEENUM)GetProcAddress(hmodMPR, "WNetCloseEnum");
|
|
#ifdef WNETCONNECTIONDIALOG1
|
|
g_pfnWNetConnectionDialog1 = (PFNWNETCONNECTIONDIALOG1)GetProcAddress(hmodMPR, "WNetConnectionDialog1A");
|
|
#else
|
|
g_pfnWNetAddConnectionDialog = (PFNWNETADDCONNECTIONDIALOG)GetProcAddress(hmodMPR, "WNetAddConnectionDialogA");
|
|
g_pfnWNetConnectionDialog = (PFNWNETCONNECTIONDIALOG)GetProcAddress(hmodMPR, "WNetConnectionDialog");
|
|
#endif
|
|
g_pfnWNetDisconnectDialog = (PFNWNETDISCONNECTDIALOG)GetProcAddress(hmodMPR, "WNetDisconnectDialog");
|
|
g_pfnWNetDisconnectDialog1 = (PFNWNETDISCONNECTDIALOG1)GetProcAddress(hmodMPR, "WNetDisconnectDialog1A");
|
|
g_pfnWNetEnumResource = (PFNWNETENUMRESOURCE)GetProcAddress(hmodMPR, "WNetEnumResourceA");
|
|
g_pfnWNetFormatNetworkName = (PFNWNETFORMATNETWORKNAME)GetProcAddress(hmodMPR, "WNetFormatNetworkNameA");
|
|
g_pfnWNetGetConnection = (PFNWNETGETCONNECTION)GetProcAddress(hmodMPR, "WNetGetConnectionA");
|
|
g_pfnWNetGetConnection3 = (PFNWNETGETCONNECTION3)GetProcAddress(hmodMPR, "WNetGetConnection3A");
|
|
g_pfnWNetGetLastError = (PFNWNETGETLASTERROR)GetProcAddress(hmodMPR, "WNetGetLastErrorA");
|
|
g_pfnWNetGetResourceParent = (PFNWNETGETRESOURCEPARENT)GetProcAddress(hmodMPR, "WNetGetResourceParentA");
|
|
g_pfnWNetGetResourceInformation = (PFNWNETGETRESOURCEINFORMATION)GetProcAddress(hmodMPR, "WNetGetResourceInformationA");
|
|
g_pfnWNetGetNetworkInformation = (PFNWNETGETNETWORKINFORMATION)GetProcAddress(hmodMPR, "WNetGetNetworkInformationA");
|
|
g_pfnWNetOpenEnum = (PFNWNETOPENENUM)GetProcAddress(hmodMPR, "WNetOpenEnumA");
|
|
g_pfnWNetGetHomeDirectory = (PFNWNETGETHOMEDIRECTORY)GetProcAddress(hmodMPR, "WNetGetHomeDirectoryA");
|
|
g_pfnWNetGetUser = (PFNWNETGETUSER)GetProcAddress(hmodMPR, "WNetGetUserA");
|
|
g_pfnMultinetGetConnectionPerformance = (PFNMULTINETGETCONNECTIONPERFORMANCE)GetProcAddress(hmodMPR, "MultinetGetConnectionPerformanceA");
|
|
g_pfnMultinetGetErrorText = (PFNMULTINETGETERRORTEXT)GetProcAddress(hmodMPR, "MultinetGetErrorTextA");
|
|
#ifndef WINNT
|
|
g_pfnWNetLogon = (PFNWNETLOGON)GetProcAddress(hmodMPR, "WNetLogonA");
|
|
#endif // !WINNT
|
|
g_pfnWNetRestoreConnection = (PFNWNETRESTORECONNECTION)GetProcAddress(hmodMPR, "WNetRestoreConnectionA");
|
|
g_pfnWNetGetProviderType = (PFNWNETGETPROVIDERTYPE)GetProcAddress(hmodMPR, "WNetGetProviderTypeA");
|
|
g_pfnWNetGetProviderName = (PFNWNETGETPROVIDERNAME)GetProcAddress(hmodMPR, "WNetGetProviderNameA");
|
|
#endif
|
|
|
|
#ifndef BUGBUG_BOBDAY
|
|
if ( g_pfnMultinetGetConnectionPerformance == NULL || //*
|
|
g_pfnMultinetGetErrorText == NULL || //*
|
|
g_pfnWNetAddConnection3 == NULL ||
|
|
g_pfnWNetUseConnection == NULL ||
|
|
g_pfnWNetCancelConnection == NULL ||
|
|
g_pfnWNetCloseEnum == NULL ||
|
|
#ifdef WNETCONNECTIONDIALOG1
|
|
g_pfnWNetConnectionDialog1 == NULL ||
|
|
#else
|
|
g_pfnWNetAddConnectionDialog == NULL ||
|
|
g_pfnWNetConnectionDialog == NULL ||
|
|
#endif
|
|
g_pfnWNetDisconnectDialog == NULL ||
|
|
g_pfnWNetDisconnectDialog1 == NULL ||
|
|
g_pfnWNetEnumResource == NULL ||
|
|
g_pfnWNetFormatNetworkName == NULL ||
|
|
g_pfnWNetGetConnection == NULL ||
|
|
g_pfnWNetGetLastError == NULL ||
|
|
g_pfnWNetGetResourceParent == NULL ||
|
|
g_pfnWNetGetResourceInformation == NULL ||
|
|
g_pfnWNetGetNetworkInformation == NULL ||
|
|
#ifndef WINNT
|
|
g_pfnWNetLogon == NULL || //*
|
|
#endif // !WINNT
|
|
g_pfnWNetOpenEnum == NULL ||
|
|
g_pfnWNetGetProviderName == NULL ||
|
|
g_pfnWNetRestoreConnection == NULL ) //*
|
|
{
|
|
//
|
|
// Reset all of these suckers to 0!
|
|
//
|
|
g_pfnMultinetGetConnectionPerformance = NULL;
|
|
g_pfnMultinetGetErrorText = NULL;
|
|
g_pfnWNetAddConnection3 = NULL;
|
|
g_pfnWNetUseConnection = NULL;
|
|
g_pfnWNetCancelConnection = NULL;
|
|
g_pfnWNetCloseEnum = NULL;
|
|
#ifdef WNETCONNECTIONDIALOG1
|
|
g_pfnWNetConnectionDialog1 = NULL;
|
|
#else
|
|
g_pfnWNetAddConnectionDialog = NULL;
|
|
g_pfnWNetConnectionDialog = NULL;
|
|
#endif
|
|
g_pfnWNetDisconnectDialog = NULL;
|
|
g_pfnWNetDisconnectDialog1 = NULL;
|
|
g_pfnWNetEnumResource = NULL;
|
|
g_pfnWNetFormatNetworkName = NULL;
|
|
g_pfnWNetGetConnection = NULL;
|
|
g_pfnWNetGetConnection3 = NULL;
|
|
g_pfnWNetGetLastError = NULL;
|
|
g_pfnWNetGetResourceParent = NULL;
|
|
g_pfnWNetGetResourceInformation = NULL;
|
|
g_pfnWNetGetNetworkInformation = NULL;
|
|
#ifndef WINNT
|
|
g_pfnWNetLogon = NULL;
|
|
#endif // !WINNT
|
|
g_pfnWNetOpenEnum = NULL;
|
|
g_pfnWNetGetProviderType = NULL;
|
|
g_pfnWNetGetProviderName = NULL;
|
|
g_pfnWNetRestoreConnection = NULL;
|
|
FreeLibrary(hmodMPR);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Don't need to check for NULL here as the callers have already done
|
|
// do.
|
|
//
|
|
ENTERCRITICAL;
|
|
|
|
// Make sure another thrad has not already done this between the
|
|
// time we checked and the time we got into the critical section.
|
|
if (s_hmodMPR != NULL)
|
|
{
|
|
LEAVECRITICAL;
|
|
|
|
// WARNING: We MUST NOT call FreeLibrary from within cr-section.
|
|
FreeLibrary(hmodMPR);
|
|
return(TRUE);
|
|
}
|
|
|
|
// set the global that we use after we setup all of the pointers that
|
|
// we use that are based off of this guy...
|
|
s_hmodMPR = hmodMPR;
|
|
LEAVECRITICAL;
|
|
return TRUE;
|
|
}
|
|
|
|
void MprDLL_Term()
|
|
{
|
|
// If we loaded it for this app, we should now free ti
|
|
if (ISVALIDHINSTANCE(s_hmodMPR))
|
|
{
|
|
FreeLibrary(s_hmodMPR);
|
|
s_hmodMPR = NULL;
|
|
|
|
// We could also set all of the vars to NULL, but not needed
|
|
// as we always call through our wrappers
|
|
}
|
|
}
|
|
|
|
|
|
|
|
DWORD APIENTRY MultinetGetConnectionPerformance (LPNETRESOURCE lpNetResource, LPNETCONNECTINFOSTRUCT lpNetConnectInfoStruct)
|
|
{
|
|
CheckMprLoad;
|
|
return g_pfnMultinetGetConnectionPerformance (lpNetResource, lpNetConnectInfoStruct);
|
|
}
|
|
|
|
DWORD APIENTRY MultinetGetErrorText(
|
|
LPTSTR lpErrorTextBuf,
|
|
LPDWORD pnErrorBufSize,
|
|
LPTSTR lpProviderNameBuf,
|
|
LPDWORD pnNameBufSize)
|
|
{
|
|
CheckMprLoad;
|
|
return g_pfnMultinetGetErrorText(lpErrorTextBuf, pnErrorBufSize, lpProviderNameBuf, pnNameBufSize);
|
|
}
|
|
|
|
DWORD APIENTRY WNetAddConnection3 (HWND hwndOwner, LPNETRESOURCE lpNetResource, LPCTSTR lpUserID, LPCTSTR lpPassword, DWORD dwFlags)
|
|
{
|
|
CheckMprLoad;
|
|
return g_pfnWNetAddConnection3 (hwndOwner, lpNetResource, lpUserID, lpPassword, dwFlags);
|
|
}
|
|
|
|
DWORD APIENTRY WNetUseConnection (HWND hwndOwner, LPNETRESOURCE lpNetResource, LPCTSTR lpUserID, LPCTSTR lpPassword, DWORD dwFlags, LPTSTR lpAccessName, LPDWORD lpBufferSize, LPDWORD lpResult)
|
|
{
|
|
CheckMprLoad;
|
|
return g_pfnWNetUseConnection (hwndOwner, lpNetResource, lpUserID, lpPassword, dwFlags, lpAccessName, lpBufferSize, lpResult);
|
|
}
|
|
|
|
DWORD APIENTRY WNetCancelConnection (LPCTSTR lpName, BOOL fForce)
|
|
{
|
|
CheckMprLoad;
|
|
return g_pfnWNetCancelConnection (lpName, fForce);
|
|
}
|
|
|
|
DWORD APIENTRY WNetCloseEnum (HANDLE hEnum)
|
|
{
|
|
CheckMprLoad;
|
|
return g_pfnWNetCloseEnum (hEnum);
|
|
}
|
|
|
|
DWORD APIENTRY SHNetConnectionDialog (HWND hwnd, LPTSTR pszRemoteName, DWORD dwType)
|
|
{
|
|
#ifdef WNETCONNECTIONDIALOG1
|
|
CONNECTDLGSTRUCT cds;
|
|
NETRESOURCE nr = {0};
|
|
DWORD mnr;
|
|
|
|
CheckMprLoad;
|
|
|
|
cds.cbStructure = SIZEOF(cds); /* size of this structure in bytes */
|
|
cds.hwndOwner = hwnd; /* owner window for the dialog */
|
|
cds.lpConnRes = &nr; /* Requested Resource info */
|
|
cds.dwFlags = CONNDLG_USE_MRU; /* flags (see below) */
|
|
// cds.dwDevNum; /* number of device connected to */
|
|
|
|
nr.dwType = dwType;
|
|
|
|
if (pszRemoteName)
|
|
{
|
|
nr.lpRemoteName = pszRemoteName;
|
|
cds.dwFlags = CONNDLG_RO_PATH;
|
|
}
|
|
mnr = g_pfnWNetConnectionDialog1(&cds);
|
|
|
|
if (mnr == WN_SUCCESS && dwType != RESOURCETYPE_PRINT && cds.dwDevNum != 0xffffffff)
|
|
{
|
|
TCHAR szDriveRoot[10];
|
|
LPITEMIDLIST pidl;
|
|
|
|
PathBuildRoot(szDriveRoot, cds.dwDevNum-1 /* 1-based! */);
|
|
pidl = ILCreateFromPath(szDriveRoot);
|
|
if (pidl)
|
|
{
|
|
SHChangeNotify(SHCNE_DRIVEADDGUI, SHCNF_IDLIST, pidl, NULL);
|
|
ILFree(pidl);
|
|
}
|
|
}
|
|
return(mnr);
|
|
#else
|
|
// This is a pretty bogus workaround to simulate WnetConnectionDialog
|
|
// to see which drive was added
|
|
DWORD mnr;
|
|
DWORD dwDrives;
|
|
|
|
CheckMprLoad;
|
|
|
|
// Get the list before this call.
|
|
dwDrives = GetLogicalDrives();
|
|
|
|
if (pszRemoteName)
|
|
mnr = g_pfnWNetAddConnectionDialog (hwnd, pszRemoteName, dwType);
|
|
else
|
|
mnr = g_pfnWNetConnectionDialog (hwnd, dwType);
|
|
|
|
if (mnr == WN_SUCCESS && dwType != RESOURCETYPE_PRINT)
|
|
{
|
|
TCHAR szDriveRoot[10];
|
|
LPITEMIDLIST pidl;
|
|
int nDrive;
|
|
|
|
dwDrives = GetLogicalDrives() & ~dwDrives;
|
|
for (nDrive = 0; nDrive < 26; nDrive++)
|
|
{
|
|
if ((1 << nDrive) & dwDrives)
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("sh TR - SHNetConnectionDialog new drive mask: %x"), dwDrives);
|
|
PathBuildRoot(szDriveRoot, nDrive);
|
|
pidl = ILCreateFromPath(szDriveRoot);
|
|
if (pidl)
|
|
{
|
|
SHChangeNotify(SHCNE_DRIVEADDGUI, SHCNF_IDLIST, pidl, NULL);
|
|
ILFree(pidl);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
return(mnr);
|
|
#endif
|
|
}
|
|
|
|
typedef struct _shnc
|
|
{
|
|
HWND hwnd;
|
|
TCHAR szRemoteName[MAX_PATH];
|
|
BOOL fRemoteName;
|
|
DWORD dwType;
|
|
DWORD dwThreadId;
|
|
} SHNETCONNECT, *LPSHNETCONNECT;
|
|
|
|
DWORD CALLBACK _StartNetConnect(LPSHNETCONNECT pshnc)
|
|
{
|
|
HWND hwnd = pshnc->hwnd;
|
|
DWORD dwType = pshnc->dwType;
|
|
BOOL fRemoteName = pshnc->fRemoteName;
|
|
TCHAR szRemoteName[MAX_PATH];
|
|
LPTSTR lpszRemoteName = NULL;
|
|
|
|
if (fRemoteName)
|
|
{
|
|
lstrcpy(szRemoteName,pshnc->szRemoteName);
|
|
lpszRemoteName = szRemoteName;
|
|
}
|
|
|
|
LocalFree(pshnc);
|
|
|
|
SHNetConnectionDialog(hwnd, lpszRemoteName, dwType);
|
|
|
|
SHChangeNotifyHandleEvents();
|
|
return 0;
|
|
}
|
|
|
|
HRESULT APIENTRY SHStartNetConnectionDialog(HWND hwnd, LPTSTR pszRemoteName, DWORD dwType)
|
|
{
|
|
DWORD dwThreadId;
|
|
HANDLE hThread;
|
|
LPSHNETCONNECT pshnc = (void*)LocalAlloc(LPTR, SIZEOF(SHNETCONNECT));
|
|
|
|
if (!pshnc)
|
|
return E_OUTOFMEMORY;
|
|
|
|
pshnc->hwnd = hwnd;
|
|
pshnc->dwType = dwType;
|
|
pshnc->dwThreadId = GetCurrentThreadId();
|
|
if (pszRemoteName)
|
|
{
|
|
pshnc->fRemoteName = TRUE;
|
|
lstrcpyn(pshnc->szRemoteName,pszRemoteName,ARRAYSIZE(pshnc->szRemoteName));
|
|
}
|
|
else
|
|
pshnc->fRemoteName = FALSE;
|
|
|
|
hThread = CreateThread(NULL, 0, _StartNetConnect, pshnc, 0, &dwThreadId);
|
|
|
|
if (hThread) {
|
|
CloseHandle(hThread);
|
|
return S_OK;
|
|
} else {
|
|
LocalFree((HLOCAL)pshnc);
|
|
return E_UNEXPECTED;
|
|
}
|
|
}
|
|
|
|
DWORD APIENTRY WNetDisconnectDialog (HWND hwnd, DWORD dwType)
|
|
{
|
|
CheckMprLoad;
|
|
return g_pfnWNetDisconnectDialog (hwnd, dwType);
|
|
}
|
|
|
|
DWORD APIENTRY WNetDisconnectDialog1 (LPDISCDLGSTRUCT lpConnDlgStruct)
|
|
{
|
|
TCHAR szLocalName[3];
|
|
CheckMprLoad;
|
|
|
|
if (lpConnDlgStruct && lpConnDlgStruct->lpLocalName && lstrlen(lpConnDlgStruct->lpLocalName) > 2)
|
|
{
|
|
// Kludge allert, don't pass c:\ to API, instead only pass C:
|
|
szLocalName[0] = lpConnDlgStruct->lpLocalName[0];
|
|
szLocalName[1] = TEXT(':');
|
|
szLocalName[2] = TEXT('\0');
|
|
lpConnDlgStruct->lpLocalName = szLocalName;
|
|
}
|
|
return g_pfnWNetDisconnectDialog1 (lpConnDlgStruct);
|
|
}
|
|
|
|
DWORD APIENTRY WNetEnumResource (HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
|
|
{
|
|
CheckMprLoad;
|
|
return g_pfnWNetEnumResource (hEnum, lpcCount, lpBuffer, lpBufferSize);
|
|
}
|
|
|
|
DWORD APIENTRY WNetFormatNetworkName (LPCTSTR lpProvider, LPCTSTR lpRemoteName, LPTSTR lpFormattedName, LPDWORD lpnLength, DWORD dwFlags, DWORD dwAveCharPerLine)
|
|
{
|
|
CheckMprLoad;
|
|
|
|
if (!lpProvider || !(*lpProvider))
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
return g_pfnWNetFormatNetworkName (lpProvider, lpRemoteName, lpFormattedName, lpnLength, dwFlags, dwAveCharPerLine);
|
|
}
|
|
|
|
DWORD APIENTRY WNetGetConnection (LPCTSTR lpLocalName, LPTSTR lpRemoteName, LPDWORD lpnLength)
|
|
{
|
|
TCHAR szLocalName[3];
|
|
CheckMprLoad;
|
|
if (lpLocalName && lstrlen(lpLocalName) > 2)
|
|
{
|
|
// Kludge allert, don't pass c:\ to API, instead only pass C:
|
|
szLocalName[0] = lpLocalName[0];
|
|
szLocalName[1] = TEXT(':');
|
|
szLocalName[2] = TEXT('\0');
|
|
lpLocalName = szLocalName;
|
|
}
|
|
return g_pfnWNetGetConnection (lpLocalName, lpRemoteName, lpnLength);
|
|
}
|
|
|
|
DWORD APIENTRY WNetGetConnection3 (LPCTSTR lpLocalName, LPCTSTR lpProvider, DWORD dwInfoLevel, LPVOID lpBuffer, LPDWORD lpcbBuffer)
|
|
{
|
|
CheckMprLoad;
|
|
if (g_pfnWNetGetConnection3)
|
|
return g_pfnWNetGetConnection3(lpLocalName, lpProvider, dwInfoLevel, lpBuffer, lpcbBuffer);
|
|
else
|
|
return ERROR_INVALID_FUNCTION;
|
|
}
|
|
|
|
DWORD APIENTRY WNetGetLastError (LPDWORD lpError, LPTSTR lpErrorBuf, DWORD nErrorBufSize, LPTSTR lpNameBuf, DWORD nNameBufSize)
|
|
{
|
|
CheckMprLoad;
|
|
return g_pfnWNetGetLastError (lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize);
|
|
}
|
|
|
|
DWORD APIENTRY WNetGetResourceParent (LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD cbBuffer)
|
|
{
|
|
CheckMprLoad;
|
|
return g_pfnWNetGetResourceParent (lpNetResource, lpBuffer, cbBuffer);
|
|
}
|
|
|
|
DWORD APIENTRY WNetGetResourceInformation (LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD cbBuffer,
|
|
LPTSTR * lplpSystem)
|
|
{
|
|
|
|
CheckMprLoad;
|
|
|
|
return g_pfnWNetGetResourceInformation (lpNetResource, lpBuffer, cbBuffer, lplpSystem);
|
|
|
|
}
|
|
|
|
DWORD APIENTRY WNetGetNetworkInformation (LPCTSTR lpProvider, LPNETINFOSTRUCT lpNetInfoStruct)
|
|
{
|
|
CheckMprLoad;
|
|
return g_pfnWNetGetNetworkInformation(lpProvider, lpNetInfoStruct);
|
|
}
|
|
|
|
DWORD APIENTRY WNetGetProviderType (LPCTSTR lpProvider, LPDWORD lpType)
|
|
{
|
|
CheckMprLoad;
|
|
if (g_pfnWNetGetProviderType)
|
|
return g_pfnWNetGetProviderType(lpProvider, lpType);
|
|
else
|
|
return ERROR_INVALID_FUNCTION;
|
|
}
|
|
|
|
DWORD APIENTRY WNetGetProviderName (DWORD dwNetType, LPTSTR lpProvider, LPDWORD lpBufferSize)
|
|
{
|
|
CheckMprLoad;
|
|
if (g_pfnWNetGetProviderName)
|
|
return g_pfnWNetGetProviderName(dwNetType, lpProvider, lpBufferSize);
|
|
else
|
|
return ERROR_INVALID_FUNCTION;
|
|
}
|
|
|
|
#ifndef WINNT
|
|
DWORD APIENTRY WNetLogon (LPCTSTR lpProvider, HWND hwndOwner)
|
|
{
|
|
CheckMprLoad;
|
|
return g_pfnWNetLogon (lpProvider, hwndOwner);
|
|
}
|
|
#endif // !WINNT
|
|
|
|
DWORD APIENTRY WNetOpenEnum (DWORD dwScope, DWORD dwType, DWORD dwUsage, LPNETRESOURCE lpNetResource, LPHANDLE lphEnum)
|
|
{
|
|
CheckMprLoad;
|
|
return g_pfnWNetOpenEnum (dwScope, dwType, dwUsage, lpNetResource, lphEnum);
|
|
}
|
|
|
|
DWORD APIENTRY WNetRestoreConnection (HWND hwndParent, LPCTSTR lpDevice)
|
|
{
|
|
CheckMprLoad;
|
|
return g_pfnWNetRestoreConnection (hwndParent, lpDevice);
|
|
}
|
|
|
|
DWORD APIENTRY WNetGetHomeDirectory(LPCTSTR lpProviderName, LPTSTR lpDirectory, LPDWORD lpBufferSize)
|
|
{
|
|
CheckMprLoad;
|
|
return g_pfnWNetGetHomeDirectory (lpProviderName, lpDirectory, lpBufferSize);
|
|
}
|
|
|
|
DWORD APIENTRY WNetGetUser(LPCTSTR lpName, LPTSTR lpUserName, LPDWORD lpnLength)
|
|
{
|
|
CheckMprLoad;
|
|
return g_pfnWNetGetUser (lpName, lpUserName, lpnLength);
|
|
}
|
|
|
|
/////////////////////////////////
|
|
|
|
#ifdef DEBUG
|
|
|
|
LPTSTR DumpPidl(LPITEMIDLIST pidl)
|
|
{
|
|
static TCHAR szBuf[MAX_PATH];
|
|
TCHAR szTmp[MAX_PATH];
|
|
USHORT cb;
|
|
BYTE bFlags;
|
|
LPTSTR pszT;
|
|
|
|
szBuf[0] = TEXT('\0');
|
|
|
|
if (NULL == pidl)
|
|
{
|
|
lstrcat(szBuf, TEXT("Empty pidl"));
|
|
return szBuf;
|
|
}
|
|
|
|
while (!ILIsEmpty(pidl))
|
|
{
|
|
cb = pidl->mkid.cb;
|
|
wsprintf(szTmp, TEXT("size %d"), cb);
|
|
lstrcat(szBuf, szTmp);
|
|
|
|
wsprintf(szTmp, TEXT(", type "));
|
|
lstrcat(szBuf, szTmp);
|
|
|
|
switch (SIL_GetType(pidl) & SHID_TYPEMASK)
|
|
{
|
|
case SHID_ROOT: pszT = TEXT("SHID_ROOT"); break;
|
|
case SHID_ROOT_REGITEM: pszT = TEXT("SHID_ROOT_REGITEM"); break;
|
|
case SHID_COMPUTER: pszT = TEXT("SHID_COMPUTER"); break;
|
|
case SHID_COMPUTER_1: pszT = TEXT("SHID_COMPUTER_1"); break;
|
|
case SHID_COMPUTER_REMOVABLE: pszT = TEXT("SHID_COMPUTER_REMOVABLE"); break;
|
|
case SHID_COMPUTER_FIXED: pszT = TEXT("SHID_COMPUTER_FIXED"); break;
|
|
case SHID_COMPUTER_REMOTE: pszT = TEXT("SHID_COMPUTER_REMOTE"); break;
|
|
case SHID_COMPUTER_CDROM: pszT = TEXT("SHID_COMPUTER_CDROM"); break;
|
|
case SHID_COMPUTER_RAMDISK: pszT = TEXT("SHID_COMPUTER_RAMDISK"); break;
|
|
case SHID_COMPUTER_7: pszT = TEXT("SHID_COMPUTER_7"); break;
|
|
case SHID_COMPUTER_DRIVE525: pszT = TEXT("SHID_COMPUTER_DRIVE525"); break;
|
|
case SHID_COMPUTER_DRIVE35: pszT = TEXT("SHID_COMPUTER_DRIVE35"); break;
|
|
case SHID_COMPUTER_NETDRIVE: pszT = TEXT("SHID_COMPUTER_NETDRIVE"); break;
|
|
case SHID_COMPUTER_NETUNAVAIL: pszT = TEXT("SHID_COMPUTER_NETUNAVAIL"); break;
|
|
case SHID_COMPUTER_C: pszT = TEXT("SHID_COMPUTER_C"); break;
|
|
case SHID_COMPUTER_D: pszT = TEXT("SHID_COMPUTER_D"); break;
|
|
case SHID_COMPUTER_REGITEM: pszT = TEXT("SHID_COMPUTER_REGITEM"); break;
|
|
case SHID_COMPUTER_MISC: pszT = TEXT("SHID_COMPUTER_MISC"); break;
|
|
case SHID_FS: pszT = TEXT("SHID_FS"); break;
|
|
case SHID_FS_TYPEMASK: pszT = TEXT("SHID_FS_TYPEMASK"); break;
|
|
case SHID_FS_DIRECTORY: pszT = TEXT("SHID_FS_DIRECTORY"); break;
|
|
case SHID_FS_FILE: pszT = TEXT("SHID_FS_FILE"); break;
|
|
case SHID_FS_UNICODE: pszT = TEXT("SHID_FS_UNICODE"); break;
|
|
case SHID_FS_DIRUNICODE: pszT = TEXT("SHID_FS_DIRUNICODE"); break;
|
|
case SHID_FS_FILEUNICODE: pszT = TEXT("SHID_FS_FILEUNICODE"); break;
|
|
case SHID_NET: pszT = TEXT("SHID_NET"); break;
|
|
case SHID_NET_DOMAIN: pszT = TEXT("SHID_NET_DOMAIN"); break;
|
|
case SHID_NET_SERVER: pszT = TEXT("SHID_NET_SERVER"); break;
|
|
case SHID_NET_SHARE: pszT = TEXT("SHID_NET_SHARE"); break;
|
|
case SHID_NET_FILE: pszT = TEXT("SHID_NET_FILE"); break;
|
|
case SHID_NET_GROUP: pszT = TEXT("SHID_NET_GROUP"); break;
|
|
case SHID_NET_NETWORK: pszT = TEXT("SHID_NET_NETWORK"); break;
|
|
case SHID_NET_RESTOFNET: pszT = TEXT("SHID_NET_RESTOFNET"); break;
|
|
case SHID_NET_SHAREADMIN: pszT = TEXT("SHID_NET_SHAREADMIN"); break;
|
|
case SHID_NET_DIRECTORY: pszT = TEXT("SHID_NET_DIRECTORY"); break;
|
|
case SHID_NET_TREE: pszT = TEXT("SHID_NET_TREE"); break;
|
|
case SHID_NET_REGITEM: pszT = TEXT("SHID_NET_REGITEM"); break;
|
|
case SHID_NET_PRINTER: pszT = TEXT("SHID_NET_PRINTER"); break;
|
|
default: pszT = TEXT("unknown"); break;
|
|
}
|
|
lstrcat(szBuf, pszT);
|
|
|
|
if (SIL_GetType(pidl) & SHID_JUNCTION)
|
|
{
|
|
lstrcat(szBuf, TEXT(", junction"));
|
|
}
|
|
|
|
pidl = _ILNext(pidl);
|
|
|
|
if (!ILIsEmpty(pidl))
|
|
{
|
|
lstrcat(szBuf, TEXT("; "));
|
|
}
|
|
}
|
|
|
|
return szBuf;
|
|
}
|
|
|
|
#endif // DEBUG
|
|
|
|
#ifdef WINNT
|
|
//
|
|
// pidlRemainder will be filled in (only in the TRUE return case) with a
|
|
// pointer to the part of the IDL (if any) past the remote regitem.
|
|
// This value may be used, for example, to differentiate between a remote
|
|
// printer folder and a printer under a remote printer folder
|
|
//
|
|
|
|
BOOL NET_IsRemoteRegItem(LPCITEMIDLIST pidl, REFCLSID rclsid, LPITEMIDLIST* ppidlRemainder)
|
|
{
|
|
#pragma pack(1)
|
|
typedef struct
|
|
{
|
|
WORD cb;
|
|
BYTE bFlags;
|
|
BYTE bReserved; // This is to get DWORD alignment
|
|
CLSID clsid;
|
|
} IDREGITEM, *LPIDREGITEM;
|
|
|
|
typedef struct
|
|
{
|
|
IDREGITEM idri;
|
|
USHORT cbNext;
|
|
} IDLREGITEM, *LPIDLREGITEM;
|
|
#pragma pack()
|
|
|
|
LPIDLREGITEM pidlitem;
|
|
LPIDREGITEM pitem;
|
|
|
|
if (NULL == pidl)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// check for net hood
|
|
if ((SIL_GetType(pidl) & SHID_TYPEMASK) != SHID_ROOT_REGITEM)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Now, compare to make sure the class id is the reg items.
|
|
// HACKHACK: stole definition from regitms.c !!!!!!!!!!!!!!!!!!!!!
|
|
pidlitem = (LPIDLREGITEM)&c_idlNet;
|
|
pitem = (LPIDREGITEM)&(pidlitem->idri);
|
|
if (!IsEqualCLSID( &(((LPIDREGITEM)pidl)->clsid), &pitem->clsid ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Now, search for a server item. HACKHACK: this assume everything from
|
|
// the NetHood to the server item is a shell pidl with a bFlags field!!
|
|
|
|
pidl = _ILNext(pidl);
|
|
while (!ILIsEmpty(pidl))
|
|
{
|
|
if ((SIL_GetType(pidl) & SHID_TYPEMASK) == SHID_NET_SERVER)
|
|
{
|
|
break;
|
|
}
|
|
pidl = _ILNext(pidl);
|
|
}
|
|
|
|
if (ILIsEmpty(pidl))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Found a server. Is the think after it a remote registry item?
|
|
|
|
pidl = _ILNext(pidl);
|
|
if ((SIL_GetType(pidl) & SHID_TYPEMASK) != SHID_NET_REGITEM)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pitem = (LPIDREGITEM)pidl;
|
|
if (!IsEqualCLSID(rclsid, &pitem->clsid))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
*ppidlRemainder = _ILNext(pidl);
|
|
return TRUE;
|
|
}
|
|
#endif // WINNT
|