Leaked source code of windows server 2003
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.

418 lines
9.2 KiB

  1. // Copyright (C) 2001 Microsoft Corporation
  2. //
  3. // Application Partition (aka. Non-Domain Naming Context) page
  4. //
  5. // 24 Jul 2001 sburns
  6. #include "headers.hxx"
  7. #include "ApplicationPartitionPage.hpp"
  8. #include "resource.h"
  9. #include "state.hpp"
  10. ApplicationPartitionPage::ApplicationPartitionPage()
  11. :
  12. DCPromoWizardPage(
  13. IDD_APP_PARTITION,
  14. IDS_APP_PARTITION_PAGE_TITLE,
  15. IDS_APP_PARTITION_PAGE_SUBTITLE)
  16. // partitionList is populated on-demand in OnSetActive
  17. {
  18. LOG_CTOR(ApplicationPartitionPage);
  19. }
  20. ApplicationPartitionPage::~ApplicationPartitionPage()
  21. {
  22. LOG_DTOR(ApplicationPartitionPage);
  23. }
  24. void
  25. ApplicationPartitionPage::OnInit()
  26. {
  27. LOG_FUNCTION(ApplicationPartitionPage::OnInit);
  28. HWND view = Win::GetDlgItem(hwnd, IDC_NDNC_LIST);
  29. // Build a list view with two columns, one for the DN of the ndncs for
  30. // which this box is the last replica, another for the description(s) of
  31. // those ndncs.
  32. Win::ListView_SetExtendedListViewStyle(view, LVS_EX_FULLROWSELECT);
  33. // add a column to the list view for the DN
  34. LVCOLUMN column;
  35. // REVIEWED-2002/02/22-sburns call correctly passes byte count.
  36. ::ZeroMemory(&column, sizeof column);
  37. column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  38. column.fmt = LVCFMT_LEFT;
  39. int width = 0;
  40. String::load(IDS_NDNC_LIST_NAME_COLUMN_WIDTH).convert(width);
  41. column.cx = width;
  42. String label = String::load(IDS_NDNC_LIST_NAME_COLUMN);
  43. column.pszText = const_cast<wchar_t*>(label.c_str());
  44. Win::ListView_InsertColumn(view, 0, column);
  45. // add a column to the list view for description.
  46. String::load(IDS_NDNC_LIST_DESC_COLUMN_WIDTH).convert(width);
  47. column.cx = width;
  48. label = String::load(IDS_NDNC_LIST_DESC_COLUMN);
  49. column.pszText = const_cast<wchar_t*>(label.c_str());
  50. Win::ListView_InsertColumn(view, 1, column);
  51. }
  52. // Unwraps the safearray of variants inside a variant, extracts the strings
  53. // inside them, and catenates the strings together with semicolons in between.
  54. // Return empty string on error.
  55. //
  56. // variant - in, the variant containing a safearray of variants of bstr.
  57. String
  58. GetNdncDescriptionHelper(VARIANT* variant)
  59. {
  60. LOG_FUNCTION(GetNdncDescriptionHelper);
  61. ASSERT(variant);
  62. ASSERT(V_VT(variant) == (VT_ARRAY | VT_VARIANT));
  63. String result;
  64. SAFEARRAY* psa = V_ARRAY(variant);
  65. do
  66. {
  67. ASSERT(psa);
  68. ASSERT(psa != (SAFEARRAY*)-1);
  69. if (!psa || psa == (SAFEARRAY*)-1)
  70. {
  71. LOG(L"variant not safe array");
  72. break;
  73. }
  74. if (::SafeArrayGetDim(psa) != 1)
  75. {
  76. LOG(L"safe array: wrong number of dimensions");
  77. break;
  78. }
  79. VARTYPE vt = VT_EMPTY;
  80. HRESULT hr = ::SafeArrayGetVartype(psa, &vt);
  81. if (FAILED(hr) || vt != VT_VARIANT)
  82. {
  83. LOG(L"safe array: wrong element type");
  84. break;
  85. }
  86. long lower = 0;
  87. long upper = 0;
  88. hr = ::SafeArrayGetLBound(psa, 1, &lower);
  89. BREAK_ON_FAILED_HRESULT2(hr, L"can't get lower bound");
  90. hr = ::SafeArrayGetUBound(psa, 1, &upper);
  91. BREAK_ON_FAILED_HRESULT2(hr, L"can't get upper bound");
  92. VARIANT varItem;
  93. ::VariantInit(&varItem);
  94. for (long i = lower; i <= upper; ++i)
  95. {
  96. hr = ::SafeArrayGetElement(psa, &i, &varItem);
  97. if (FAILED(hr))
  98. {
  99. LOG(String::format(L"index %1!d! failed", i));
  100. continue;
  101. }
  102. result += V_BSTR(&varItem);
  103. if (i < upper)
  104. {
  105. result += L";";
  106. }
  107. ::VariantClear(&varItem);
  108. }
  109. }
  110. while (0);
  111. LOG(result);
  112. return result;
  113. }
  114. // bind to an ndnc, read it's description(s), and return them catenated
  115. // together. Return empty string on error.
  116. //
  117. // ndncDn - in, DN of the ndnc
  118. String
  119. GetNdncDescription(const String& ndncDn)
  120. {
  121. LOG_FUNCTION2(GetNdncDescription, ndncDn);
  122. ASSERT(!ndncDn.empty());
  123. String result;
  124. do
  125. {
  126. String path = L"LDAP://" + ndncDn;
  127. SmartInterface<IADs> iads(0);
  128. IADs* dumb = 0;
  129. HRESULT hr =
  130. ::ADsGetObject(
  131. path.c_str(),
  132. __uuidof(iads),
  133. reinterpret_cast<void**>(&dumb));
  134. BREAK_ON_FAILED_HRESULT2(hr, L"ADsGetObject failed on " + path);
  135. iads.Acquire(dumb);
  136. // description is a multivalued attrbute for no apparent good reason.
  137. // so we need to walk an array of values.
  138. _variant_t variant;
  139. hr = iads->GetEx(AutoBstr(L"description"), &variant);
  140. BREAK_ON_FAILED_HRESULT2(hr, L"read description failed");
  141. result = GetNdncDescriptionHelper(&variant);
  142. }
  143. while (0);
  144. LOG(result);
  145. return result;
  146. }
  147. void
  148. ApplicationPartitionPage::PopulateListView()
  149. {
  150. LOG_FUNCTION(ApplicationPartitionPage::PopulateListView);
  151. HWND view = Win::GetDlgItem(hwnd, IDC_NDNC_LIST);
  152. Win::ListView_DeleteAllItems(view);
  153. // Load up the edit box with the DNs we discovered
  154. LVITEM item;
  155. // REVIEWED-2002/02/22-sburns call correctly passes byte count.
  156. ::ZeroMemory(&item, sizeof item);
  157. const StringList& ndncList = State::GetInstance().GetAppPartitionList();
  158. if (!ndncList.size())
  159. {
  160. // put "none" in the list
  161. static const String NONE = String::load(IDS_NONE);
  162. item.mask = LVIF_TEXT;
  163. item.pszText = const_cast<wchar_t*>(NONE.c_str());
  164. item.iSubItem = 0;
  165. item.iItem = Win::ListView_InsertItem(view, item);
  166. }
  167. else
  168. {
  169. for (
  170. StringList::iterator i = ndncList.begin();
  171. i != ndncList.end();
  172. ++i)
  173. {
  174. item.mask = LVIF_TEXT;
  175. item.pszText = const_cast<wchar_t*>(i->c_str());
  176. item.iSubItem = 0;
  177. item.iItem = Win::ListView_InsertItem(view, item);
  178. // add the description sub-item to the list control
  179. String description = GetNdncDescription(*i);
  180. item.mask = LVIF_TEXT;
  181. item.pszText = const_cast<wchar_t*>(description.c_str());
  182. item.iSubItem = 1;
  183. Win::ListView_SetItem(view, item);
  184. }
  185. }
  186. }
  187. bool
  188. ApplicationPartitionPage::OnSetActive()
  189. {
  190. LOG_FUNCTION(ApplicationPartitionPage::OnSetActive);
  191. Win::WaitCursor wait;
  192. State& state = State::GetInstance();
  193. Wizard& wizard = GetWizard();
  194. // we re-evaluate this each time we hit the page to make sure the list
  195. // we present reflects the current state of the machine.
  196. bool wasLastReplica = state.GetAppPartitionList().size() ? true : false;
  197. bool isLastReplica = state.IsLastAppPartitionReplica();
  198. if (
  199. state.RunHiddenUnattended()
  200. || (!wasLastReplica && !isLastReplica) )
  201. {
  202. LOG(L"Planning to skip ApplicationPartitionPage");
  203. if (wizard.IsBacktracking())
  204. {
  205. // backup once again
  206. wizard.Backtrack(hwnd);
  207. return true;
  208. }
  209. int nextPage = ApplicationPartitionPage::Validate();
  210. if (nextPage != -1)
  211. {
  212. LOG(L"skipping ApplicationPartitionPage");
  213. wizard.SetNextPageID(hwnd, nextPage);
  214. return true;
  215. }
  216. state.ClearHiddenWhileUnattended();
  217. }
  218. // at this point, we know that the machine is the last replica of
  219. // at least one ndnc. Populate the list box.
  220. PopulateListView();
  221. Win::PropSheet_SetWizButtons(
  222. Win::GetParent(hwnd),
  223. PSWIZB_BACK | PSWIZB_NEXT);
  224. return true;
  225. }
  226. bool
  227. ApplicationPartitionPage::OnNotify(
  228. HWND /* windowFrom */ ,
  229. UINT_PTR controlIDFrom,
  230. UINT code,
  231. LPARAM /* lParam */ )
  232. {
  233. // LOG_FUNCTION(ApplicationPartitionPage::OnNotify);
  234. bool result = false;
  235. if (controlIDFrom == IDC_HELP_LINK)
  236. {
  237. switch (code)
  238. {
  239. case NM_CLICK:
  240. case NM_RETURN:
  241. {
  242. LOG(L"launching ndnc help");
  243. Win::HtmlHelp(
  244. hwnd,
  245. L"adconcepts.chm::/ADHelpDemoteWithNDNC.htm",
  246. HH_DISPLAY_TOPIC,
  247. 0);
  248. result = true;
  249. }
  250. default:
  251. {
  252. // do nothing
  253. break;
  254. }
  255. }
  256. }
  257. return result;
  258. }
  259. bool
  260. ApplicationPartitionPage::OnCommand(
  261. HWND /* windowFrom */ ,
  262. unsigned controlIDFrom,
  263. unsigned code)
  264. {
  265. // LOG_FUNCTION(ApplicationPartitionPage::OnCommand);
  266. switch (controlIDFrom)
  267. {
  268. case IDC_REFRESH:
  269. {
  270. if (code == BN_CLICKED)
  271. {
  272. Win::WaitCursor wait;
  273. State::GetInstance().IsLastAppPartitionReplica();
  274. PopulateListView();
  275. return true;
  276. }
  277. break;
  278. }
  279. default:
  280. {
  281. // do nothing
  282. break;
  283. }
  284. }
  285. return false;
  286. }
  287. int
  288. ApplicationPartitionPage::Validate()
  289. {
  290. LOG_FUNCTION(ApplicationPartitionPage::Validate);
  291. return IDD_APP_PARTITION_CONFIRM;
  292. }