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.

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