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.
395 lines
12 KiB
395 lines
12 KiB
#include "shellprv.h"
|
|
#include "netview.h"
|
|
#include "mtpt.h"
|
|
#include "ids.h"
|
|
|
|
#pragma hdrstop
|
|
|
|
// from mtptarun.cpp
|
|
STDAPI_(void) CMtPt_SetWantUI(int iDrive);
|
|
|
|
//
|
|
// Converts an offset to a string to a string pointer.
|
|
//
|
|
|
|
LPCTSTR _Offset2Ptr(LPTSTR pszBase, UINT_PTR 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;
|
|
}
|
|
|
|
|
|
//
|
|
// exported networking APIs from shell32
|
|
//
|
|
|
|
STDAPI_(UINT) SHGetNetResource(HNRES hnres, UINT iItem, LPNETRESOURCE pnresOut, UINT cbMax)
|
|
{
|
|
UINT iRet = 0; // assume error
|
|
LPNRESARRAY panr = (LPNRESARRAY)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_PTR)panr->nr[iItem].lpProvider, &cbProvider);
|
|
LPCTSTR pszRemoteName = _Offset2Ptr((LPTSTR)panr, (UINT_PTR)panr->nr[iItem].lpRemoteName, &cbRemoteName);
|
|
iRet = sizeof(NETRESOURCE) + cbProvider + cbRemoteName;
|
|
if (iRet <= cbMax)
|
|
{
|
|
DWORD cch;
|
|
LPTSTR psz = (LPTSTR)(pnresOut + 1);
|
|
*pnresOut = panr->nr[iItem];
|
|
if (pnresOut->lpProvider)
|
|
{
|
|
cch = cbProvider / sizeof(TCHAR); // Includes NULL terminator
|
|
|
|
pnresOut->lpProvider = psz;
|
|
StrCpyN(psz, pszProvider, cch);
|
|
psz += cch;
|
|
}
|
|
if (pnresOut->lpRemoteName)
|
|
{
|
|
cch = cbRemoteName / sizeof(TCHAR); // Includes NULL terminator
|
|
pnresOut->lpRemoteName = psz;
|
|
StrCpyN(psz, pszRemoteName, cch);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
iRet = 0; // FAIL if not enough space in the buffer!
|
|
}
|
|
}
|
|
GlobalUnlock(hnres);
|
|
}
|
|
return iRet;
|
|
}
|
|
|
|
|
|
STDAPI_(DWORD) SHNetConnectionDialog(HWND hwnd, LPTSTR pszRemoteName, DWORD dwType)
|
|
{
|
|
CONNECTDLGSTRUCT cds = {0};
|
|
NETRESOURCE nr = {0};
|
|
|
|
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) */
|
|
|
|
nr.dwType = dwType;
|
|
|
|
if (pszRemoteName)
|
|
{
|
|
nr.lpRemoteName = pszRemoteName;
|
|
cds.dwFlags = CONNDLG_RO_PATH;
|
|
}
|
|
DWORD mnr = WNetConnectionDialog1(&cds);
|
|
if (mnr == WN_SUCCESS && dwType != RESOURCETYPE_PRINT && cds.dwDevNum != 0)
|
|
{
|
|
TCHAR szPath[4];
|
|
|
|
CMountPoint::WantAutorunUI(PathBuildRoot(szPath, cds.dwDevNum - 1 /* 1-based! */));
|
|
}
|
|
return mnr;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
HWND hwnd;
|
|
TCHAR szRemoteName[MAX_PATH];
|
|
DWORD dwType;
|
|
} SHNETCONNECT;
|
|
|
|
DWORD CALLBACK _NetConnectThreadProc(void *pv)
|
|
{
|
|
SHNETCONNECT *pshnc = (SHNETCONNECT *)pv;
|
|
HWND hwndDestroy = NULL;
|
|
|
|
if (!pshnc->hwnd)
|
|
{
|
|
RECT rc;
|
|
LPPOINT ppt;
|
|
DWORD pid;
|
|
|
|
// Wild multimon guess - Since we don't have a parent window,
|
|
// we will arbitrarily position ourselves in the same location as
|
|
// the foreground window, if the foreground window belongs to our
|
|
// process.
|
|
HWND hwnd = GetForegroundWindow();
|
|
|
|
if (hwnd &&
|
|
GetWindowThreadProcessId(hwnd, &pid) &&
|
|
(pid == GetCurrentProcessId()) &&
|
|
GetWindowRect(hwnd, &rc))
|
|
{
|
|
// Don't use the upper left corner exactly; slide down by
|
|
// some fudge factor. We definitely want to get past the
|
|
// caption.
|
|
rc.top += GetSystemMetrics(SM_CYCAPTION) * 4;
|
|
rc.left += GetSystemMetrics(SM_CXVSCROLL) * 4;
|
|
ppt = (LPPOINT)&rc;
|
|
}
|
|
else
|
|
{
|
|
ppt = NULL;
|
|
}
|
|
|
|
// Create a stub window so the wizard can establish an Alt+Tab icon
|
|
hwndDestroy = _CreateStubWindow(ppt, NULL);
|
|
pshnc->hwnd = hwndDestroy;
|
|
}
|
|
|
|
SHNetConnectionDialog(pshnc->hwnd, pshnc->szRemoteName[0] ? pshnc->szRemoteName : NULL, pshnc->dwType);
|
|
|
|
if (hwndDestroy)
|
|
DestroyWindow(hwndDestroy);
|
|
|
|
LocalFree(pshnc);
|
|
|
|
SHChangeNotifyHandleEvents();
|
|
return 0;
|
|
}
|
|
|
|
|
|
STDAPI SHStartNetConnectionDialog(HWND hwnd, LPCTSTR pszRemoteName OPTIONAL, DWORD dwType)
|
|
{
|
|
SHNETCONNECT *pshnc = (SHNETCONNECT *)LocalAlloc(LPTR, sizeof(SHNETCONNECT));
|
|
if (pshnc)
|
|
{
|
|
pshnc->hwnd = hwnd;
|
|
pshnc->dwType = dwType;
|
|
if (pszRemoteName)
|
|
StrCpyN(pshnc->szRemoteName, pszRemoteName, ARRAYSIZE(pshnc->szRemoteName));
|
|
|
|
if (!SHCreateThread(_NetConnectThreadProc, pshnc, CTF_PROCESS_REF | CTF_COINIT, NULL))
|
|
{
|
|
LocalFree((HLOCAL)pshnc);
|
|
}
|
|
}
|
|
return S_OK; // whole thing is async, value here is meaningless
|
|
}
|
|
|
|
|
|
#ifdef UNICODE
|
|
|
|
STDAPI SHStartNetConnectionDialogA(HWND hwnd, LPCSTR pszRemoteName, DWORD dwType)
|
|
{
|
|
WCHAR wsz[MAX_PATH];
|
|
|
|
if (pszRemoteName)
|
|
{
|
|
SHAnsiToUnicode(pszRemoteName, wsz, SIZECHARS(wsz));
|
|
pszRemoteName = (LPCSTR)wsz;
|
|
}
|
|
return SHStartNetConnectionDialog(hwnd, (LPCTSTR)pszRemoteName, dwType);
|
|
}
|
|
|
|
#else
|
|
|
|
STDAPI SHStartNetConnectionDialogW(HWND hwnd, LPCWSTR pszRemoteName, DWORD dwType)
|
|
{
|
|
char sz[MAX_PATH];
|
|
|
|
if (pszRemoteName)
|
|
{
|
|
SHUnicodeToAnsi(pszRemoteName, sz, SIZECHARS(sz));
|
|
pszRemoteName = (LPCWSTR)sz;
|
|
}
|
|
|
|
return SHStartNetConnectionDialog(hwnd, (LPCTSTR)pszRemoteName, dwType);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
// These are wrappers around the same WNet APIs, but play with the parameters
|
|
// to make it easier to call. They accept full paths rather than just drive letters.
|
|
//
|
|
DWORD APIENTRY SHWNetDisconnectDialog1 (LPDISCDLGSTRUCT lpConnDlgStruct)
|
|
{
|
|
TCHAR szLocalName[3];
|
|
|
|
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] = 0;
|
|
lpConnDlgStruct->lpLocalName = szLocalName;
|
|
}
|
|
|
|
return WNetDisconnectDialog1 (lpConnDlgStruct);
|
|
}
|
|
|
|
|
|
DWORD APIENTRY SHWNetGetConnection (LPCTSTR lpLocalName, LPTSTR lpRemoteName, LPDWORD lpnLength)
|
|
{
|
|
TCHAR szLocalName[3];
|
|
|
|
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] = 0;
|
|
lpLocalName = szLocalName;
|
|
}
|
|
|
|
return WNetGetConnection (lpLocalName, lpRemoteName, lpnLength);
|
|
}
|
|
|
|
|
|
// exported for netfind.cpp to use
|
|
|
|
STDAPI SHGetDomainWorkgroupIDList(LPITEMIDLIST *ppidl)
|
|
{
|
|
*ppidl = NULL;
|
|
|
|
IShellFolder *psfDesktop;
|
|
HRESULT hr = SHGetDesktopFolder(&psfDesktop);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TCHAR szName[MAX_PATH];
|
|
|
|
StrCpyN(szName, TEXT("\\\\"), ARRAYSIZE(szName));
|
|
|
|
if (RegGetValueString(HKEY_LOCAL_MACHINE,
|
|
TEXT("SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ComputerName"),
|
|
TEXT("ComputerName"), szName + 2, sizeof(szName) - 2 * sizeof(TCHAR)))
|
|
{
|
|
WCHAR wszName[MAX_PATH];
|
|
|
|
SHTCharToUnicode(szName, wszName, ARRAYSIZE(wszName));
|
|
|
|
hr = psfDesktop->ParseDisplayName(NULL, NULL, wszName, NULL, ppidl, NULL);
|
|
if (SUCCEEDED(hr))
|
|
ILRemoveLastID(*ppidl);
|
|
}
|
|
else
|
|
hr = E_FAIL;
|
|
|
|
psfDesktop->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
// SHGetComputerDisplayName - formats and returns the computer name for display.
|
|
|
|
#define REGSTR_PATH_COMPUTERDESCCACHE REGSTR_PATH_EXPLORER TEXT("\\ComputerDescriptions")
|
|
|
|
STDAPI_(void) SHCacheComputerDescription(LPCTSTR pszMachineName, LPCTSTR pszDescription)
|
|
{
|
|
if (pszDescription)
|
|
{
|
|
DWORD cb = (lstrlen(pszDescription) + 1) * sizeof(*pszDescription);
|
|
SHSetValue(HKEY_CURRENT_USER, REGSTR_PATH_COMPUTERDESCCACHE, SkipServerSlashes(pszMachineName), REG_SZ, pszDescription, cb);
|
|
}
|
|
}
|
|
|
|
STDAPI _GetComputerDescription(LPCTSTR pszMachineName, LPTSTR pszDescription, DWORD cchDescription)
|
|
{
|
|
SERVER_INFO_101 *psv101 = NULL;
|
|
HRESULT hr = ResultFromWin32(NetServerGetInfo((LPWSTR)pszMachineName, 101, (BYTE**)&psv101));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (psv101->sv101_comment && psv101->sv101_comment[0])
|
|
{
|
|
StrCpyN(pszDescription, psv101->sv101_comment, cchDescription);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
NetApiBufferFree(psv101);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT _GetCachedComputerDescription(LPCTSTR pszMachineName, LPTSTR pszDescription, int cchDescription)
|
|
{
|
|
ULONG cb = cchDescription*sizeof(*pszDescription);
|
|
return ResultFromWin32(SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_COMPUTERDESCCACHE, SkipServerSlashes(pszMachineName), NULL, pszDescription, &cb));
|
|
}
|
|
|
|
STDAPI SHGetComputerDisplayNameW(LPCWSTR pszMachineName, DWORD dwFlags, LPWSTR pszDisplay, DWORD cchDisplay)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
// map the NULL machine name to the local computer name - so we can cache correctly.
|
|
|
|
WCHAR szMachineName[CNLEN + 1];
|
|
if (!pszMachineName)
|
|
{
|
|
DWORD cchMachine = ARRAYSIZE(szMachineName);
|
|
if (GetComputerName(szMachineName, &cchMachine))
|
|
{
|
|
pszMachineName = szMachineName;
|
|
dwFlags |= SGCDNF_NOCACHEDENTRY;
|
|
}
|
|
}
|
|
|
|
// we must have a machine name, so we can perform the look up.
|
|
|
|
if (pszMachineName)
|
|
{
|
|
WCHAR szDescription[256];
|
|
|
|
// can we read the name from teh cache, if not/or the user says they don't want
|
|
// the cached name then lets hit the wire and read it.
|
|
|
|
if (!(dwFlags & SGCDNF_NOCACHEDENTRY))
|
|
hr = _GetCachedComputerDescription(pszMachineName, szDescription, ARRAYSIZE(szDescription));
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
hr = _GetComputerDescription(pszMachineName, szDescription, ARRAYSIZE(szDescription));
|
|
if (FAILED(hr))
|
|
{
|
|
*szDescription = _TEXT('\0');
|
|
}
|
|
if (!(dwFlags & SGCDNF_NOCACHEDENTRY))
|
|
{
|
|
SHCacheComputerDescription(pszMachineName, szDescription); // write through to cache
|
|
}
|
|
}
|
|
|
|
// we have a name, so lets format it, if they request description only / or we failed
|
|
// above lets just return raw string. otherwise we build a new machine name based
|
|
// on the remote name and the description we fetched.
|
|
|
|
if (SUCCEEDED(hr) && *szDescription)
|
|
{
|
|
if (dwFlags & SGCDNF_DESCRIPTIONONLY)
|
|
{
|
|
StrCpyN(pszDisplay, szDescription, cchDisplay);
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = SHBuildDisplayMachineName(pszMachineName, szDescription, pszDisplay, cchDisplay);
|
|
}
|
|
}
|
|
else if (!(dwFlags & SGCDNF_DESCRIPTIONONLY))
|
|
{
|
|
StrCpyN(pszDisplay, SkipServerSlashes(pszMachineName), cchDisplay);
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|