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.

1545 lines
47 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: newobj.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. /////////////////////////////////////////////////////////////////////
  11. // newobj.cpp
  12. //
  13. // Implementation of the CNewADsObjectCreateInfo class.
  14. //
  15. // HISTORY
  16. // 20-Aug-97 Dan Morin Creation.
  17. //
  18. /////////////////////////////////////////////////////////////////////
  19. #include "stdafx.h"
  20. #include "resource.h"
  21. #include "dsutil.h"
  22. #include "util.h"
  23. #include "uiutil.h"
  24. #include "newobj.h"
  25. ///////////////////////////////////////////////////////////////////////
  26. // GUIDs for the DS Admin default wizards
  27. // {DE41B65A-8960-11d1-B93C-00A0C9A06D2D}
  28. static const GUID USER_WIZ_GUID = { 0xde41b65a, 0x8960, 0x11d1, { 0xb9, 0x3c, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  29. // {DE41B65B-8960-11d1-B93C-00A0C9A06D2D}
  30. static const GUID VOLUME_WIZ_GUID = { 0xde41b65b, 0x8960, 0x11d1, { 0xb9, 0x3c, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  31. // {DE41B65C-8960-11d1-B93C-00A0C9A06D2D}
  32. static const GUID COMPUTER_WIZ_GUID = { 0xde41b65c, 0x8960, 0x11d1, { 0xb9, 0x3c, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  33. // {DE41B65D-8960-11d1-B93C-00A0C9A06D2D}
  34. static const GUID PRINTQUEUE_WIZ_GUID = { 0xde41b65d, 0x8960, 0x11d1, { 0xb9, 0x3c, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  35. // {DE41B65E-8960-11d1-B93C-00A0C9A06D2D}
  36. static const GUID GROUP_WIZ_GUID = { 0xde41b65e, 0x8960, 0x11d1, { 0xb9, 0x3c, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  37. // {C05C260F-9DCA-11D1-B9B2-00C04FD8D5B0}
  38. static const GUID CONTACT_WIZ_GUID = { 0xc05c260f, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  39. // {DE41B65F-8960-11d1-B93C-00A0C9A06D2D}
  40. static const GUID NTDSCONN_WIZ_GUID = { 0xde41b65f, 0x8960, 0x11d1, { 0xb9, 0x3c, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  41. // {DE41B660-8960-11d1-B93C-00A0C9A06D2D}
  42. static const GUID FIXEDNAME_WIZ_GUID = { 0xde41b660, 0x8960, 0x11d1, { 0xb9, 0x3c, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  43. #ifdef FRS_CREATE
  44. // {DE41B661-8960-11d1-B93C-00A0C9A06D2D}
  45. static const GUID FRS_SUBSCRIBER_WIZ_GUID = { 0xde41b661, 0x8960, 0x11d1, { 0xb9, 0x3c, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  46. #endif // FRS_CREATE
  47. // {DE41B662-8960-11d1-B93C-00A0C9A06D2D}
  48. static const GUID SITE_WIZ_GUID = { 0xde41b662, 0x8960, 0x11d1, { 0xb9, 0x3c, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  49. // {DE41B663-8960-11d1-B93C-00A0C9A06D2D}
  50. static const GUID SUBNET_WIZ_GUID = { 0xde41b663, 0x8960, 0x11d1, { 0xb9, 0x3c, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  51. // {DE41B664-8960-11d1-B93C-00A0C9A06D2D}
  52. static const GUID OU_WIZ_GUID = { 0xde41b664, 0x8960, 0x11d1, { 0xb9, 0x3c, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  53. // {DE41B667-8960-11d1-B93C-00A0C9A06D2D}
  54. static const GUID SERVER_WIZ_GUID = { 0xde41b667, 0x8960, 0x11d1, { 0xb9, 0x3c, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  55. #ifdef FRS_CREATE
  56. // {DE41B668-8960-11d1-B93C-00A0C9A06D2D}
  57. static const GUID FRS_REPLICA_SET_WIZ_GUID = { 0xde41b668, 0x8960, 0x11d1, { 0xb9, 0x3c, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  58. // {C05C260C-9DCA-11D1-B9B2-00C04FD8D5B0}
  59. static const GUID FRS_MEMBER_WIZ_GUID = { 0xc05c260c, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  60. #endif // FRS_CREATE
  61. // {C05C260D-9DCA-11D1-B9B2-00C04FD8D5B0}
  62. static const GUID SITE_LINK_WIZ_GUID = { 0xc05c260d, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  63. // {C05C260E-9DCA-11D1-B9B2-00C04FD8D5B0}
  64. static const GUID SITE_LINK_BRIDGE_WIZ_GUID = { 0xc05c260e, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  65. /*
  66. // {C05C2610-9DCA-11D1-B9B2-00C04FD8D5B0}
  67. static const GUID <<name>> = { 0xc05c2610, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  68. // {C05C2611-9DCA-11D1-B9B2-00C04FD8D5B0}
  69. static const GUID <<name>> = { 0xc05c2611, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  70. // {C05C2612-9DCA-11D1-B9B2-00C04FD8D5B0}
  71. static const GUID <<name>> = { 0xc05c2612, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  72. // {C05C2613-9DCA-11D1-B9B2-00C04FD8D5B0}
  73. static const GUID <<name>> = { 0xc05c2613, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  74. // {C05C2614-9DCA-11D1-B9B2-00C04FD8D5B0}
  75. static const GUID <<name>> = { 0xc05c2614, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  76. // {C05C2615-9DCA-11D1-B9B2-00C04FD8D5B0}
  77. static const GUID <<name>> = { 0xc05c2615, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  78. // {C05C2616-9DCA-11D1-B9B2-00C04FD8D5B0}
  79. static const GUID <<name>> = { 0xc05c2616, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  80. // {C05C2617-9DCA-11D1-B9B2-00C04FD8D5B0}
  81. static const GUID <<name>> = { 0xc05c2617, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  82. // {C05C2618-9DCA-11D1-B9B2-00C04FD8D5B0}
  83. static const GUID <<name>> = { 0xc05c2618, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  84. // {C05C2619-9DCA-11D1-B9B2-00C04FD8D5B0}
  85. static const GUID <<name>> = { 0xc05c2619, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  86. // {C05C261A-9DCA-11D1-B9B2-00C04FD8D5B0}
  87. static const GUID <<name>> = { 0xc05c261a, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  88. // {C05C261B-9DCA-11D1-B9B2-00C04FD8D5B0}
  89. static const GUID <<name>> = { 0xc05c261b, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  90. // {C05C261C-9DCA-11D1-B9B2-00C04FD8D5B0}
  91. static const GUID <<name>> = { 0xc05c261c, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  92. // {C05C261D-9DCA-11D1-B9B2-00C04FD8D5B0}
  93. static const GUID <<name>> = { 0xc05c261d, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  94. // {C05C261E-9DCA-11D1-B9B2-00C04FD8D5B0}
  95. static const GUID <<name>> = { 0xc05c261e, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  96. // {C05C261F-9DCA-11D1-B9B2-00C04FD8D5B0}
  97. static const GUID <<name>> = { 0xc05c261f, 0x9dca, 0x11d1, { 0xb9, 0xb2, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  98. */
  99. /////////////////////////////////////////////////////////////////////
  100. // Structure to build a lookup table to match an object class
  101. // to a "create routine".
  102. // flags for the _CREATE_NEW_OBJECT::dwFlags field
  103. #define CNOF_STANDALONE_UI 0x00000001
  104. struct _CREATE_NEW_OBJECT // cno
  105. {
  106. LPCWSTR pszObjectClass; // Class of object to create. eg: user, computer, volume.
  107. PFn_HrCreateADsObject pfnCreate; // Pointer to "create routine" to create the new object
  108. const GUID* pWizardGUID; // guid of the DS Admin create wizard
  109. PVOID pvCreationParameter; // Optional creation parameter
  110. DWORD dwFlags; // miscellanea flags
  111. };
  112. /////////////////////////////////////////////////////////////////////
  113. //
  114. // Lookup table
  115. //
  116. // Each entry contains an attribute and a pointer to a routine to create the object.
  117. // If the attribute is not found in the table, then the object will be created
  118. // using the HrCreateADsObject() routine.
  119. //
  120. static const _CREATE_NEW_OBJECT g_rgcno[] =
  121. {
  122. { gsz_user, HrCreateADsUser, &USER_WIZ_GUID, NULL, CNOF_STANDALONE_UI },
  123. #ifdef INETORGPERSON
  124. { gsz_inetOrgPerson, HrCreateADsUser, &USER_WIZ_GUID, NULL, CNOF_STANDALONE_UI },
  125. #endif
  126. { gsz_volume, HrCreateADsVolume, &VOLUME_WIZ_GUID, NULL, CNOF_STANDALONE_UI },
  127. { gsz_computer, HrCreateADsComputer, &COMPUTER_WIZ_GUID, NULL, CNOF_STANDALONE_UI },
  128. { gsz_printQueue, HrCreateADsPrintQueue, &PRINTQUEUE_WIZ_GUID, NULL, CNOF_STANDALONE_UI },
  129. { gsz_group, HrCreateADsGroup, &GROUP_WIZ_GUID, NULL, CNOF_STANDALONE_UI },
  130. { gsz_contact, HrCreateADsContact, &CONTACT_WIZ_GUID, NULL, CNOF_STANDALONE_UI },
  131. { gsz_nTDSConnection, HrCreateADsNtDsConnection, &NTDSCONN_WIZ_GUID, NULL, 0x0 },
  132. // Note that names of DS objects are not internationalized. I will leave
  133. // this string out of the resource file to make sure that INTL doesn't try
  134. // to internationalize it.
  135. { gsz_nTDSSiteSettings, HrCreateADsFixedName, &FIXEDNAME_WIZ_GUID, (PVOID)L"NTDS Site Settings", 0x0 },
  136. { gsz_serversContainer, HrCreateADsFixedName, &FIXEDNAME_WIZ_GUID, (PVOID)L"Servers", 0x0 },
  137. // CODEWORK could have a special wizard but this will do for now
  138. { gsz_licensingSiteSettings, HrCreateADsFixedName, &FIXEDNAME_WIZ_GUID, (PVOID)L"Licensing Site Settings", 0x0 },
  139. { gsz_siteLink, HrCreateADsSiteLink, &SITE_LINK_WIZ_GUID, NULL, 0x0 },
  140. { gsz_siteLinkBridge, HrCreateADsSiteLinkBridge, &SITE_LINK_BRIDGE_WIZ_GUID, NULL, 0x0 },
  141. #ifdef FRS_CREATE
  142. //
  143. // FRS stuff
  144. //
  145. { gsz_nTFRSSettings, HrCreateADsFixedName, &FIXEDNAME_WIZ_GUID, (PVOID)L"FRS Settings", 0x0 },
  146. { gsz_nTFRSReplicaSet, HrCreateADsSimpleObject, &FRS_REPLICA_SET_WIZ_GUID, NULL, 0x0 },
  147. { gsz_nTFRSMember, HrCreateADsNtFrsMember, &FRS_MEMBER_WIZ_GUID, NULL, 0x0 },
  148. // CODEWORK fixed name doesn't mesh with the ability to create a subtree of these
  149. { gsz_nTFRSSubscriptions, CreateADsNtFrsSubscriptions, &FIXEDNAME_WIZ_GUID, (PVOID)L"FRS Subscriptions", 0x0 },
  150. { gsz_nTFRSSubscriber, HrCreateADsNtFrsSubscriber, &FRS_SUBSCRIBER_WIZ_GUID, NULL, 0x0 },
  151. #endif // FRS_CREATE
  152. { gsz_server, HrCreateADsServer, &SERVER_WIZ_GUID, NULL, 0x0 },
  153. { gsz_site, HrCreateADsSite, &SITE_WIZ_GUID, NULL, 0x0 },
  154. { gsz_subnet, HrCreateADsSubnet, &SUBNET_WIZ_GUID, NULL, 0x0 },
  155. { gsz_organizationalUnit, HrCreateADsOrganizationalUnit, &OU_WIZ_GUID, NULL, CNOF_STANDALONE_UI },
  156. };
  157. ////////////////////////////////////////////////////////////////////////////
  158. // MarcoC:
  159. // Test only: simple dump function to print the table above
  160. // need this to dump formatted table for documentation.
  161. /*
  162. void DumpCreateTable()
  163. {
  164. for (int i = 0; i < LENGTH(g_rgcno); i++)
  165. {
  166. ASSERT(g_rgcno[i].pszObjectClass != NULL);
  167. WCHAR szBuf[256];
  168. StringFromGUID2(*(g_rgcno[i].pWizardGUID), szBuf, 256);
  169. LPCWSTR lpsz = (g_rgcno[i].dwFlags & CNOF_STANDALONE_UI) ? L"Y" : L"N";
  170. TRACE(L"%s\t%s\t%s\n", g_rgcno[i].pszObjectClass, szBuf, lpsz);
  171. } // for
  172. }
  173. */
  174. ////////////////////////////////////////////////////////////////////////////
  175. // simple lookup function to return the internal handler inf given
  176. // a class name
  177. BOOL FindHandlerFunction(/*IN*/ LPCWSTR lpszObjectClass,
  178. /*OUT*/ PFn_HrCreateADsObject* ppfFunc,
  179. /*OUT*/ void** ppVoid)
  180. {
  181. *ppfFunc = NULL;
  182. *ppVoid = NULL;
  183. for (int i = 0; i < ARRAYLEN(g_rgcno); i++)
  184. {
  185. ASSERT(g_rgcno[i].pszObjectClass != NULL);
  186. ASSERT(g_rgcno[i].pfnCreate != NULL);
  187. // compare class name
  188. if (0 == lstrcmp(g_rgcno[i].pszObjectClass, lpszObjectClass))
  189. {
  190. // found matching class, get the function from it
  191. *ppfFunc = g_rgcno[i].pfnCreate;
  192. *ppVoid = g_rgcno[i].pvCreationParameter;
  193. return TRUE;
  194. } // if
  195. } // for
  196. return FALSE;
  197. }
  198. /////////////////////////////////////////////////////////////////////////////////////
  199. // Hackarama fix
  200. HRESULT HrCreateFixedNameHelper(/*IN*/ LPCWSTR lpszObjectClass,
  201. /*IN*/ LPCWSTR lpszAttrString, // typically "cn="
  202. /*IN*/ IADsContainer* pIADsContainer)
  203. {
  204. // find the fixed name on the table
  205. LPCWSTR lpszName = NULL;
  206. for (int i = 0; i < ARRAYLEN(g_rgcno); i++)
  207. {
  208. ASSERT(g_rgcno[i].pszObjectClass != NULL);
  209. // compare class name
  210. if (0 == lstrcmp(g_rgcno[i].pszObjectClass, lpszObjectClass))
  211. {
  212. lpszName = (LPCWSTR)(g_rgcno[i].pvCreationParameter);
  213. break;
  214. } // if
  215. } // for
  216. ASSERT(lpszName != NULL);
  217. if (lpszName == NULL)
  218. return E_INVALIDARG;
  219. // create the temporary object
  220. CString szAdsName;
  221. szAdsName.Format(_T("%s%s"), (LPCWSTR)lpszAttrString, lpszName);
  222. IDispatch* pIDispatch = NULL;
  223. HRESULT hr = pIADsContainer->Create(CComBSTR(lpszObjectClass),
  224. CComBSTR(szAdsName),
  225. &pIDispatch);
  226. if (FAILED(hr))
  227. return hr; // could not create
  228. ASSERT(pIDispatch != NULL);
  229. IADs* pIADs = NULL;
  230. hr = pIDispatch->QueryInterface(IID_IADs, (LPVOID *)&pIADs);
  231. pIDispatch->Release();
  232. if (FAILED(hr))
  233. return hr; // should never happen!!!
  234. //commit object
  235. hr = pIADs->SetInfo();
  236. pIADs->Release();
  237. return hr;
  238. }
  239. ////////////////////////////////////////////////////////////////////////////
  240. // This function just returns the values from the internal table
  241. // To be used when other type of data retrieval fails
  242. // returns S_OK if the info was found, E_FAIL if not
  243. STDAPI DsGetClassCreationInfoInternal(LPCWSTR pClassName, LPDSCLASSCREATIONINFO* ppInfo)
  244. {
  245. if (ppInfo == NULL)
  246. return E_INVALIDARG;
  247. *ppInfo = (DSCLASSCREATIONINFO*)::LocalAlloc(LPTR, sizeof(DSCLASSCREATIONINFO));
  248. if (*ppInfo != NULL)
  249. {
  250. ZeroMemory(*ppInfo, sizeof(DSCLASSCREATIONINFO));
  251. for (int i = 0; i < ARRAYLEN(g_rgcno); i++)
  252. {
  253. ASSERT(g_rgcno[i].pszObjectClass != NULL);
  254. ASSERT(g_rgcno[i].pfnCreate != NULL);
  255. if (0 == lstrcmp(g_rgcno[i].pszObjectClass, pClassName))
  256. {
  257. // found matching class
  258. (*ppInfo)->dwFlags = DSCCIF_HASWIZARDPRIMARYPAGE;
  259. (*ppInfo)->clsidWizardPrimaryPage = *(g_rgcno[i].pWizardGUID);
  260. return S_OK;
  261. } // if
  262. } // for
  263. }
  264. return E_FAIL;
  265. }
  266. //////////////////////////////////////////////////////////////////////////////////
  267. // NOTICE: this #define is used to enable externsibility testing without having
  268. // to modify the schema.
  269. //#ifdef _DEBUG
  270. // #define _TEST_OVERRIDE
  271. //#endif
  272. #ifdef _TEST_OVERRIDE
  273. BOOL g_bTestCreateOverride = FALSE;
  274. //BOOL g_bTestCreateOverride = TRUE;
  275. // {DE41B658-8960-11d1-B93C-00A0C9A06D2D}
  276. static const GUID CLSID_CCreateDlg =
  277. { 0xde41b658, 0x8960, 0x11d1, { 0xb9, 0x3c, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  278. // {DE41B659-8960-11d1-B93C-00A0C9A06D2D}
  279. static const GUID CLSID_WizExt =
  280. { 0xde41b659, 0x8960, 0x11d1, { 0xb9, 0x3c, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  281. // {C03793D2-A7C8-11d1-B940-00A0C9A06D2D}
  282. static const GUID CLSID_WizExtNoUI =
  283. { 0xc03793d2, 0xa7c8, 0x11d1, { 0xb9, 0x40, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  284. // {C03793D3-A7C8-11d1-B940-00A0C9A06D2D}
  285. static const GUID CLSID_WizExtUser =
  286. { 0xc03793d3, 0xa7c8, 0x11d1, { 0xb9, 0x40, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  287. #endif // _TEST_OVERRIDE
  288. ///////////////////////////////////////////////////////////////////////////
  289. // Wrapper function to do filtering and error handling
  290. HRESULT DsGetClassCreationInfoEx(IN MyBasePathsInfo* pBasePathsInfo,
  291. IN LPCWSTR pClassName,
  292. OUT LPDSCLASSCREATIONINFO* ppInfo)
  293. {
  294. TRACE(L"DsGetClassCreationInfoEx(_, pClassName = %s, _)\n", pClassName);
  295. HRESULT hr;
  296. // do some filtering, to ignore overrides
  297. if (0 == lstrcmp(gsz_printQueue, pClassName))
  298. {
  299. // ignore override of this class
  300. hr = ::DsGetClassCreationInfoInternal(pClassName, ppInfo);
  301. ASSERT(SUCCEEDED(hr));
  302. return hr;
  303. }
  304. #ifdef _TEST_OVERRIDE
  305. if (g_bTestCreateOverride)
  306. {
  307. //
  308. // this is just to test extensions
  309. //
  310. if ( (0 == lstrcmp(L"contact", pClassName)) ||
  311. (0 == lstrcmp(L"organizationalUnit", pClassName)) )
  312. {
  313. hr = ::DsGetClassCreationInfoInternal(pClassName, ppInfo);
  314. // replace the dialog completely
  315. (*ppInfo)->clsidWizardPrimaryPage = CLSID_CCreateDlg;
  316. (*ppInfo)->dwFlags |= DSCCIF_HASWIZARDPRIMARYPAGE;
  317. return S_OK;
  318. }
  319. else if (0 == lstrcmp(gsz_user, pClassName))
  320. {
  321. // add user specific extension and generic extension
  322. hr = ::DsGetClassCreationInfoInternal(pClassName, ppInfo);
  323. ASSERT(SUCCEEDED(hr));
  324. LPDSCLASSCREATIONINFO pTempInfo = (*ppInfo);
  325. (*ppInfo) = (DSCLASSCREATIONINFO*)::LocalAlloc(LPTR, sizeof(DSCLASSCREATIONINFO)+ sizeof(GUID));
  326. (*ppInfo)->clsidWizardPrimaryPage = pTempInfo->clsidWizardPrimaryPage;
  327. (*ppInfo)->dwFlags = pTempInfo->dwFlags;
  328. (*ppInfo)->cWizardExtensions = 2;
  329. (*ppInfo)->aWizardExtensions[0] = CLSID_WizExtUser;
  330. (*ppInfo)->aWizardExtensions[1] = CLSID_WizExt;
  331. ::LocalFree(pTempInfo);
  332. return S_OK;
  333. }
  334. else
  335. {
  336. // add a general purpose extension for other known classes
  337. hr = ::DsGetClassCreationInfoInternal(pClassName, ppInfo);
  338. if(SUCCEEDED(hr))
  339. {
  340. (*ppInfo)->cWizardExtensions = 1;
  341. (*ppInfo)->aWizardExtensions[0] = CLSID_WizExt;
  342. return S_OK;
  343. }
  344. }
  345. } // g_bTestCreateOverride
  346. #endif // _TEST_OVERRIDE
  347. // try the display specifiers in the back end (DSUIEXT.DLL)
  348. TRACE(L"calling pBasePathsInfo->GetClassCreationInfo()\n");
  349. hr = pBasePathsInfo->GetClassCreationInfo(pClassName, ppInfo);
  350. ASSERT(SUCCEEDED(hr));
  351. ASSERT((*ppInfo) != NULL);
  352. // protect from somebody erroneously putting CLSID_DsAdminCreateObj
  353. if ( (*ppInfo)->clsidWizardPrimaryPage == CLSID_DsAdminCreateObj)
  354. {
  355. // just remove entry, next check below will try to fix if possible
  356. TRACE(L"// just remove entry, next check below will try to fix if possible\n");
  357. (*ppInfo)->dwFlags &= ~DSCCIF_HASWIZARDPRIMARYPAGE;
  358. (*ppInfo)->clsidWizardPrimaryPage = CLSID_NULL;
  359. }
  360. if (((*ppInfo)->dwFlags & DSCCIF_HASWIZARDPRIMARYPAGE) == 0)
  361. {
  362. // something went wrong or there is no specifier at all for the primary wizard,
  363. // just call the internal implementation to get the primary wizard
  364. TRACE(L"// just call the internal implementation to get the primary wizard\n");
  365. LPDSCLASSCREATIONINFO pTempInfo;
  366. HRESULT hrInternal = DsGetClassCreationInfoInternal(pClassName, &pTempInfo);
  367. if (SUCCEEDED(hrInternal))
  368. {
  369. // it is a class we know about, modify the info we got from backend
  370. (*ppInfo)->dwFlags |= DSCCIF_HASWIZARDPRIMARYPAGE;
  371. (*ppInfo)->clsidWizardPrimaryPage = pTempInfo->clsidWizardPrimaryPage;
  372. ::LocalFree(pTempInfo);
  373. }
  374. }
  375. TRACE(L"DsGetClassCreationInfoEx() returning hr = 0x%x\n", hr);
  376. return hr;
  377. }
  378. /////////////////////////////////////////////////////////////////////
  379. //////////////////// CNewADsObjectCreateInfo ////////////////////////
  380. /////////////////////////////////////////////////////////////////////
  381. /////////////////////////////////////////////////////////////////////
  382. CNewADsObjectCreateInfo::CNewADsObjectCreateInfo(
  383. MyBasePathsInfo* pBasePathsInfo,
  384. LPCTSTR pszObjectClass)
  385. {
  386. ASSERT(pszObjectClass != NULL);
  387. ASSERT(pBasePathsInfo != NULL);
  388. m_pBasePathsInfo = pBasePathsInfo;
  389. m_pszObjectClass = pszObjectClass;
  390. m_hWnd = NULL;
  391. m_pvCreationParameter = NULL;
  392. m_pfnCreateObject = NULL;
  393. m_pIADsContainer = NULL;
  394. m_pDsCacheItem = NULL;
  395. m_pCD = NULL;
  396. m_pIADs = NULL;
  397. m_pCreateInfo = NULL;
  398. m_bPostCommit = FALSE;
  399. m_pCopyHandler = NULL;
  400. }
  401. /////////////////////////////////////////////////////////////////////
  402. CNewADsObjectCreateInfo::~CNewADsObjectCreateInfo()
  403. {
  404. if (m_pCreateInfo != NULL)
  405. {
  406. ::LocalFree(m_pCreateInfo);
  407. m_pCreateInfo = NULL;
  408. }
  409. if (m_pCopyHandler != NULL)
  410. {
  411. delete m_pCopyHandler;
  412. }
  413. }
  414. /////////////////////////////////////////////////////////////////////
  415. // Another method to inizialize the object with additional pointers.
  416. void
  417. CNewADsObjectCreateInfo::SetContainerInfo(
  418. IN IADsContainer * pIADsContainer,
  419. IN CDSClassCacheItemBase* pDsCacheItem,
  420. IN CDSComponentData* pCD,
  421. IN LPCWSTR lpszAttrString)
  422. {
  423. ASSERT(m_pIADs == NULL);
  424. ASSERT(pIADsContainer != NULL);
  425. if (pDsCacheItem != NULL)
  426. {
  427. m_szCacheNamingAttribute = pDsCacheItem->GetNamingAttribute();
  428. }
  429. else
  430. {
  431. m_szCacheNamingAttribute = lpszAttrString;
  432. }
  433. m_pIADsContainer = pIADsContainer;
  434. m_pDsCacheItem = pDsCacheItem;
  435. m_pCD = pCD;
  436. }
  437. /////////////////////////////////////////////////////////////////////
  438. HRESULT CNewADsObjectCreateInfo::SetCopyInfo(IADs* pIADsCopyFrom)
  439. {
  440. ASSERT(pIADsCopyFrom != NULL);
  441. CWaitCursor wait;
  442. // load the object cache
  443. HRESULT hr = pIADsCopyFrom->GetInfo();
  444. if (FAILED(hr))
  445. {
  446. TRACE(L"pIADsCopyFrom->GetInfo() failed with hr = 0x%x\n", hr);
  447. return hr;
  448. }
  449. // get the object class
  450. CComBSTR bstrClassName;
  451. hr = pIADsCopyFrom->get_Class(&bstrClassName);
  452. if (FAILED(hr))
  453. {
  454. TRACE(L"spIADsCopyFrom->get_Class() failed with hr = 0x%x\n", hr);
  455. return hr;
  456. }
  457. // make sure we are dealing with the right class type
  458. if (wcscmp(m_pszObjectClass, bstrClassName) != 0)
  459. {
  460. hr = E_INVALIDARG;
  461. TRACE(L"ERROR: wrong source object class m_pszObjectClass = %s, bstrClassName = %s\n",
  462. m_pszObjectClass, bstrClassName);
  463. return hr;
  464. }
  465. // determine if this is a copyable class
  466. // and create the appropriate copy handler
  467. ASSERT(m_pCopyHandler == NULL);
  468. if (wcscmp(m_pszObjectClass, L"user") == 0
  469. #ifdef INETORGPERSON
  470. || _wcsicmp(m_pszObjectClass, L"inetOrgPerson") == 0
  471. #endif
  472. )
  473. {
  474. ASSERT(m_pCopyHandler == NULL);
  475. m_pCopyHandler = new CCopyUserHandler();
  476. }
  477. else
  478. {
  479. // default, do-nothing copy handler
  480. m_pCopyHandler = new CCopyObjectHandlerBase();
  481. }
  482. if (m_pCopyHandler == NULL)
  483. return E_OUTOFMEMORY;
  484. hr = m_pCopyHandler->Init(m_pBasePathsInfo, pIADsCopyFrom);
  485. return hr;
  486. }
  487. HRESULT CNewADsObjectCreateInfo::SetCopyInfo(LPCWSTR lpszCopyFromLDAPPath)
  488. {
  489. TRACE(L"CNewADsObjectCreateInfo::SetCopyInfo(%s)\n", lpszCopyFromLDAPPath);
  490. // bind to the object
  491. CComPtr<IADs> spIADsCopyFrom;
  492. HRESULT hr = S_OK;
  493. {
  494. CWaitCursor wait;
  495. hr = DSAdminOpenObject(lpszCopyFromLDAPPath,
  496. IN IID_IADs,
  497. OUT (LPVOID *) &spIADsCopyFrom,
  498. TRUE /*bServer*/);
  499. }
  500. if (FAILED(hr))
  501. {
  502. TRACE(L"DSAdminOpenObject(%s) failed with hr = 0x%x\n", lpszCopyFromLDAPPath, hr);
  503. return hr;
  504. }
  505. // do the copy info setup using the bound pointer
  506. return SetCopyInfo(spIADsCopyFrom);
  507. }
  508. /////////////////////////////////////////////////////////////////////
  509. // gets the current container (in canonical form)
  510. LPCWSTR CNewADsObjectCreateInfo::GetContainerCanonicalName()
  511. {
  512. if (m_szContainerCanonicalName.IsEmpty())
  513. {
  514. CComPtr<IADs> spObj;
  515. HRESULT hr = m_pIADsContainer->QueryInterface(
  516. IID_IADs, (void **)&spObj);
  517. if (SUCCEEDED(hr))
  518. {
  519. CComBSTR bsPath, bsDN;
  520. LPWSTR pszCanonical = NULL;
  521. spObj->get_ADsPath(&bsPath);
  522. CPathCracker pathCracker;
  523. pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
  524. pathCracker.Set(bsPath, ADS_SETTYPE_FULL);
  525. pathCracker.Retrieve(ADS_FORMAT_X500_DN, &bsDN);
  526. hr = CrackName (bsDN, &pszCanonical, GET_OBJ_CAN_NAME, NULL);
  527. if (SUCCEEDED(hr))
  528. m_szContainerCanonicalName = pszCanonical;
  529. if (pszCanonical != NULL)
  530. LocalFreeStringW(&pszCanonical);
  531. }
  532. }
  533. return m_szContainerCanonicalName;
  534. }
  535. /////////////////////////////////////////////////////////////////////
  536. // _RemoveAttribute()
  537. HRESULT CNewADsObjectCreateInfo::_RemoveAttribute(BSTR bstrAttrName, BOOL bDefaultList)
  538. {
  539. if (bDefaultList)
  540. return _RemoveVariantInfo(bstrAttrName);
  541. else
  542. return _HrClearAttribute(bstrAttrName);
  543. }
  544. /////////////////////////////////////////////////////////////////////
  545. // _PAllocateVariantInfo()
  546. //
  547. // Private routine to allocate and initialize a VARIANT_INFO structure.
  548. //
  549. // Return pointer to VARIANT structure if successful, otherwise
  550. // return NULL.
  551. //
  552. // INTERFACE NOTES
  553. // All allocated variants will be cleared when the class gets destroyed.
  554. //
  555. VARIANT*
  556. CNewADsObjectCreateInfo::_PAllocateVariantInfo(BSTR bstrAttrName)
  557. {
  558. // first look if we have the attribute already in the list
  559. for (POSITION pos = m_defaultVariantList.GetHeadPosition(); pos != NULL; )
  560. {
  561. CVariantInfo* pCurrInfo = m_defaultVariantList.GetNext(pos);
  562. if (_wcsicmp (pCurrInfo->m_szAttrName, bstrAttrName) == 0)
  563. {
  564. // found, just recycle this one
  565. ::VariantClear(&pCurrInfo->m_varAttrValue);
  566. return &pCurrInfo->m_varAttrValue;
  567. }
  568. }
  569. // not found, create a new one and add to the list
  570. CVariantInfo* pVariantInfo = new CVariantInfo;
  571. if (pVariantInfo == NULL)
  572. return NULL;
  573. pVariantInfo->m_bPostCommit = m_bPostCommit;
  574. pVariantInfo->m_szAttrName = bstrAttrName;
  575. m_defaultVariantList.AddTail(pVariantInfo);
  576. return &pVariantInfo->m_varAttrValue;
  577. }
  578. /////////////////////////////////////////////////////////////////////
  579. //
  580. HRESULT CNewADsObjectCreateInfo::_RemoveVariantInfo(BSTR bstrAttrName)
  581. {
  582. POSITION deletePos = NULL;
  583. CVariantInfo* pCurrInfo = NULL;
  584. for (POSITION pos = m_defaultVariantList.GetHeadPosition(); pos != NULL; )
  585. {
  586. POSITION lastPos = pos;
  587. pCurrInfo = m_defaultVariantList.GetNext(pos);
  588. if (_wcsicmp (pCurrInfo->m_szAttrName, bstrAttrName) == 0)
  589. {
  590. // found
  591. deletePos = lastPos;
  592. break;
  593. }
  594. }
  595. if (deletePos != NULL)
  596. {
  597. m_defaultVariantList.RemoveAt(deletePos);
  598. delete pCurrInfo;
  599. }
  600. return S_OK;
  601. }
  602. /////////////////////////////////////////////////////////////////////
  603. // Add a BSTR variant where the value is name of the object.
  604. //
  605. // Here are some examples where the name of the object is the
  606. // attribute value: "cn", "ou", "samAccountName"
  607. //
  608. HRESULT
  609. CNewADsObjectCreateInfo::HrAddVariantFromName(BSTR bstrAttrName)
  610. {
  611. ASSERT(bstrAttrName != NULL);
  612. ASSERT(!m_strObjectName.IsEmpty());
  613. return HrAddVariantBstr(bstrAttrName, m_strObjectName);
  614. }
  615. /////////////////////////////////////////////////////////////////////
  616. // Add a BSTR variant to the list.
  617. HRESULT
  618. CNewADsObjectCreateInfo::HrAddVariantBstr(BSTR bstrAttrName, LPCTSTR pszAttrValue,
  619. BOOL bDefaultList)
  620. {
  621. ASSERT(bstrAttrName != NULL);
  622. // passing a NULL or empty string means remove the attribute
  623. if ( (pszAttrValue == NULL) || ((pszAttrValue != NULL) && (pszAttrValue[0] == NULL)) )
  624. {
  625. return _RemoveAttribute(bstrAttrName, bDefaultList);
  626. }
  627. ASSERT(pszAttrValue != NULL);
  628. HRESULT hr = S_OK;
  629. if (bDefaultList)
  630. {
  631. VARIANT * pVariant = _PAllocateVariantInfo(bstrAttrName);
  632. if (pVariant == NULL)
  633. hr = E_OUTOFMEMORY;
  634. else
  635. {
  636. pVariant->vt = VT_BSTR;
  637. pVariant->bstrVal = ::SysAllocString(pszAttrValue);
  638. if (pVariant->bstrVal == NULL)
  639. hr = E_OUTOFMEMORY;
  640. }
  641. }
  642. else
  643. {
  644. CComVariant v;
  645. v.vt = VT_BSTR;
  646. v.bstrVal = ::SysAllocString(pszAttrValue);
  647. if (v.bstrVal == NULL)
  648. return E_OUTOFMEMORY;
  649. hr = _HrSetAttributeVariant(bstrAttrName, &v);
  650. }
  651. return hr;
  652. }
  653. /////////////////////////////////////////////////////////////////////
  654. // Add a BSTR variant to the list if the string value is not empty.
  655. HRESULT
  656. CNewADsObjectCreateInfo::HrAddVariantBstrIfNotEmpty(BSTR bstrAttrName,
  657. LPCWSTR pszAttrValue,
  658. BOOL bDefaultList)
  659. {
  660. if (pszAttrValue == NULL)
  661. return S_OK;
  662. while (*pszAttrValue == _T(' '))
  663. pszAttrValue++;
  664. if (pszAttrValue[0] == _T('\0'))
  665. return S_OK;
  666. return HrAddVariantBstr(bstrAttrName, pszAttrValue, bDefaultList);
  667. }
  668. /////////////////////////////////////////////////////////////////////
  669. // Add an integer variant to the list.
  670. HRESULT CNewADsObjectCreateInfo::HrAddVariantLong(BSTR bstrAttrName, LONG lAttrValue,
  671. BOOL bDefaultList)
  672. {
  673. ASSERT(bstrAttrName != NULL);
  674. HRESULT hr = S_OK;
  675. if (bDefaultList)
  676. {
  677. VARIANT * pVariant = _PAllocateVariantInfo(bstrAttrName);
  678. if (pVariant == NULL)
  679. hr = E_OUTOFMEMORY;
  680. else
  681. {
  682. pVariant->vt = VT_I4;
  683. pVariant->lVal = lAttrValue;
  684. }
  685. }
  686. else
  687. {
  688. CComVariant v;
  689. v.vt = VT_I4;
  690. v.lVal = lAttrValue;
  691. hr = _HrSetAttributeVariant(bstrAttrName, &v);
  692. }
  693. return hr;
  694. }
  695. /////////////////////////////////////////////////////////////////////
  696. // Add a boolean variant to the list.
  697. HRESULT
  698. CNewADsObjectCreateInfo::HrAddVariantBoolean(BSTR bstrAttrName, BOOL fAttrValue,
  699. BOOL bDefaultList)
  700. {
  701. ASSERT(bstrAttrName != NULL);
  702. HRESULT hr = S_OK;
  703. if (bDefaultList)
  704. {
  705. VARIANT * pVariant = _PAllocateVariantInfo(bstrAttrName);
  706. if (pVariant == NULL)
  707. hr = E_OUTOFMEMORY;
  708. else
  709. {
  710. pVariant->vt = VT_BOOL;
  711. pVariant->boolVal = (VARIANT_BOOL)fAttrValue;
  712. }
  713. }
  714. else
  715. {
  716. CComVariant v;
  717. v.vt = VT_BOOL;
  718. v.boolVal = (VARIANT_BOOL)fAttrValue;
  719. hr = _HrSetAttributeVariant(bstrAttrName, &v);
  720. }
  721. return hr;
  722. }
  723. /////////////////////////////////////////////////////////////////////
  724. // HrAddVariantCopyVar()
  725. //
  726. // Add an exact copy of an existing variant to the list.
  727. // This is the most generic routine to add a variant type that does
  728. // not have a frienldy wrapper.
  729. //
  730. // INTERFACE NOTES
  731. // Depending on the type of variant to be copied, the routine may
  732. // allocate extra memory to store the data.
  733. // - If pvargSrc is a VT_BSTR, a copy of the string is made.
  734. // - If pvargSrc is a VT_ARRAY, the entire array is copied.
  735. // The user must clear the variant using ClearVariant(varSrc) when no longer needed.
  736. //
  737. HRESULT
  738. CNewADsObjectCreateInfo::HrAddVariantCopyVar(IN BSTR bstrAttrName, IN VARIANT varSrc,
  739. BOOL bDefaultList)
  740. {
  741. ASSERT(bstrAttrName != NULL);
  742. HRESULT hr = S_OK;
  743. if (bDefaultList)
  744. {
  745. VARIANT * pVariant = _PAllocateVariantInfo(bstrAttrName);
  746. if (pVariant == NULL)
  747. hr = E_OUTOFMEMORY;
  748. else
  749. hr = ::VariantCopy(OUT pVariant, IN &varSrc);
  750. }
  751. else
  752. hr = _HrSetAttributeVariant(bstrAttrName, IN &varSrc);
  753. return hr;
  754. } // HrAddVariantCopyVar()
  755. /////////////////////////////////////////////////////////////////////
  756. // HrGetAttributeVariant()
  757. //
  758. // Routine to get the attribute variant by calling pIADs->Get().
  759. //
  760. // Sometimes there are attributes (typically flags) that
  761. // cannot be set directly.
  762. // 1. The flag must be read using pIADs->Get().
  763. // 2. The flag is updated by changing some bits (using binary operators)
  764. // 3. The flag is written back using pIADs->Put().
  765. //
  766. // INTERFACE NOTES
  767. // - This routine is only available after the object has been
  768. // successfully created.
  769. // - The variant does NOT need to be initialized. The routine
  770. // will initialize the variant for you.
  771. //
  772. HRESULT CNewADsObjectCreateInfo::HrGetAttributeVariant(BSTR bstrAttrName, OUT VARIANT * pvarData)
  773. {
  774. ASSERT(bstrAttrName != NULL);
  775. ASSERT(pvarData != NULL);
  776. VariantInit(OUT pvarData);
  777. ASSERT(m_pIADs != NULL && "You must call HrSetInfo() first before extracting data from object.");
  778. return m_pIADs->Get(bstrAttrName, OUT pvarData);
  779. } // HrGetAttributeVariant()
  780. //////////////////////////////////////////////////////////////////////
  781. // HrSetAttributeVariant
  782. HRESULT
  783. CNewADsObjectCreateInfo::_HrSetAttributeVariant(BSTR bstrAttrName, IN VARIANT * pvarData)
  784. {
  785. ASSERT(bstrAttrName != NULL);
  786. ASSERT(pvarData != NULL);
  787. HRESULT hr = m_pIADs->Put(bstrAttrName, IN *pvarData);
  788. return hr;
  789. }
  790. //////////////////////////////////////////////////////////////////////
  791. // _HrClearAttribute
  792. HRESULT
  793. CNewADsObjectCreateInfo::_HrClearAttribute(BSTR bstrAttrName)
  794. {
  795. ASSERT(m_pIADs != NULL);
  796. ASSERT(bstrAttrName != NULL);
  797. HRESULT hr = S_OK;
  798. CComVariant varVal;
  799. // see if the attribute is there
  800. HRESULT hrFind = m_pIADs->Get(bstrAttrName, &varVal);
  801. if (SUCCEEDED(hrFind))
  802. {
  803. // found, need to clear the property
  804. if (m_bPostCommit)
  805. {
  806. // remove from the committed object
  807. hr = m_pIADs->PutEx(ADS_PROPERTY_CLEAR, bstrAttrName, varVal);
  808. }
  809. else
  810. {
  811. // remove from the cache of the temporary object
  812. IADsPropertyList* pPropList = NULL;
  813. hr = m_pIADs->QueryInterface(IID_IADsPropertyList, (void**)&pPropList);
  814. ASSERT(pPropList != NULL);
  815. if (SUCCEEDED(hr))
  816. {
  817. CComVariant v;
  818. v.vt = VT_BSTR;
  819. v.bstrVal = ::SysAllocString(bstrAttrName);
  820. hr = pPropList->ResetPropertyItem(v);
  821. pPropList->Release();
  822. }
  823. }
  824. }
  825. return hr;
  826. }
  827. /////////////////////////////////////////////////////////////////
  828. // CNewADsObjectCreateInfo:: HrLoadCreationInfo()
  829. //
  830. // The routine will do a lookup to match m_pszObjectClass
  831. // to the best "create routine". If no match is found,
  832. // the create routine will point to the "Generic Create" wizard.
  833. //
  834. HRESULT CNewADsObjectCreateInfo::HrLoadCreationInfo()
  835. {
  836. ASSERT(m_pszObjectClass != NULL);
  837. ASSERT(lstrlen(m_pszObjectClass) > 0);
  838. // Load the creation information from the display specifiers
  839. ASSERT(m_pCreateInfo == NULL);
  840. ASSERT(m_pfnCreateObject == NULL);
  841. HRESULT hr = ::DsGetClassCreationInfoEx(GetBasePathsInfo(), m_pszObjectClass, &m_pCreateInfo);
  842. if (FAILED(hr))
  843. return hr;
  844. ASSERT(m_pCreateInfo != NULL);
  845. // Set the default to point to the "Generic Create" wizard
  846. m_pfnCreateObject = HrCreateADsObjectGenericWizard;
  847. // Given an class name, search the lookup table for a specific create routine
  848. BOOL bFound = FALSE;
  849. for (int i = 0; i < ARRAYLEN(g_rgcno); i++)
  850. {
  851. ASSERT(g_rgcno[i].pszObjectClass != NULL);
  852. ASSERT(g_rgcno[i].pfnCreate != NULL);
  853. // compare class name
  854. if (0 == lstrcmp(g_rgcno[i].pszObjectClass, m_pszObjectClass))
  855. {
  856. // found matching class, compare provided GUID
  857. if ( (m_pCreateInfo->dwFlags & DSCCIF_HASWIZARDPRIMARYPAGE) &&
  858. (m_pCreateInfo->clsidWizardPrimaryPage == *(g_rgcno[i].pWizardGUID)) )
  859. {
  860. if ( IsStandaloneUI() && ((g_rgcno[i].dwFlags & CNOF_STANDALONE_UI)==0) )
  861. {
  862. return E_INVALIDARG;
  863. }
  864. else
  865. {
  866. // found matching GUID, this is our wizard
  867. m_pfnCreateObject = g_rgcno[i].pfnCreate;
  868. m_pvCreationParameter = g_rgcno[i].pvCreationParameter;
  869. bFound = TRUE;
  870. } // if
  871. } // if
  872. break;
  873. } // if
  874. } // for
  875. if (!bFound)
  876. {
  877. // we did not find any matching class name, but we might
  878. // have a derived class with a known wizard GUID
  879. for (i = 0; i < ARRAYLEN(g_rgcno); i++)
  880. {
  881. ASSERT(g_rgcno[i].pszObjectClass != NULL);
  882. ASSERT(g_rgcno[i].pfnCreate != NULL);
  883. // found matching class
  884. if ((m_pCreateInfo->dwFlags & DSCCIF_HASWIZARDPRIMARYPAGE) &&
  885. (m_pCreateInfo->clsidWizardPrimaryPage == *(g_rgcno[i].pWizardGUID)))
  886. {
  887. if ( IsStandaloneUI() && ((g_rgcno[i].dwFlags & CNOF_STANDALONE_UI)==0) )
  888. {
  889. return E_INVALIDARG;
  890. }
  891. else
  892. {
  893. // found matching GUID, this is our wizard
  894. m_pfnCreateObject = g_rgcno[i].pfnCreate;
  895. m_pvCreationParameter = g_rgcno[i].pvCreationParameter;
  896. bFound = TRUE;
  897. } // if
  898. break;
  899. } // if
  900. } // for
  901. } // if
  902. if ( !bFound && (m_pCreateInfo->dwFlags & DSCCIF_HASWIZARDPRIMARYPAGE) &&
  903. (m_pCreateInfo->clsidWizardPrimaryPage != GUID_NULL) )
  904. {
  905. // we have a non null GUID,
  906. // assume this is provided a new dialog for creation
  907. m_pfnCreateObject = HrCreateADsObjectOverride;
  908. } // if
  909. ASSERT(m_pfnCreateObject != NULL);
  910. if ((m_pfnCreateObject == HrCreateADsObjectGenericWizard) && IsStandaloneUI())
  911. {
  912. // cannot call generic wizard under these conditions, just bail out
  913. m_pfnCreateObject = NULL;
  914. return E_INVALIDARG;
  915. }
  916. // finally we have a function pointer
  917. ASSERT(m_pfnCreateObject != NULL);
  918. return S_OK;
  919. }
  920. /////////////////////////////////////////////////////////////////////
  921. // HrDoModal()
  922. //
  923. // Invoke a dialog to create a new object.
  924. //
  925. // RETURNS
  926. // The return value depends on the return value of the "create routine".
  927. // S_OK - The object was created and persisted successfully.
  928. // S_FALSE - The user hit the "Cancel" button or object creation failed.
  929. //
  930. // INTERFACE NOTES
  931. // The "create routine" will validate the data and create the object.
  932. // If the object creation fails, the routine should display an error
  933. // message and return S_FALSE.
  934. //
  935. // EXTRA INFO
  936. // The "create routine" will validate the data and store each
  937. // attribute into a list of variants.
  938. //
  939. HRESULT
  940. CNewADsObjectCreateInfo::HrDoModal(HWND hWnd)
  941. {
  942. CThemeContextActivator activator;
  943. ASSERT(m_pszObjectClass != NULL);
  944. ASSERT(lstrlen(m_pszObjectClass) > 0);
  945. // Load the creation information from the display specifiers
  946. ASSERT(m_pCreateInfo != NULL);
  947. ASSERT(m_pfnCreateObject != NULL);
  948. if (m_pfnCreateObject == NULL)
  949. return E_INVALIDARG;
  950. ASSERT(hWnd != NULL);
  951. m_hWnd = hWnd;
  952. HRESULT hr = E_UNEXPECTED;
  953. TRY
  954. {
  955. // Invoke the "create routine" which will bring a wizard.
  956. hr = m_pfnCreateObject(INOUT this);
  957. }
  958. CATCH(CMemoryException, e)
  959. {
  960. hr = E_OUTOFMEMORY;
  961. ASSERT(e != NULL);
  962. e->Delete();
  963. }
  964. AND_CATCH_ALL(e)
  965. {
  966. hr = E_FAIL;
  967. ASSERT(e != NULL);
  968. e->Delete();
  969. }
  970. END_CATCH_ALL;
  971. return hr;
  972. } // HrDoModal()
  973. /////////////////////////////////////////////////////////////////////
  974. // HrCreateNew()
  975. HRESULT
  976. CNewADsObjectCreateInfo::HrCreateNew(LPCWSTR pszName, BOOL bSilentError, BOOL bAllowCopy)
  977. {
  978. ASSERT(m_bPostCommit == FALSE);
  979. ASSERT(m_pIADsContainer != NULL);
  980. CWaitCursor wait;
  981. // get rid of old object if there
  982. if (m_pIADs != NULL)
  983. {
  984. m_pIADs->Release();
  985. m_pIADs = NULL;
  986. }
  987. // set the given name
  988. m_strObjectName = pszName;
  989. ASSERT(!m_strObjectName.IsEmpty());
  990. if (m_strObjectName.IsEmpty())
  991. return E_INVALIDARG;
  992. m_strObjectName.TrimRight();
  993. m_strObjectName.TrimLeft();
  994. HRESULT hr;
  995. IDispatch * pIDispatch = NULL;
  996. CString strADsName = m_strADsName;
  997. if (strADsName.IsEmpty())
  998. {
  999. strADsName = m_szCacheNamingAttribute; // Typically "cn"
  1000. strADsName += L"=";
  1001. strADsName += GetName();
  1002. }
  1003. TRACE(_T("name, before escaping: %ws\n"), strADsName);
  1004. CComBSTR bsEscapedName;
  1005. CPathCracker pathCracker;
  1006. hr = pathCracker.GetEscapedElement(0, //reserved
  1007. (BSTR)(LPCWSTR)strADsName,
  1008. &bsEscapedName);
  1009. #ifdef TESTING
  1010. hr = _EscapeRDN ((BSTR)(LPCWSTR)strADsName,
  1011. &bsEscapedName);
  1012. #endif
  1013. if (FAILED(hr))
  1014. goto CleanUp;
  1015. TRACE(_T("name, after escaping: %ws\n"), bsEscapedName);
  1016. hr = m_pIADsContainer->Create(CComBSTR(m_pszObjectClass),
  1017. CComBSTR(bsEscapedName),
  1018. OUT &pIDispatch);
  1019. if (FAILED(hr))
  1020. goto CleanUp;
  1021. ASSERT(pIDispatch != NULL);
  1022. hr = pIDispatch->QueryInterface(IID_IADs, OUT (LPVOID *)&m_pIADs);
  1023. if (FAILED(hr))
  1024. {
  1025. m_pIADs = NULL;
  1026. goto CleanUp;
  1027. }
  1028. // if copy operation, do a bulk copy
  1029. if ((m_pCopyHandler != NULL) && bAllowCopy)
  1030. {
  1031. hr = m_pCopyHandler->CopyAtCreation(m_pIADs);
  1032. if (FAILED(hr))
  1033. {
  1034. goto CleanUp;
  1035. }
  1036. }
  1037. // write al the default attributes
  1038. hr = HrAddDefaultAttributes();
  1039. if (FAILED(hr))
  1040. {
  1041. goto CleanUp;
  1042. }
  1043. CleanUp:
  1044. if (pIDispatch != NULL)
  1045. pIDispatch->Release();
  1046. if (FAILED(hr))
  1047. {
  1048. if (!bSilentError)
  1049. {
  1050. PVOID apv[1] = {(LPWSTR)GetName()};
  1051. ReportErrorEx (GetParentHwnd(),IDS_12_GENERIC_CREATION_FAILURE,hr,
  1052. MB_OK | MB_ICONERROR, apv, 1);
  1053. }
  1054. // reset to empty state
  1055. m_strObjectName.Empty();
  1056. }
  1057. return hr;
  1058. }
  1059. /////////////////////////////////////////////////////////////////////
  1060. // HrSetInfo()
  1061. HRESULT
  1062. CNewADsObjectCreateInfo::HrSetInfo(BOOL fSilentError)
  1063. {
  1064. ASSERT(m_pIADsContainer != NULL);
  1065. // we assume that HrCreateNew() has been already called
  1066. ASSERT(m_pIADs != NULL);
  1067. if (m_pIADs == NULL)
  1068. return E_INVALIDARG;
  1069. CWaitCursor wait;
  1070. HRESULT hr;
  1071. // Persist the object. This is it folks!!
  1072. hr = m_pIADs->SetInfo();
  1073. if (FAILED(hr))
  1074. {
  1075. if(!fSilentError)
  1076. {
  1077. PVOID apv[1] = {(LPWSTR)GetName()};
  1078. ReportErrorEx (GetParentHwnd(),IDS_12_GENERIC_CREATION_FAILURE,hr,
  1079. MB_OK | MB_ICONERROR, apv, 1);
  1080. m_strObjectName = L"";
  1081. }
  1082. }
  1083. if (!FAILED(hr))
  1084. {
  1085. // Make sure re-fill the cache
  1086. hr = m_pIADs->GetInfo();
  1087. if (FAILED(hr))
  1088. {
  1089. if (!fSilentError)
  1090. {
  1091. PVOID apv[1] = {(LPWSTR)GetName()};
  1092. ReportErrorEx (GetParentHwnd(),IDS_12_GENERIC_CREATION_FAILURE,hr,
  1093. MB_OK | MB_ICONERROR, apv, 1);
  1094. m_strObjectName = L"";
  1095. }
  1096. }
  1097. }
  1098. return hr;
  1099. } // HrSetInfo()
  1100. ////////////////////////////////////////////////////////////////////
  1101. // HrDeleteFromBackend()
  1102. //
  1103. // deletes object from back end when post commit fails
  1104. //
  1105. HRESULT CNewADsObjectCreateInfo::HrDeleteFromBackend()
  1106. {
  1107. ASSERT(m_pIADsContainer != NULL);
  1108. ASSERT(m_pIADs != NULL);
  1109. // get the name of the object
  1110. CComBSTR bstrName;
  1111. HRESULT hr = m_pIADs->get_Name(&bstrName);
  1112. if (SUCCEEDED(hr))
  1113. {
  1114. // do the actual delete
  1115. ASSERT(bstrName != NULL);
  1116. hr = m_pIADsContainer->Delete(CComBSTR(m_pszObjectClass), bstrName);
  1117. }
  1118. // release the object only if we could delete it
  1119. if (SUCCEEDED(hr))
  1120. SetIADsPtr(NULL);
  1121. return hr;
  1122. }
  1123. /////////////////////////////////////////////////////////////////////////
  1124. // CDsAdminCreateObj
  1125. HRESULT _ReBindToObj(INOUT CComPtr<IADs>& spIADs,
  1126. INOUT CString& szServerName)
  1127. {
  1128. // get the path of the object
  1129. CComBSTR bstrObjectLdapPath;
  1130. HRESULT hr = spIADs->get_ADsPath(&bstrObjectLdapPath);
  1131. if (FAILED(hr))
  1132. {
  1133. return hr;
  1134. }
  1135. // make sure we are bound to a server
  1136. if (szServerName.IsEmpty())
  1137. {
  1138. hr = GetADSIServerName(szServerName, spIADs);
  1139. if (FAILED(hr))
  1140. {
  1141. return hr;
  1142. }
  1143. }
  1144. if (szServerName.IsEmpty())
  1145. {
  1146. return E_INVALIDARG;
  1147. }
  1148. // rebuild the LDAP path with the server
  1149. CPathCracker pathCracker;
  1150. CComBSTR bsX500DN;
  1151. pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
  1152. pathCracker.Set(bstrObjectLdapPath, ADS_SETTYPE_FULL);
  1153. pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_ON);
  1154. pathCracker.Retrieve(ADS_FORMAT_X500_DN, &bsX500DN);
  1155. CString szNewLdapPath;
  1156. szNewLdapPath.Format(L"LDAP://%s/%s", (LPCWSTR)szServerName, bsX500DN);
  1157. // bind to the object again
  1158. CComPtr<IADs> spADsObjNew;
  1159. hr = DSAdminOpenObject(szNewLdapPath,
  1160. IID_IADs,
  1161. (void **)&spADsObjNew,
  1162. TRUE /*bServer*/);
  1163. if (FAILED(hr))
  1164. {
  1165. return hr;
  1166. }
  1167. // update smart pointer
  1168. spIADs = spADsObjNew;
  1169. return S_OK;
  1170. }
  1171. HRESULT _ReBindToContainer(INOUT CComPtr<IADsContainer>& spADsContainerObj,
  1172. INOUT CString& szServerName)
  1173. {
  1174. // get the path of the container
  1175. CComPtr<IADs> spIADsCont;
  1176. HRESULT hr = spADsContainerObj->QueryInterface(IID_IADs, (void**)&spIADsCont);
  1177. if (FAILED(hr))
  1178. {
  1179. return hr;
  1180. }
  1181. hr = _ReBindToObj(spIADsCont, szServerName);
  1182. if (FAILED(hr))
  1183. {
  1184. return hr;
  1185. }
  1186. CComPtr<IADsContainer> spADsContainerObjNew;
  1187. hr = spIADsCont->QueryInterface(IID_IADsContainer, (void**)&spADsContainerObjNew);
  1188. if (FAILED(hr))
  1189. {
  1190. return hr;
  1191. }
  1192. // update smart pointer
  1193. spADsContainerObj = spADsContainerObjNew;
  1194. return S_OK;
  1195. }
  1196. HRESULT CDsAdminCreateObj::Initialize(IADsContainer* pADsContainerObj,
  1197. IADs* pADsCopySource,
  1198. LPCWSTR lpszClassName)
  1199. {
  1200. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1201. if ((pADsContainerObj == NULL) || (lpszClassName == NULL))
  1202. {
  1203. // must have valid pointers
  1204. return E_INVALIDARG;
  1205. }
  1206. m_szObjectClass = lpszClassName;
  1207. m_szObjectClass.TrimRight();
  1208. m_szObjectClass.TrimLeft();
  1209. if (m_szObjectClass.IsEmpty())
  1210. {
  1211. // passed blank?
  1212. return E_INVALIDARG;
  1213. }
  1214. if ((pADsCopySource != NULL) && (m_szObjectClass != L"user")
  1215. #ifdef INETORGPERSON
  1216. && (m_szObjectClass != L"inetOrgPerson")
  1217. #endif
  1218. )
  1219. {
  1220. // we allow the copy operation only for users
  1221. return E_INVALIDARG;
  1222. }
  1223. // make sure we have the right LDAP path
  1224. m_spADsContainerObj = pADsContainerObj;
  1225. CString szServerName;
  1226. HRESULT hr = _ReBindToContainer(m_spADsContainerObj, szServerName);
  1227. if (FAILED(hr))
  1228. {
  1229. return hr;
  1230. }
  1231. hr = m_basePathsInfo.InitFromContainer(m_spADsContainerObj);
  1232. if (FAILED(hr))
  1233. {
  1234. return hr;
  1235. }
  1236. hr = _GetNamingAttribute();
  1237. if (FAILED(hr))
  1238. {
  1239. return hr;
  1240. }
  1241. ASSERT(m_pNewADsObjectCreateInfo == NULL);
  1242. if (m_pNewADsObjectCreateInfo != NULL)
  1243. delete m_pNewADsObjectCreateInfo;
  1244. m_pNewADsObjectCreateInfo = new CNewADsObjectCreateInfo(&m_basePathsInfo, m_szObjectClass);
  1245. if (m_pNewADsObjectCreateInfo == NULL)
  1246. return E_OUTOFMEMORY;
  1247. m_pNewADsObjectCreateInfo->SetContainerInfo(m_spADsContainerObj, NULL, NULL, m_szNamingAttribute);
  1248. // copy operation, need to set the copy source
  1249. if (pADsCopySource != NULL)
  1250. {
  1251. CComPtr<IADs> spADsCopySource = pADsCopySource;
  1252. hr = _ReBindToObj(spADsCopySource, szServerName);
  1253. if (FAILED(hr))
  1254. {
  1255. return hr;
  1256. }
  1257. hr = m_pNewADsObjectCreateInfo->SetCopyInfo(spADsCopySource);
  1258. if (FAILED(hr))
  1259. {
  1260. return hr;
  1261. }
  1262. }
  1263. hr = m_pNewADsObjectCreateInfo->HrLoadCreationInfo();
  1264. if (FAILED(hr))
  1265. {
  1266. delete m_pNewADsObjectCreateInfo;
  1267. m_pNewADsObjectCreateInfo = NULL;
  1268. }
  1269. return hr;
  1270. }
  1271. HRESULT CDsAdminCreateObj::CreateModal(HWND hwndParent,
  1272. IADs** ppADsObj)
  1273. {
  1274. CThemeContextActivator activator;
  1275. if ( (m_pNewADsObjectCreateInfo == NULL)
  1276. || (hwndParent == NULL) || (m_spADsContainerObj == NULL)
  1277. || m_szObjectClass.IsEmpty() || m_szNamingAttribute.IsEmpty())
  1278. return E_INVALIDARG;
  1279. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1280. HRESULT hr = m_pNewADsObjectCreateInfo->HrDoModal(hwndParent);
  1281. IADs* pIADs = m_pNewADsObjectCreateInfo->PGetIADsPtr();
  1282. if ( (hr != S_FALSE) && SUCCEEDED(hr) && (ppADsObj != NULL))
  1283. {
  1284. *ppADsObj = pIADs;
  1285. pIADs = NULL; // transfer ownership
  1286. }
  1287. if (pIADs != NULL)
  1288. pIADs->Release();
  1289. return hr;
  1290. }
  1291. HRESULT CDsAdminCreateObj::_GetNamingAttribute()
  1292. {
  1293. CString szSchemaPath;
  1294. m_basePathsInfo.GetAbstractSchemaPath(szSchemaPath);
  1295. ASSERT(!szSchemaPath.IsEmpty());
  1296. CString szSchemaClassPath;
  1297. szSchemaClassPath.Format(L"%s/%s", (LPCWSTR)szSchemaPath,
  1298. (LPCWSTR)m_szObjectClass);
  1299. CComPtr<IADsClass> spDsClass;
  1300. CComBSTR bstr = szSchemaClassPath;
  1301. HRESULT hr = DSAdminOpenObject(bstr,
  1302. IID_IADsClass,
  1303. (void**)&spDsClass,
  1304. TRUE /*bServer*/);
  1305. if (FAILED(hr))
  1306. return hr;
  1307. CComVariant Var;
  1308. hr = spDsClass->get_NamingProperties(&Var);
  1309. if (FAILED(hr))
  1310. {
  1311. m_szNamingAttribute.Empty();
  1312. return hr;
  1313. }
  1314. m_szNamingAttribute = Var.bstrVal;
  1315. return hr;
  1316. }