Source code of Windows XP (NT5)
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.

840 lines
24 KiB

  1. // WizDir.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "shrwiz.h"
  5. #include "WizDir.h"
  6. #include <shlobj.h>
  7. #include "icanon.h"
  8. #include <macfile.h>
  9. #ifdef _DEBUG
  10. #define new DEBUG_NEW
  11. #undef THIS_FILE
  12. static char THIS_FILE[] = __FILE__;
  13. #endif
  14. void OpenBrowseDialog(IN HWND hwndParent, IN LPCTSTR lpszComputer, OUT LPTSTR lpszDir);
  15. BOOL
  16. IsValidLocalAbsolutePath(
  17. IN LPCTSTR lpszPath
  18. );
  19. BOOL
  20. VerifyDirectory(
  21. IN LPCTSTR lpszServer,
  22. IN LPCTSTR lpszDir
  23. );
  24. /////////////////////////////////////////////////////////////////////////////
  25. // CWizFolder property page
  26. IMPLEMENT_DYNCREATE(CWizFolder, CPropertyPage)
  27. CWizFolder::CWizFolder() : CPropertyPage(CWizFolder::IDD)
  28. {
  29. //{{AFX_DATA_INIT(CWizFolder)
  30. // NOTE: the ClassWizard will add member initialization here
  31. //}}AFX_DATA_INIT
  32. }
  33. CWizFolder::~CWizFolder()
  34. {
  35. }
  36. void CWizFolder::DoDataExchange(CDataExchange* pDX)
  37. {
  38. CPropertyPage::DoDataExchange(pDX);
  39. //{{AFX_DATA_MAP(CWizFolder)
  40. // NOTE: the ClassWizard will add DDX and DDV calls here
  41. //}}AFX_DATA_MAP
  42. }
  43. BEGIN_MESSAGE_MAP(CWizFolder, CPropertyPage)
  44. //{{AFX_MSG_MAP(CWizFolder)
  45. ON_BN_CLICKED(IDC_BROWSEFOLDER, OnBrowsefolder)
  46. ON_BN_CLICKED(IDC_CHECK_MAC, OnCheckMac)
  47. ON_BN_CLICKED(IDC_CHECK_MS, OnCheckMs)
  48. ON_BN_CLICKED(IDC_CHECK_NETWARE, OnCheckNetware)
  49. ON_EN_CHANGE(IDC_SHARENAME, OnChangeSharename)
  50. //}}AFX_MSG_MAP
  51. ON_MESSAGE(WM_SETPAGEFOCUS, OnSetPageFocus)
  52. END_MESSAGE_MAP()
  53. /////////////////////////////////////////////////////////////////////////////
  54. // CWizFolder message handlers
  55. #define SHARE_NAME_LIMIT NNLEN
  56. #define SFM_SHARE_NAME_LIMIT AFP_VOLNAME_LEN
  57. #define SHARE_DESCRIPTION_LIMIT MAXCOMMENTSZ
  58. BOOL CWizFolder::OnInitDialog()
  59. {
  60. CPropertyPage::OnInitDialog();
  61. GetDlgItem(IDC_FOLDER)->SendMessage(EM_LIMITTEXT, _MAX_DIR - 1, 0);
  62. GetDlgItem(IDC_SHARENAME)->SendMessage(EM_LIMITTEXT, SHARE_NAME_LIMIT, 0);
  63. GetDlgItem(IDC_MACSHARENAME)->SendMessage(EM_LIMITTEXT, SFM_SHARE_NAME_LIMIT, 0);
  64. GetDlgItem(IDC_SHAREDESCRIPTION)->SendMessage(EM_LIMITTEXT, SHARE_DESCRIPTION_LIMIT, 0);
  65. return TRUE; // return TRUE unless you set the focus to a control
  66. // EXCEPTION: OCX Property Pages should return FALSE
  67. }
  68. LRESULT CWizFolder::OnWizardNext()
  69. {
  70. CWaitCursor wait;
  71. Reset(); // init all related place holders
  72. CShrwizApp *pApp = (CShrwizApp *)AfxGetApp();
  73. pApp->m_bSMB = (1 == ((CButton *)GetDlgItem(IDC_CHECK_MS))->GetCheck());
  74. pApp->m_bFPNW = (1 == ((CButton *)GetDlgItem(IDC_CHECK_NETWARE))->GetCheck());
  75. pApp->m_bSFM = (1 == ((CButton *)GetDlgItem(IDC_CHECK_MAC))->GetCheck());
  76. if (!pApp->m_bSMB && !pApp->m_bFPNW && !pApp->m_bSFM)
  77. {
  78. DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_CLIENT_REQUIRED);
  79. GetDlgItem(IDC_CHECK_MS)->SetFocus();
  80. return -1;
  81. }
  82. CString cstrFolder;
  83. GetDlgItemText(IDC_FOLDER, cstrFolder);
  84. cstrFolder.TrimLeft();
  85. cstrFolder.TrimRight();
  86. if (cstrFolder.IsEmpty())
  87. {
  88. CString cstrField;
  89. cstrField.LoadString(IDS_FOLDER_LABEL);
  90. DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_TEXT_REQUIRED, cstrField);
  91. GetDlgItem(IDC_FOLDER)->SetFocus();
  92. return -1;
  93. }
  94. // Removing the ending backslash, otherwise, GetFileAttribute/NetShareAdd will fail.
  95. if (!IsValidLocalAbsolutePath(cstrFolder))
  96. {
  97. DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_INVALID_FOLDER);
  98. GetDlgItem(IDC_FOLDER)->SetFocus();
  99. return -1;
  100. } else
  101. {
  102. int iLen = cstrFolder.GetLength();
  103. if (cstrFolder[iLen - 1] == _T('\\') &&
  104. cstrFolder[iLen - 2] != _T(':'))
  105. cstrFolder.SetAt(iLen - 1, _T('\0'));
  106. }
  107. if (!VerifyDirectory(pApp->m_cstrTargetComputer, cstrFolder))
  108. {
  109. GetDlgItem(IDC_FOLDER)->SetFocus();
  110. return -1;
  111. }
  112. pApp->m_cstrFolder = cstrFolder;
  113. DWORD dwStatus = 0;
  114. if (pApp->m_bSMB || pApp->m_bFPNW)
  115. {
  116. CString cstrShareName;
  117. GetDlgItemText(IDC_SHARENAME, cstrShareName);
  118. cstrShareName.TrimLeft();
  119. cstrShareName.TrimRight();
  120. if (cstrShareName.IsEmpty())
  121. {
  122. CString cstrField;
  123. cstrField.LoadString(IDS_SHARENAME_LABEL);
  124. DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_TEXT_REQUIRED, cstrField);
  125. GetDlgItem(IDC_SHARENAME)->SetFocus();
  126. return -1;
  127. }
  128. dwStatus = I_NetNameValidate(
  129. const_cast<LPTSTR>(static_cast<LPCTSTR>(pApp->m_cstrTargetComputer)),
  130. const_cast<LPTSTR>(static_cast<LPCTSTR>(cstrShareName)),
  131. NAMETYPE_SHARE,
  132. 0);
  133. if (dwStatus)
  134. {
  135. DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_INVALID_SHARENAME, cstrShareName);
  136. GetDlgItem(IDC_SHARENAME)->SetFocus();
  137. return -1;
  138. }
  139. if (pApp->m_bSMB && ShareNameExists(cstrShareName, CLIENT_TYPE_SMB) ||
  140. pApp->m_bFPNW && ShareNameExists(cstrShareName, CLIENT_TYPE_FPNW))
  141. {
  142. DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_DUPLICATE_SHARENAME, cstrShareName);
  143. GetDlgItem(IDC_SHARENAME)->SetFocus();
  144. return -1;
  145. }
  146. pApp->m_cstrShareName = cstrShareName;
  147. }
  148. if (pApp->m_bSMB)
  149. {
  150. CString cstrShareDescription;
  151. GetDlgItemText(IDC_SHAREDESCRIPTION, cstrShareDescription);
  152. cstrShareDescription.TrimLeft();
  153. cstrShareDescription.TrimRight();
  154. pApp->m_cstrShareDescription = cstrShareDescription;
  155. }
  156. if (pApp->m_bSFM)
  157. {
  158. CString cstrMACShareName;
  159. GetDlgItemText(IDC_MACSHARENAME, cstrMACShareName);
  160. cstrMACShareName.TrimLeft();
  161. cstrMACShareName.TrimRight();
  162. if (cstrMACShareName.IsEmpty())
  163. {
  164. CString cstrField;
  165. cstrField.LoadString(IDS_MACSHARENAME_LABEL);
  166. DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_TEXT_REQUIRED, cstrField);
  167. GetDlgItem(IDC_MACSHARENAME)->SetFocus();
  168. return -1;
  169. } else
  170. {
  171. dwStatus = I_NetNameValidate(
  172. const_cast<LPTSTR>(static_cast<LPCTSTR>(pApp->m_cstrTargetComputer)),
  173. const_cast<LPTSTR>(static_cast<LPCTSTR>(cstrMACShareName)),
  174. NAMETYPE_SHARE,
  175. 0);
  176. if (dwStatus)
  177. {
  178. DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_INVALID_SHARENAME, cstrMACShareName);
  179. GetDlgItem(IDC_MACSHARENAME)->SetFocus();
  180. return -1;
  181. }
  182. }
  183. if (ShareNameExists(cstrMACShareName, CLIENT_TYPE_SFM))
  184. {
  185. DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_DUPLICATE_SHARENAME, cstrMACShareName);
  186. GetDlgItem(IDC_MACSHARENAME)->SetFocus();
  187. return -1;
  188. }
  189. pApp->m_cstrMACShareName = cstrMACShareName;
  190. }
  191. pApp->m_bNextButtonClicked = TRUE;
  192. return CPropertyPage::OnWizardNext();
  193. }
  194. void CWizFolder::OnBrowsefolder()
  195. {
  196. CShrwizApp *pApp = (CShrwizApp *)AfxGetApp();
  197. LPTSTR lpszComputer = const_cast<LPTSTR>(static_cast<LPCTSTR>(pApp->m_cstrTargetComputer));
  198. CString cstrPath;
  199. TCHAR szDir[MAX_PATH * 2] = _T(""); // double the size in case the remote path is itself close to MAX_PATH
  200. OpenBrowseDialog(m_hWnd, lpszComputer, szDir);
  201. if (szDir[0])
  202. {
  203. if (pApp->m_bIsLocal)
  204. cstrPath = szDir;
  205. else
  206. { // szDir is in the form of \\server\share or \\server\share\path....
  207. LPTSTR pShare = _tcschr(szDir + 2, _T('\\'));
  208. pShare++;
  209. LPTSTR pLeftOver = _tcschr(pShare, _T('\\'));
  210. if (pLeftOver && *pLeftOver)
  211. *pLeftOver++ = _T('\0');
  212. SHARE_INFO_2 *psi = NULL;
  213. if (NERR_Success == NetShareGetInfo(lpszComputer, pShare, 2, (LPBYTE *)&psi))
  214. {
  215. cstrPath = psi->shi2_path;
  216. if (pLeftOver && *pLeftOver)
  217. {
  218. if (_T('\\') != cstrPath.Right(1))
  219. cstrPath += _T('\\');
  220. cstrPath += pLeftOver;
  221. }
  222. NetApiBufferFree(psi);
  223. }
  224. }
  225. }
  226. if (!cstrPath.IsEmpty())
  227. SetDlgItemText(IDC_FOLDER, cstrPath);
  228. }
  229. void CWizFolder::OnCheckClient()
  230. {
  231. BOOL bSMB = (1 == ((CButton *)GetDlgItem(IDC_CHECK_MS))->GetCheck());
  232. BOOL bFPNW = (1 == ((CButton *)GetDlgItem(IDC_CHECK_NETWARE))->GetCheck());
  233. BOOL bSFM = (1 == ((CButton *)GetDlgItem(IDC_CHECK_MAC))->GetCheck());
  234. GetDlgItem(IDC_SHARENAME)->EnableWindow(bSMB || bFPNW);
  235. if (!bSMB && !bFPNW)
  236. SetDlgItemText(IDC_SHARENAME, _T(""));
  237. GetDlgItem(IDC_SHAREDESCRIPTION)->EnableWindow(bSMB);
  238. if (!bSMB)
  239. SetDlgItemText(IDC_SHAREDESCRIPTION, _T(""));
  240. GetDlgItem(IDC_MACSHARENAME)->EnableWindow(bSFM);
  241. if (!bSFM)
  242. SetDlgItemText(IDC_MACSHARENAME, _T(""));
  243. }
  244. void CWizFolder::OnCheckMac()
  245. {
  246. OnCheckClient();
  247. if (1 == ((CButton *)GetDlgItem(IDC_CHECK_MAC))->GetCheck())
  248. {
  249. CString cstrShareName;
  250. GetDlgItemText(IDC_SHARENAME, cstrShareName);
  251. SetDlgItemText(IDC_MACSHARENAME, cstrShareName.Left(SFM_SHARE_NAME_LIMIT));
  252. }
  253. }
  254. void CWizFolder::OnCheckMs()
  255. {
  256. OnCheckClient();
  257. }
  258. void CWizFolder::OnCheckNetware()
  259. {
  260. OnCheckClient();
  261. }
  262. void CWizFolder::OnChangeSharename()
  263. {
  264. BOOL bSMB = (1 == ((CButton *)GetDlgItem(IDC_CHECK_MS))->GetCheck());
  265. BOOL bFPNW = (1 == ((CButton *)GetDlgItem(IDC_CHECK_NETWARE))->GetCheck());
  266. BOOL bSFM = (1 == ((CButton *)GetDlgItem(IDC_CHECK_MAC))->GetCheck());
  267. if ((bSMB || bFPNW) && bSFM)
  268. {
  269. CString cstrShareName;
  270. GetDlgItemText(IDC_SHARENAME, cstrShareName);
  271. SetDlgItemText(IDC_MACSHARENAME, cstrShareName.Left(SFM_SHARE_NAME_LIMIT));
  272. }
  273. }
  274. BOOL CWizFolder::OnSetActive()
  275. {
  276. ((CPropertySheet *)GetParent())->SetWizardButtons(PSWIZB_NEXT);
  277. CShrwizApp *pApp = (CShrwizApp *)AfxGetApp();
  278. if (pApp->m_bNextButtonClicked)
  279. {
  280. SetDlgItemText(IDC_COMPUTER, pApp->m_cstrTargetComputer);
  281. SetDlgItemText(IDC_FOLDER, pApp->m_cstrFolder);
  282. SetDlgItemText(IDC_SHARENAME, pApp->m_cstrShareName);
  283. SetDlgItemText(IDC_SHAREDESCRIPTION, pApp->m_cstrShareDescription);
  284. SetDlgItemText(IDC_SHARENAME_MAC, pApp->m_cstrMACShareName);
  285. CheckDlgButton(IDC_CHECK_MS, 1);
  286. CheckDlgButton(IDC_CHECK_NETWARE, 0);
  287. CheckDlgButton(IDC_CHECK_MAC, 0);
  288. OnCheckMs();
  289. GetDlgItem(IDC_CHECK_NETWARE)->EnableWindow(pApp->m_bServerFPNW);
  290. GetDlgItem(IDC_CHECK_MAC)->EnableWindow(pApp->m_bServerSFM);
  291. GetDlgItem(IDC_MACSHARENAME_STATIC)->ShowWindow(pApp->m_bServerSFM ? SW_SHOW : SW_HIDE);
  292. GetDlgItem(IDC_SHARENAME_MAC)->ShowWindow(pApp->m_bServerSFM ? SW_SHOW : SW_HIDE);
  293. if (!(pApp->m_bServerFPNW) && !(pApp->m_bServerSFM))
  294. {
  295. // hide the whole group if only SMB
  296. GetDlgItem(IDC_CLIENTS_GROUP)->ShowWindow(SW_HIDE);
  297. GetDlgItem(IDC_CHECK_MS)->EnableWindow(FALSE);
  298. GetDlgItem(IDC_CHECK_MS)->ShowWindow(SW_HIDE);
  299. GetDlgItem(IDC_CHECK_NETWARE)->ShowWindow(SW_HIDE);
  300. GetDlgItem(IDC_CHECK_MAC)->ShowWindow(SW_HIDE);
  301. } else
  302. {
  303. GetDlgItem(IDC_CLIENTS_GROUP)->ShowWindow(SW_SHOW);
  304. GetDlgItem(IDC_CHECK_MS)->EnableWindow(TRUE);
  305. GetDlgItem(IDC_CHECK_MS)->ShowWindow(SW_SHOW);
  306. GetDlgItem(IDC_CHECK_NETWARE)->ShowWindow(SW_SHOW);
  307. GetDlgItem(IDC_CHECK_MAC)->ShowWindow(SW_SHOW);
  308. }
  309. } else
  310. {
  311. CheckDlgButton(IDC_CHECK_MS, pApp->m_bSMB);
  312. CheckDlgButton(IDC_CHECK_NETWARE, pApp->m_bFPNW);
  313. CheckDlgButton(IDC_CHECK_MAC, pApp->m_bSFM);
  314. OnCheckClient();
  315. }
  316. BOOL fRet = CPropertyPage::OnSetActive();
  317. PostMessage(WM_SETPAGEFOCUS, 0, 0L);
  318. return fRet;
  319. }
  320. //
  321. // Q148388 How to Change Default Control Focus on CPropertyPage
  322. //
  323. LRESULT CWizFolder::OnSetPageFocus(WPARAM wParam, LPARAM lParam)
  324. {
  325. GetDlgItem(IDC_FOLDER)->SetFocus();
  326. return 0;
  327. }
  328. BOOL CWizFolder::ShareNameExists(IN LPCTSTR lpszShareName, IN CLIENT_TYPE iType)
  329. {
  330. BOOL bReturn = FALSE;
  331. CShrwizApp *pApp = (CShrwizApp *)AfxGetApp();
  332. switch (iType)
  333. {
  334. case CLIENT_TYPE_SMB:
  335. {
  336. bReturn = SMBShareNameExists(pApp->m_cstrTargetComputer, lpszShareName);
  337. break;
  338. }
  339. case CLIENT_TYPE_FPNW:
  340. {
  341. ASSERT(pApp->m_hLibFPNW);
  342. bReturn = FPNWShareNameExists(pApp->m_cstrTargetComputer, lpszShareName, pApp->m_hLibFPNW);
  343. break;
  344. }
  345. case CLIENT_TYPE_SFM:
  346. {
  347. ASSERT(pApp->m_hLibSFM);
  348. bReturn = SFMShareNameExists(pApp->m_cstrTargetComputer, lpszShareName, pApp->m_hLibSFM);
  349. break;
  350. }
  351. default:
  352. break;
  353. }
  354. return bReturn;
  355. }
  356. void CWizFolder::Reset()
  357. {
  358. CShrwizApp *pApp = (CShrwizApp *)AfxGetApp();
  359. pApp->m_cstrFolder.Empty();
  360. pApp->m_cstrShareName.Empty();
  361. pApp->m_cstrShareDescription.Empty();
  362. pApp->m_cstrMACShareName.Empty();
  363. pApp->m_bSMB = FALSE;
  364. pApp->m_bFPNW = FALSE;
  365. pApp->m_bSFM = FALSE;
  366. }
  367. ////////////////////////////////////////////////////////////
  368. // OpenBrowseDialog
  369. //
  370. //
  371. // 7/11/2001 LinanT bug#426953
  372. // Since connection made by Terminal Service may bring some client side resources
  373. // (disks, serial ports, etc.) into "My Computer" namespace, we want to disable
  374. // the OK button when browsing to a non-local folder. We don't have this problem
  375. // when browsing a remote machine.
  376. //
  377. typedef struct _LOCAL_DISKS
  378. {
  379. LPTSTR pszDisks;
  380. DWORD dwNumOfDisks;
  381. } LOCAL_DISKS;
  382. #define DISK_ENTRY_LENGTH 3 // Drive letter, colon, NULL
  383. #define DISK_NAME_LENGTH 2 // Drive letter, colon
  384. BOOL InDiskList(IN LPCTSTR pszDir, IN LOCAL_DISKS *pDisks)
  385. {
  386. if (!pszDir || !pDisks)
  387. return FALSE;
  388. DWORD i = 0;
  389. PTSTR pszDisk = pDisks->pszDisks;
  390. for (; pszDisk && i < pDisks->dwNumOfDisks; i++)
  391. {
  392. if (!_tcsnicmp(pszDisk, pszDir, DISK_NAME_LENGTH))
  393. return TRUE;
  394. pszDisk += DISK_ENTRY_LENGTH;
  395. }
  396. return FALSE;
  397. }
  398. int CALLBACK
  399. BrowseCallbackProc(
  400. IN HWND hwnd,
  401. IN UINT uMsg,
  402. IN LPARAM lp,
  403. IN LPARAM pData
  404. )
  405. {
  406. switch(uMsg) {
  407. case BFFM_SELCHANGED:
  408. {
  409. // enable the OK button if the selected path is local to that computer.
  410. BOOL bEnableOK = FALSE;
  411. TCHAR szDir[MAX_PATH];
  412. if (SHGetPathFromIDList((LPITEMIDLIST) lp ,szDir))
  413. {
  414. if (pData)
  415. {
  416. // we're looking at a local computer, verify if szDir is on a local disk
  417. bEnableOK = InDiskList(szDir, (LOCAL_DISKS *)pData);
  418. } else
  419. {
  420. // no such problem when browsing at a remote computer, always enable OK button.
  421. bEnableOK = TRUE;
  422. }
  423. }
  424. SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM)bEnableOK);
  425. break;
  426. }
  427. default:
  428. break;
  429. }
  430. return 0;
  431. }
  432. void OpenBrowseDialog(IN HWND hwndParent, IN LPCTSTR lpszComputer, OUT LPTSTR lpszDir)
  433. {
  434. ASSERT(lpszComputer && *lpszComputer);
  435. HRESULT hr = S_OK;
  436. LOCAL_DISKS localDisks = {0};
  437. CString cstrComputer;
  438. if (*lpszComputer != _T('\\') || *(lpszComputer + 1) != _T('\\'))
  439. {
  440. cstrComputer = _T("\\\\");
  441. cstrComputer += lpszComputer;
  442. } else
  443. {
  444. cstrComputer = lpszComputer;
  445. }
  446. hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  447. if (SUCCEEDED(hr))
  448. {
  449. LPMALLOC pMalloc;
  450. hr = SHGetMalloc(&pMalloc);
  451. if (SUCCEEDED(hr))
  452. {
  453. LPSHELLFOLDER pDesktopFolder;
  454. hr = SHGetDesktopFolder(&pDesktopFolder);
  455. if (SUCCEEDED(hr))
  456. {
  457. LPITEMIDLIST pidlRoot;
  458. if (IsLocalComputer(lpszComputer))
  459. {
  460. hr = SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidlRoot);
  461. if (SUCCEEDED(hr))
  462. {
  463. //
  464. // 7/11/2001 LinanT bug#426953
  465. // Since connection made by Terminal Service may bring some client side resources
  466. // (disks, serial ports, etc.) into "My Computer" namespace, we want to disable
  467. // the OK button when browsing to a non-local folder. We don't have this problem
  468. // when browsing a remote machine.
  469. //
  470. //
  471. // Get an array of local disk names, this information is later used
  472. // in the browse dialog to disable OK button if non-local path is selected.
  473. //
  474. DWORD dwTotalEntries = 0;
  475. DWORD nStatus = NetServerDiskEnum(
  476. NULL, // local computer
  477. 0, // level must be zero
  478. (LPBYTE *)&(localDisks.pszDisks),
  479. -1, // dwPrefMaxLen,
  480. &(localDisks.dwNumOfDisks),
  481. &dwTotalEntries,
  482. NULL);
  483. if (NERR_Success != nStatus)
  484. {
  485. hr = HRESULT_FROM_WIN32(nStatus);
  486. }
  487. }
  488. } else
  489. {
  490. ULONG chEaten = 0;
  491. hr = pDesktopFolder->ParseDisplayName(NULL, NULL,
  492. const_cast<LPTSTR>(static_cast<LPCTSTR>(cstrComputer)),
  493. &chEaten, &pidlRoot, NULL);
  494. }
  495. if (SUCCEEDED(hr))
  496. {
  497. CString cstrLabel;
  498. cstrLabel.LoadString(IDS_BROWSE_FOLDER);
  499. BROWSEINFO bi;
  500. ZeroMemory(&bi,sizeof(bi));
  501. bi.hwndOwner = hwndParent;
  502. bi.pszDisplayName = 0;
  503. bi.lpszTitle = cstrLabel;
  504. bi.pidlRoot = pidlRoot;
  505. bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_SHAREABLE | BIF_USENEWUI;
  506. bi.lpfn = BrowseCallbackProc;
  507. if (localDisks.pszDisks)
  508. bi.lParam = (LPARAM)&localDisks; // pass the structure to the browse dialog
  509. LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
  510. if (pidl) {
  511. SHGetPathFromIDList(pidl, lpszDir);
  512. pMalloc->Free(pidl);
  513. }
  514. pMalloc->Free(pidlRoot);
  515. }
  516. pDesktopFolder->Release();
  517. }
  518. pMalloc->Release();
  519. }
  520. CoUninitialize();
  521. }
  522. if (localDisks.pszDisks)
  523. NetApiBufferFree(localDisks.pszDisks);
  524. if (FAILED(hr))
  525. DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONWARNING, hr, IDS_CANNOT_BROWSE_FOLDER, lpszComputer);
  526. }
  527. BOOL
  528. IsValidLocalAbsolutePath(
  529. IN LPCTSTR lpszPath
  530. )
  531. {
  532. DWORD dwPathType = 0;
  533. DWORD dwStatus = I_NetPathType(
  534. NULL,
  535. const_cast<LPTSTR>(lpszPath),
  536. &dwPathType,
  537. 0);
  538. if (dwStatus)
  539. return FALSE;
  540. if (dwPathType ^ ITYPE_PATH_ABSD)
  541. return FALSE;
  542. return TRUE;
  543. }
  544. //+---------------------------------------------------------------------------
  545. //
  546. // Function: IsAnExistingFolder
  547. //
  548. // Synopsis: Check if pszPath is pointing at an existing folder.
  549. //
  550. // S_OK: The specified path points to an existing folder.
  551. // S_FALSE: The specified path doesn't point to an existing folder.
  552. // hr: Failed to get info on the specified path, or
  553. // the path exists but doesn't point to a folder.
  554. // The function reports error msg for both failures if desired.
  555. //----------------------------------------------------------------------------
  556. HRESULT
  557. IsAnExistingFolder(
  558. IN HWND hwnd,
  559. IN LPCTSTR pszPath,
  560. IN BOOL bDisplayErrorMsg
  561. )
  562. {
  563. if (!hwnd)
  564. hwnd = GetActiveWindow();
  565. HRESULT hr = S_OK;
  566. DWORD dwRet = GetFileAttributes(pszPath);
  567. if (-1 == dwRet)
  568. {
  569. DWORD dwErr = GetLastError();
  570. if (ERROR_PATH_NOT_FOUND == dwErr || ERROR_FILE_NOT_FOUND == dwErr)
  571. {
  572. // the specified path doesn't exist
  573. hr = S_FALSE;
  574. }
  575. else
  576. {
  577. hr = HRESULT_FROM_WIN32(dwErr);
  578. if (ERROR_NOT_READY == dwErr)
  579. {
  580. // fix for bug#358033/408803: ignore errors from GetFileAttributes in order to
  581. // allow the root of movable drives to be shared without media inserted in.
  582. int len = _tcslen(pszPath);
  583. if (len > 3 &&
  584. pszPath[len - 1] == _T('\\') &&
  585. pszPath[len - 2] == _T(':'))
  586. {
  587. // pszPath is pointing at the root of the drive, ignore the error
  588. hr = S_OK;
  589. }
  590. }
  591. if ( FAILED(hr) && bDisplayErrorMsg )
  592. DisplayMessageBox(hwnd, MB_OK, dwErr, IDS_FAILED_TO_GETINFO_FOLDER, pszPath);
  593. }
  594. } else if ( 0 == (dwRet & FILE_ATTRIBUTE_DIRECTORY) )
  595. {
  596. // the specified path is not pointing to a folder
  597. if (bDisplayErrorMsg)
  598. DisplayMessageBox(hwnd, MB_OK|MB_ICONERROR, 0, IDS_PATH_NOT_FOLDER, pszPath);
  599. hr = E_FAIL;
  600. }
  601. return hr;
  602. }
  603. // create the directories layer by layer
  604. HRESULT
  605. CreateLayeredDirectory(
  606. IN LPCTSTR lpszServer,
  607. IN LPCTSTR lpszDir
  608. )
  609. {
  610. ASSERT(IsValidLocalAbsolutePath(lpszDir));
  611. BOOL bLocal = IsLocalComputer(lpszServer);
  612. CString cstrFullPath;
  613. GetFullPath(lpszServer, lpszDir, cstrFullPath);
  614. // add prefix to skip the CreateDirectory limit of 248 chars
  615. CString cstrFullPathNoParsing = (bLocal ? _T("\\\\?\\") : _T("\\\\?\\UNC"));
  616. cstrFullPathNoParsing += (bLocal ? cstrFullPath : cstrFullPath.Right(cstrFullPath.GetLength() - 1));
  617. HRESULT hr = IsAnExistingFolder(NULL, cstrFullPathNoParsing, FALSE);
  618. ASSERT(S_FALSE == hr);
  619. LPTSTR pch = _tcschr(cstrFullPathNoParsing, (bLocal ? _T(':') : _T('$')));
  620. ASSERT(pch);
  621. // pszPath holds "\\?\C:\a\b\c\d" or "\\?\UNC\server\share\a\b\c\d"
  622. // pszLeft holds "a\b\c\d"
  623. LPTSTR pszPath = const_cast<LPTSTR>(static_cast<LPCTSTR>(cstrFullPathNoParsing));
  624. LPTSTR pszLeft = pch + 2;
  625. LPTSTR pszRight = NULL;
  626. ASSERT(pszLeft && *pszLeft);
  627. //
  628. // this loop will find out the 1st non-existing sub-dir to create, and
  629. // the rest of non-existing sub-dirs
  630. //
  631. while (pch = _tcsrchr(pszLeft, _T('\\'))) // backwards search for _T('\\')
  632. {
  633. *pch = _T('\0');
  634. hr = IsAnExistingFolder(NULL, pszPath, TRUE);
  635. if (FAILED(hr))
  636. return S_FALSE; // errormsg has already been reported by IsAnExistingFolder().
  637. if (S_OK == hr)
  638. {
  639. //
  640. // pszPath is pointing to the parent dir of the 1st non-existing sub-dir.
  641. // Once we restore the _T('\\'), pszPath will point at the 1st non-existing subdir.
  642. //
  643. *pch = _T('\\');
  644. break;
  645. } else
  646. {
  647. //
  648. // pszPath is pointing to a non-existing folder, continue with the loop.
  649. //
  650. if (pszRight)
  651. *(pszRight - 1) = _T('\\');
  652. pszRight = pch + 1;
  653. }
  654. }
  655. // We're ready to create directories:
  656. // pszPath points to the 1st non-existing dir, e.g., "C:\a\b" or "\\server\share\a\b"
  657. // pszRight points to the rest of non-existing sub dirs, e.g., "c\d"
  658. //
  659. do
  660. {
  661. if (!CreateDirectory(pszPath, NULL))
  662. return HRESULT_FROM_WIN32(GetLastError());
  663. if (!pszRight || !*pszRight)
  664. break;
  665. *(pszRight - 1) = _T('\\');
  666. if (pch = _tcschr(pszRight, _T('\\'))) // forward search for _T('\\')
  667. {
  668. *pch = _T('\0');
  669. pszRight = pch + 1;
  670. } else
  671. {
  672. pszRight = NULL;
  673. }
  674. } while (1);
  675. return S_OK;
  676. }
  677. BOOL
  678. VerifyDirectory(
  679. IN LPCTSTR lpszServer,
  680. IN LPCTSTR lpszDir
  681. )
  682. {
  683. ASSERT(lpszDir && *lpszDir);
  684. ASSERT(IsValidLocalAbsolutePath(lpszDir));
  685. HWND hwnd = ::GetActiveWindow();
  686. BOOL bLocal = IsLocalComputer(lpszServer);
  687. HRESULT hr = VerifyDriveLetter(lpszServer, lpszDir);
  688. if (FAILED(hr))
  689. { /*
  690. // fix for bug#351212: ignore error and leave permission checkings to NetShareAdd apis
  691. DisplayMessageBox(hwnd, MB_OK, hr, IDS_FAILED_TO_VALIDATE_FOLDER, lpszDir);
  692. return FALSE;
  693. */
  694. hr = S_OK;
  695. } else if (S_OK != hr)
  696. {
  697. DisplayMessageBox(hwnd, MB_OK|MB_ICONERROR, 0, IDS_INVALID_DRIVE, lpszDir);
  698. return FALSE;
  699. }
  700. if (!bLocal)
  701. {
  702. hr = IsAdminShare(lpszServer, lpszDir);
  703. if (FAILED(hr))
  704. {
  705. DisplayMessageBox(hwnd, MB_OK|MB_ICONERROR, hr, IDS_FAILED_TO_VALIDATE_FOLDER, lpszDir);
  706. return FALSE;
  707. } else if (S_OK != hr)
  708. {
  709. // there is no matching $ shares, hence, no need to call GetFileAttribute, CreateDirectory,
  710. // assume lpszDir points to an existing directory
  711. return TRUE;
  712. }
  713. }
  714. CString cstrPath;
  715. GetFullPath(lpszServer, lpszDir, cstrPath);
  716. // add prefix to skip the GetFileAttribute limit when the path is on a remote server
  717. CString cstrPathNoParsing = (bLocal ? _T("\\\\?\\") : _T("\\\\?\\UNC"));
  718. cstrPathNoParsing += (bLocal ? cstrPath : cstrPath.Right(cstrPath.GetLength() - 1));
  719. hr = IsAnExistingFolder(hwnd, cstrPathNoParsing, TRUE); // error has already been reported.
  720. if (FAILED(hr) || S_OK == hr)
  721. return (S_OK == hr);
  722. if ( IDYES != DisplayMessageBox(hwnd, MB_YESNO|MB_ICONQUESTION, 0, IDS_CREATE_NEW_DIR, cstrPath) )
  723. return FALSE;
  724. // create the directories layer by layer
  725. hr = CreateLayeredDirectory(lpszServer, lpszDir);
  726. if (FAILED(hr))
  727. DisplayMessageBox(hwnd, MB_OK|MB_ICONERROR, hr, IDS_FAILED_TO_CREATE_NEW_DIR, cstrPath);
  728. return (S_OK == hr);
  729. }