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.

744 lines
21 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1996 - 1999
  6. //
  7. // File: owner.cpp
  8. //
  9. // This file contains the implementation of the Owner page.
  10. //
  11. //--------------------------------------------------------------------------
  12. #include "aclpriv.h"
  13. #include "sddl.h" // ConvertSidToStringSid
  14. //
  15. // Context Help IDs.
  16. //
  17. const static DWORD aOwnerHelpIDs[] =
  18. {
  19. IDC_OWN_CURRENTOWNER_STATIC, IDH_OWN_CURRENTOWNER,
  20. IDC_OWN_CURRENTOWNER, IDH_OWN_CURRENTOWNER,
  21. IDC_OWN_OWNERLIST_STATIC, IDH_OWN_OWNERLIST,
  22. IDC_OWN_OWNERLIST, IDH_OWN_OWNERLIST,
  23. IDC_OWN_RECURSE, IDH_OWN_RECURSE,
  24. IDC_OWN_RESET, IDH_OWN_RESET,
  25. IDC_ACEL_STATIC, -1,
  26. 0, 0
  27. };
  28. //
  29. // These SIDs are always added to the list of possible owners
  30. //
  31. const static UI_TokenSid g_uiTokenSids[] =
  32. {
  33. UI_TSID_CurrentProcessUser,
  34. UI_TSID_CurrentProcessOwner,
  35. //UI_TSID_CurrentProcessPrimaryGroup,
  36. };
  37. class COwnerPage : public CSecurityPage
  38. {
  39. private:
  40. PSID m_psidOriginal;
  41. PSID m_psidNetID;
  42. HANDLE m_hSidThread;
  43. public:
  44. COwnerPage(LPSECURITYINFO psi, SI_OBJECT_INFO *psiObjectInfo);
  45. virtual ~COwnerPage(void);
  46. private:
  47. virtual BOOL DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  48. void InitDlg(HWND hDlg);
  49. int AddSid(HWND hOwner, PSID psid, LPCTSTR pszServerName = NULL);
  50. void OnApply(HWND hDlg, BOOL bClose);
  51. void OnReset(HWND hDlg);
  52. };
  53. HPROPSHEETPAGE
  54. CreateOwnerPage(LPSECURITYINFO psi, SI_OBJECT_INFO *psiObjectInfo)
  55. {
  56. HPROPSHEETPAGE hPage = NULL;
  57. COwnerPage *pPage;
  58. TraceEnter(TRACE_OWNER, "CreateOwnerPage");
  59. pPage = new COwnerPage(psi, psiObjectInfo);
  60. if (pPage)
  61. {
  62. hPage = pPage->CreatePropSheetPage(MAKEINTRESOURCE(IDD_OWNER_PAGE));
  63. if (!hPage)
  64. delete pPage;
  65. }
  66. TraceLeaveValue(hPage);
  67. }
  68. COwnerPage::COwnerPage(LPSECURITYINFO psi, SI_OBJECT_INFO *psiObjectInfo)
  69. : CSecurityPage(psi, SI_PAGE_OWNER), m_psidOriginal(NULL), m_psidNetID(NULL),
  70. m_hSidThread(NULL)
  71. {
  72. // Lookup known SIDs asynchronously so the dialog
  73. // will initialize faster
  74. HDPA hSids = DPA_Create(ARRAYSIZE(g_uiTokenSids));
  75. if (hSids)
  76. {
  77. USES_CONVERSION;
  78. LPCWSTR pszServer = NULL;
  79. if (psiObjectInfo)
  80. pszServer = psiObjectInfo->pszServerName;
  81. for (int i = 0; i < ARRAYSIZE(g_uiTokenSids); i++)
  82. DPA_AppendPtr(hSids, QueryTokenSid(g_uiTokenSids[i]));
  83. m_psidNetID = GetAuthenticationID(pszServer);
  84. if (m_psidNetID)
  85. DPA_AppendPtr(hSids, m_psidNetID);
  86. LookupSidsAsync(hSids, W2CT(pszServer), m_psi2, NULL, 0, &m_hSidThread);
  87. DPA_Destroy(hSids);
  88. }
  89. }
  90. COwnerPage::~COwnerPage(void)
  91. {
  92. if (m_hSidThread)
  93. CloseHandle(m_hSidThread);
  94. if (m_psidOriginal)
  95. LocalFree(m_psidOriginal);
  96. if (m_psidNetID)
  97. LocalFree(m_psidNetID);
  98. }
  99. int
  100. COwnerPage::AddSid(HWND hOwner, PSID psid, LPCTSTR pszServerName)
  101. {
  102. PUSER_LIST pUserList = NULL;
  103. SID_NAME_USE sidType = SidTypeUnknown;
  104. LPCTSTR pszName = NULL;
  105. LPCTSTR pszLogonName = NULL;
  106. int iItem = -1;
  107. int cItems;
  108. LV_ITEM lvItem;
  109. TraceEnter(TRACE_OWNER, "COwnerPage::AddSid");
  110. TraceAssert(!m_bAbortPage);
  111. if (!psid || !IsValidSid(psid))
  112. ExitGracefully(iItem, -1, "Bad SID parameter");
  113. // Get the name for this SID
  114. if (LookupSid(psid, pszServerName, m_psi2, &pUserList))
  115. {
  116. TraceAssert(NULL != pUserList);
  117. TraceAssert(1 == pUserList->cUsers);
  118. sidType = pUserList->rgUsers[0].SidType;
  119. pszName = pUserList->rgUsers[0].pszName;
  120. pszLogonName = pUserList->rgUsers[0].pszLogonName;
  121. }
  122. switch (sidType)
  123. {
  124. case SidTypeDomain:
  125. case SidTypeDeletedAccount:
  126. case SidTypeInvalid:
  127. case SidTypeUnknown:
  128. case SidTypeComputer:
  129. ExitGracefully(iItem, -1, "SID invalid on target");
  130. break;
  131. }
  132. cItems = ListView_GetItemCount(hOwner);
  133. lvItem.mask = LVIF_PARAM;
  134. lvItem.iSubItem = 0;
  135. // See if this SID is already in the list
  136. for (iItem = 0; iItem < cItems; iItem++)
  137. {
  138. lvItem.iItem = iItem;
  139. lvItem.lParam = NULL;
  140. ListView_GetItem(hOwner, &lvItem);
  141. if (lvItem.lParam && EqualSid(psid, (PSID)lvItem.lParam))
  142. {
  143. // This is a hack. We often see alias sids more than once when
  144. // filling the list, e.g. BUILTIN\Administrators. We want to use
  145. // the version of the name that includes the target domain, if
  146. // provided. That is, if pszServerName is non-NULL here, switch
  147. // to the version of the name that goes with pszServerName.
  148. if (pszServerName)
  149. {
  150. lvItem.mask = LVIF_TEXT;
  151. lvItem.pszText = NULL;
  152. if (BuildUserDisplayName(&lvItem.pszText, pszName, pszLogonName)
  153. || ConvertSidToStringSid(psid, &lvItem.pszText))
  154. {
  155. ListView_SetItem(hOwner, &lvItem);
  156. LocalFreeString(&lvItem.pszText);
  157. }
  158. }
  159. break;
  160. }
  161. }
  162. if (iItem == cItems)
  163. {
  164. // The SID doesn't exist in the list. Add a new entry.
  165. PSID psidCopy = LocalAllocSid(psid);
  166. if (psidCopy)
  167. {
  168. lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
  169. lvItem.iItem = 0;
  170. lvItem.iSubItem = 0;
  171. lvItem.pszText = NULL;
  172. if (!BuildUserDisplayName(&lvItem.pszText, pszName, pszLogonName))
  173. ConvertSidToStringSid(psid, &lvItem.pszText);
  174. lvItem.iImage = GetSidImageIndex(psid, sidType);
  175. lvItem.lParam = (LPARAM)psidCopy;
  176. // Insert principal into list
  177. iItem = ListView_InsertItem(hOwner, &lvItem);
  178. LocalFreeString(&lvItem.pszText);
  179. }
  180. }
  181. exit_gracefully:
  182. if (NULL != pUserList)
  183. LocalFree(pUserList);
  184. TraceLeaveValue(iItem);
  185. }
  186. void
  187. COwnerPage::InitDlg(HWND hDlg)
  188. {
  189. TCHAR szBuffer[MAX_PATH];
  190. BOOL bReadOnly;
  191. HWND hOwner = GetDlgItem(hDlg, IDC_OWN_OWNERLIST);
  192. HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  193. TraceEnter(TRACE_OWNER, "COwnerPage::InitDlg");
  194. // Hide the Reset button if it isn't supported.
  195. if (!(m_siObjectInfo.dwFlags & SI_RESET) &&
  196. !(m_siObjectInfo.dwFlags & SI_RESET_OWNER))
  197. {
  198. ShowWindow(GetDlgItem(hDlg, IDC_OWN_RESET), SW_HIDE);
  199. }
  200. // Hide the Recurse checkbox if it isn't supported.
  201. if ((m_siObjectInfo.dwFlags & (SI_OWNER_RECURSE | SI_CONTAINER)) != (SI_OWNER_RECURSE | SI_CONTAINER))
  202. {
  203. m_siObjectInfo.dwFlags &= ~SI_OWNER_RECURSE;
  204. HWND hwndRecurse = GetDlgItem(hDlg, IDC_OWN_RECURSE);
  205. ShowWindow(hwndRecurse, SW_HIDE);
  206. EnableWindow(hwndRecurse, FALSE);
  207. }
  208. if (m_bAbortPage)
  209. {
  210. //
  211. // Disable everything
  212. //
  213. bReadOnly = TRUE;
  214. }
  215. else
  216. {
  217. // Create & set the image list for the listview
  218. ListView_SetImageList(hOwner,
  219. LoadImageList(::hModule, MAKEINTRESOURCE(IDB_SID_ICONS)),
  220. LVSIL_SMALL);
  221. //
  222. // Add the "Name" column (the only column on this page)
  223. //
  224. RECT rc;
  225. GetClientRect(hOwner, &rc);
  226. LoadString(::hModule, IDS_NAME, szBuffer, ARRAYSIZE(szBuffer));
  227. LV_COLUMN col;
  228. col.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
  229. col.fmt = LVCFMT_LEFT;
  230. col.pszText = szBuffer;
  231. col.iSubItem = 0;
  232. col.cx = rc.right;
  233. ListView_InsertColumn(hOwner, 0, &col);
  234. //
  235. // Make a copy of the current owner sid
  236. //
  237. PSECURITY_DESCRIPTOR pSD = NULL;
  238. HRESULT hr = m_psi->GetSecurity(OWNER_SECURITY_INFORMATION, &pSD, FALSE);
  239. if (pSD)
  240. {
  241. PSID psidOwner = NULL;
  242. BOOL bDefaulted;
  243. GetSecurityDescriptorOwner(pSD, &psidOwner, &bDefaulted);
  244. if (psidOwner)
  245. {
  246. UINT iLength = GetLengthSid(psidOwner);
  247. m_psidOriginal = LocalAlloc(LPTR, iLength);
  248. if (m_psidOriginal)
  249. CopyMemory(m_psidOriginal, psidOwner, iLength);
  250. }
  251. LocalFree(pSD);
  252. }
  253. // Test for writeability
  254. bReadOnly = !!(m_siObjectInfo.dwFlags & SI_OWNER_READONLY);
  255. } // !m_bAbortPage
  256. //
  257. // Iterate through the groups on this process's token looking for
  258. // the SE_GROUP_OWNER attribute.
  259. //
  260. if (!bReadOnly)
  261. {
  262. HANDLE hProcessToken = NULL;
  263. //
  264. // Wait for the known SIDs to be resolved so we don't try
  265. // to look them up twice.
  266. //
  267. if (m_hSidThread)
  268. {
  269. WaitForSingleObject(m_hSidThread, INFINITE);
  270. CloseHandle(m_hSidThread);
  271. m_hSidThread = NULL;
  272. }
  273. if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken))
  274. {
  275. // Allocate a buffer for the TOKEN_GROUPS information
  276. ULONG cbBuffer = 1024; // start with 1k
  277. LPVOID pBuffer = LocalAlloc(LPTR, cbBuffer);
  278. if (pBuffer)
  279. {
  280. if (!GetTokenInformation(hProcessToken,
  281. TokenGroups,
  282. pBuffer,
  283. cbBuffer,
  284. &cbBuffer))
  285. {
  286. LocalFree(pBuffer);
  287. pBuffer = NULL;
  288. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  289. {
  290. pBuffer = LocalAlloc(LPTR, cbBuffer);// size returned above
  291. if (pBuffer && !GetTokenInformation(hProcessToken,
  292. TokenGroups,
  293. pBuffer,
  294. cbBuffer,
  295. &cbBuffer))
  296. {
  297. LocalFree(pBuffer);
  298. pBuffer = NULL;
  299. }
  300. }
  301. }
  302. if (pBuffer)
  303. {
  304. PTOKEN_GROUPS ptg = (PTOKEN_GROUPS)pBuffer;
  305. for (ULONG i = 0; i < ptg->GroupCount; i++)
  306. {
  307. DWORD dwAttr = ptg->Groups[i].Attributes;
  308. if ((dwAttr & SE_GROUP_OWNER) && !(dwAttr & SE_GROUP_LOGON_ID))
  309. {
  310. AddSid(hOwner, ptg->Groups[i].Sid, m_siObjectInfo.pszServerName);
  311. }
  312. }
  313. }
  314. if (pBuffer != NULL)
  315. LocalFree(pBuffer);
  316. }
  317. CloseHandle(hProcessToken);
  318. }
  319. //
  320. // Now add in the additional possible sids
  321. //
  322. for (int i = 0; i < ARRAYSIZE(g_uiTokenSids); i++)
  323. AddSid(hOwner, QueryTokenSid(g_uiTokenSids[i]));
  324. AddSid(hOwner, m_psidNetID, m_siObjectInfo.pszServerName);
  325. }
  326. if (!m_bAbortPage)
  327. {
  328. PUSER_LIST pUserList = NULL;
  329. LoadString(::hModule, IDS_OWNER_CANT_DISPLAY, szBuffer, ARRAYSIZE(szBuffer));
  330. // Finally, look up a name for the original SID.
  331. if (m_psidOriginal)
  332. {
  333. LPTSTR pszName = NULL;
  334. // Get the "S-1-5-blah" form of the SID in case the lookup fails
  335. if (ConvertSidToStringSid(m_psidOriginal, &pszName))
  336. {
  337. lstrcpyn(szBuffer, pszName, ARRAYSIZE(szBuffer));
  338. LocalFreeString(&pszName);
  339. }
  340. if (LookupSid(m_psidOriginal, m_siObjectInfo.pszServerName, m_psi2, &pUserList))
  341. {
  342. TraceAssert(NULL != pUserList);
  343. TraceAssert(1 == pUserList->cUsers);
  344. if (BuildUserDisplayName(&pszName, pUserList->rgUsers[0].pszName, pUserList->rgUsers[0].pszLogonName))
  345. {
  346. lstrcpyn(szBuffer, pszName, ARRAYSIZE(szBuffer));
  347. LocalFreeString(&pszName);
  348. }
  349. LocalFree(pUserList);
  350. }
  351. }
  352. SetDlgItemText(hDlg, IDC_OWN_CURRENTOWNER, szBuffer);
  353. }
  354. //
  355. // If the current user cannot change owners, gray out the list box.
  356. //
  357. if (bReadOnly)
  358. {
  359. // Disable the list and notify the user that it's read-only.
  360. EnableWindow(hOwner, FALSE);
  361. EnableWindow(GetDlgItem(hDlg, IDC_OWN_RESET), FALSE);
  362. EnableWindow(GetDlgItem(hDlg, IDC_OWN_RECURSE), FALSE);
  363. //
  364. // If we're aborting, then the user should have been notified
  365. // during the propsheetpage callback. Don't put up another
  366. // message here.
  367. //
  368. if (S_OK == m_hrLastPSPCallbackResult)
  369. {
  370. MsgPopup(hDlg,
  371. MAKEINTRESOURCE(IDS_OWNER_READONLY),
  372. MAKEINTRESOURCE(IDS_SECURITY),
  373. MB_OK | MB_ICONINFORMATION,
  374. ::hModule,
  375. m_siObjectInfo.pszObjectName);
  376. }
  377. }
  378. SetCursor(hcur);
  379. TraceLeaveVoid();
  380. }
  381. void
  382. COwnerPage::OnApply(HWND hDlg, BOOL bClose)
  383. {
  384. int iSelected = -1;
  385. HWND hwndOwnerList;
  386. PSID psid;
  387. BOOL bRecurse = FALSE;
  388. SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION;
  389. BOOL bEqualSid = FALSE;
  390. TraceEnter(TRACE_OWNER, "COwnerPage::OnApply");
  391. hwndOwnerList = GetDlgItem(hDlg, IDC_OWN_OWNERLIST);
  392. psid = (PSID)GetSelectedItemData(hwndOwnerList, &iSelected);
  393. // If there is no selection, use the original
  394. if (!psid)
  395. psid = m_psidOriginal;
  396. // If no selection and no original, then we can't do anything
  397. if (!psid)
  398. TraceLeaveVoid();
  399. if ((m_siObjectInfo.dwFlags & SI_OWNER_RECURSE)
  400. && IsDlgButtonChecked(hDlg, IDC_OWN_RECURSE) == BST_CHECKED)
  401. {
  402. bRecurse = TRUE;
  403. }
  404. // Has anything changed?
  405. if (m_psidOriginal
  406. && ( (m_psidOriginal == psid) || EqualSid(m_psidOriginal, psid) )
  407. && !bRecurse)
  408. {
  409. // Nothing has changed
  410. TraceLeaveVoid();
  411. }
  412. SECURITY_DESCRIPTOR sd = {0};
  413. DWORD dwPriv = SE_TAKE_OWNERSHIP_PRIVILEGE;
  414. HANDLE hToken = INVALID_HANDLE_VALUE;
  415. HRESULT hr;
  416. TraceAssert(!m_bAbortPage);
  417. InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
  418. SetSecurityDescriptorOwner(&sd, psid, FALSE);
  419. //
  420. // ISecurityInformation::SetSecurity doesn't have a parameter to indicate
  421. // that the owner should be recursively applied. We could add a parameter,
  422. // but for now, just use one of the unused SECURITY_INFORMATION bits.
  423. // The security descriptor structure is unlikely to change so this should
  424. // be ok for now.
  425. if (bRecurse)
  426. si |= SI_OWNER_RECURSE;
  427. hToken = EnablePrivileges(&dwPriv, 1);
  428. hr = m_psi->SetSecurity(si, &sd);
  429. ReleasePrivileges(hToken);
  430. if (S_FALSE == hr)
  431. {
  432. // S_FALSE is silent failure (the client should put up UI
  433. // during SetSecurity before returning S_FALSE).
  434. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_INVALID);
  435. }
  436. else if (S_OK == hr && !bClose)
  437. {
  438. //Inform the Effective Permission tab that
  439. //Permissions are changed
  440. PropSheet_QuerySiblings(GetParent(hDlg),0,0);
  441. UINT iLength = GetLengthSid(psid);
  442. if (-1 != iSelected)
  443. {
  444. TCHAR szName[MAX_PATH];
  445. szName[0] = TEXT('\0');
  446. ListView_GetItemText(hwndOwnerList, iSelected, 0, szName, ARRAYSIZE(szName));
  447. SetDlgItemText(hDlg, IDC_OWN_CURRENTOWNER, szName);
  448. }
  449. if (!(m_psidOriginal &&
  450. ((m_psidOriginal == psid) || EqualSid(m_psidOriginal, psid))))
  451. {
  452. if (m_psidOriginal)
  453. {
  454. UINT iLengthOriginal = (UINT)LocalSize(m_psidOriginal);
  455. if (iLengthOriginal < iLength)
  456. {
  457. LocalFree(m_psidOriginal);
  458. m_psidOriginal = NULL;
  459. }
  460. else
  461. {
  462. ZeroMemory(m_psidOriginal, iLengthOriginal);
  463. }
  464. }
  465. if (!m_psidOriginal)
  466. m_psidOriginal = LocalAlloc(LPTR, iLength);
  467. if (m_psidOriginal)
  468. {
  469. CopyMemory(m_psidOriginal, psid, iLength);
  470. }
  471. else
  472. {
  473. hr = E_OUTOFMEMORY;
  474. }
  475. }
  476. if (m_siObjectInfo.dwFlags & SI_OWNER_RECURSE)
  477. CheckDlgButton(hDlg, IDC_OWN_RECURSE, BST_UNCHECKED);
  478. }
  479. if (FAILED(hr))
  480. {
  481. SysMsgPopup(hDlg,
  482. MAKEINTRESOURCE(IDS_OWNER_WRITE_FAILED),
  483. MAKEINTRESOURCE(IDS_SECURITY),
  484. MB_OK | MB_ICONERROR,
  485. ::hModule,
  486. hr,
  487. m_siObjectInfo.pszObjectName);
  488. }
  489. TraceLeaveVoid();
  490. }
  491. void
  492. COwnerPage::OnReset(HWND hDlg)
  493. {
  494. PSECURITY_DESCRIPTOR pSD = NULL;
  495. HWND hOwner;
  496. PSID psid;
  497. HRESULT hr;
  498. TraceEnter(TRACE_OWNER, "COwnerPage::OnReset");
  499. TraceAssert(!m_bAbortPage);
  500. hOwner = GetDlgItem(hDlg, IDC_OWN_OWNERLIST);
  501. psid = (PSID)GetSelectedItemData(hOwner, NULL);
  502. hr = m_psi->GetSecurity(OWNER_SECURITY_INFORMATION, &pSD, TRUE);
  503. if (SUCCEEDED(hr))
  504. {
  505. PSID psidDefault = NULL;
  506. BOOL bDefaulted;
  507. if (pSD)
  508. GetSecurityDescriptorOwner(pSD, &psidDefault, &bDefaulted);
  509. if (psidDefault && !EqualSid(psidDefault, psid))
  510. {
  511. int iSel = AddSid(hOwner, psidDefault, m_siObjectInfo.pszServerName);
  512. if (iSel != -1)
  513. {
  514. ListView_SetItemState(hOwner, iSel, LVIS_SELECTED, LVIS_SELECTED);
  515. PropSheet_Changed(GetParent(hDlg), hDlg);
  516. }
  517. }
  518. LocalFree(pSD);
  519. }
  520. else
  521. {
  522. SysMsgPopup(hDlg,
  523. MAKEINTRESOURCE(IDS_OPERATION_FAILED),
  524. MAKEINTRESOURCE(IDS_SECURITY),
  525. MB_OK | MB_ICONERROR,
  526. ::hModule,
  527. hr);
  528. }
  529. TraceLeaveVoid();
  530. }
  531. BOOL
  532. COwnerPage::DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  533. {
  534. BOOL bResult = TRUE;
  535. switch(uMsg)
  536. {
  537. case WM_INITDIALOG:
  538. InitDlg(hDlg);
  539. break;
  540. case WM_NOTIFY:
  541. {
  542. LPNM_LISTVIEW pnmlv = (LPNM_LISTVIEW)lParam;
  543. switch (((LPNMHDR)lParam)->code)
  544. {
  545. case LVN_ITEMCHANGED:
  546. if (pnmlv->uChanged & LVIF_STATE)
  547. {
  548. // item *gaining* selection
  549. if ((pnmlv->uNewState & LVIS_SELECTED) &&
  550. !(pnmlv->uOldState & LVIS_SELECTED))
  551. {
  552. PropSheet_Changed(GetParent(hDlg), hDlg);
  553. }
  554. }
  555. break;
  556. case LVN_DELETEITEM:
  557. if (pnmlv->lParam)
  558. LocalFree((PSID)pnmlv->lParam);
  559. break;
  560. case NM_SETFOCUS:
  561. if (((LPNMHDR)lParam)->idFrom == IDC_OWN_OWNERLIST)
  562. {
  563. // Make sure the listview is always focused on something,
  564. // otherwise you can't tab into the control.
  565. HWND hwndLV = GetDlgItem(hDlg, IDC_OWN_OWNERLIST);
  566. if (-1 == ListView_GetNextItem(hwndLV, -1, LVNI_FOCUSED))
  567. ListView_SetItemState(hwndLV, 0, LVIS_FOCUSED, LVIS_FOCUSED);
  568. }
  569. break;
  570. case PSN_QUERYINITIALFOCUS:
  571. {
  572. // Set initial focus to the list of potential owners
  573. HWND hwndLV = GetDlgItem(hDlg, IDC_OWN_OWNERLIST);
  574. if (IsWindowEnabled(hwndLV))
  575. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LONG_PTR)hwndLV);
  576. else
  577. bResult = FALSE;
  578. }
  579. break;
  580. case PSN_APPLY:
  581. OnApply(hDlg, (BOOL)(((LPPSHNOTIFY)lParam)->lParam));
  582. break;
  583. default:
  584. bResult = FALSE;
  585. }
  586. }
  587. break;
  588. case WM_COMMAND:
  589. switch (GET_WM_COMMAND_ID(wParam, lParam))
  590. {
  591. case IDC_OWN_RECURSE:
  592. if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED)
  593. PropSheet_Changed(GetParent(hDlg), hDlg);
  594. break;
  595. case IDC_OWN_RESET:
  596. OnReset(hDlg);
  597. break;
  598. default:
  599. bResult = FALSE;
  600. }
  601. break;
  602. case WM_HELP:
  603. if (IsWindowEnabled(hDlg))
  604. {
  605. WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle,
  606. c_szAcluiHelpFile,
  607. HELP_WM_HELP,
  608. (DWORD_PTR)aOwnerHelpIDs);
  609. }
  610. break;
  611. case WM_CONTEXTMENU:
  612. if (IsWindowEnabled(hDlg))
  613. {
  614. WinHelp(hDlg,
  615. c_szAcluiHelpFile,
  616. HELP_CONTEXTMENU,
  617. (DWORD_PTR)aOwnerHelpIDs);
  618. }
  619. break;
  620. default:
  621. bResult = FALSE;
  622. }
  623. return bResult;
  624. }