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.

537 lines
12 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1998 - 2000 , Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // dsobject.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // This file defines the class DBObject.
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 02/20/1998 Original version.
  16. // 10/02/1998 Allow rename through PutValue.
  17. // 04/13/2000 Port to ATL 3.0
  18. //
  19. ///////////////////////////////////////////////////////////////////////////////
  20. #include <ias.h>
  21. #include <iasutil.h>
  22. #include <dsenum.h>
  23. #include <dsobject.h>
  24. #include <localtxn.h>
  25. #include <oledbstore.h>
  26. #include <guard.h>
  27. #include <varvec.h>
  28. #include <memory>
  29. //////////
  30. // ATL implementation of IEnumVARIANT
  31. //////////
  32. typedef CComEnum< IEnumVARIANT,
  33. &__uuidof(IEnumVARIANT),
  34. VARIANT,
  35. _Copy<VARIANT>,
  36. CComMultiThreadModelNoCS
  37. > EnumVARIANT;
  38. //////////
  39. // Test if a property is the special 'name' property.
  40. //////////
  41. inline bool isNameProperty(PCWSTR p) throw ()
  42. {
  43. return (*p == L'N' || *p == L'n') ? !_wcsicmp(p, L"NAME") : false;
  44. }
  45. //////////
  46. // Macro to acquire a scoped lock on the global data store.
  47. //////////
  48. #define LOCK_STORE() \
  49. Guard< CComObjectRootEx< CComMultiThreadModel > >__GUARD__(*store)
  50. //////////
  51. // Macros to begin and commit transactions on the global session.
  52. //////////
  53. #define BEGIN_WRITE_TXN() \
  54. LOCK_STORE(); \
  55. LocalTransaction __TXN__(store->session)
  56. #define COMMIT_WRITE_TXN() \
  57. __TXN__.commit()
  58. DBObject* DBObject::createInstance(
  59. OleDBDataStore* owner,
  60. IDataStoreContainer* container,
  61. ULONG uniqueID,
  62. PCWSTR relativeName
  63. )
  64. {
  65. // Create a new CComObject.
  66. CComObject<DBObject>* newObj;
  67. _com_util::CheckError(CComObject<DBObject>::CreateInstance(&newObj));
  68. // Cast to a DBObject and store it in an auto_ptr in case initialize throws
  69. // an exception.
  70. std::auto_ptr<DBObject> obj(newObj);
  71. // Initialize the object.
  72. obj->initialize(owner, container, uniqueID, relativeName);
  73. // Release and return.
  74. return obj.release();
  75. }
  76. IDataStoreObject* DBObject::spawn(ULONG childID, BSTR childName)
  77. {
  78. DBObject* child = DBObject::createInstance(store, this, childID, childName);
  79. child->InternalAddRef();
  80. return child;
  81. }
  82. STDMETHODIMP DBObject::get_Name(BSTR* pVal)
  83. {
  84. if (pVal == NULL) { return E_INVALIDARG; }
  85. return (*pVal = SysAllocString(name)) ? S_OK : E_OUTOFMEMORY;
  86. }
  87. STDMETHODIMP DBObject::get_Class(BSTR* pVal)
  88. {
  89. if (pVal == NULL) { return E_INVALIDARG; }
  90. return (*pVal = SysAllocString(L"OLE-DB Object")) ? S_OK : E_OUTOFMEMORY;
  91. }
  92. STDMETHODIMP DBObject::get_GUID(BSTR* pVal)
  93. {
  94. if (pVal == NULL) { return E_INVALIDARG; }
  95. WCHAR sz[SZLONG_LENGTH];
  96. _ultow(identity, sz, 10);
  97. return (*pVal = SysAllocString(sz)) ? S_OK : E_OUTOFMEMORY;
  98. }
  99. STDMETHODIMP DBObject::get_Container(IDataStoreContainer** pVal)
  100. {
  101. if (pVal == NULL) { return E_INVALIDARG; }
  102. if (*pVal = parent) { (*pVal)->AddRef(); }
  103. return S_OK;
  104. }
  105. STDMETHODIMP DBObject::GetValue(BSTR bstrName, VARIANT* pVal)
  106. {
  107. if (bstrName == NULL || pVal == NULL) { return E_INVALIDARG; }
  108. VariantInit(pVal);
  109. if (isNameProperty(bstrName))
  110. {
  111. V_BSTR(pVal) = SysAllocString(name);
  112. return (V_BSTR(pVal)) ? (V_VT(pVal) = VT_BSTR), S_OK : E_OUTOFMEMORY;
  113. }
  114. HRESULT hr;
  115. try
  116. {
  117. hr = properties.getValue(bstrName, pVal) ? S_OK : DISP_E_MEMBERNOTFOUND;
  118. }
  119. CATCH_AND_RETURN()
  120. return hr;
  121. }
  122. STDMETHODIMP DBObject::GetValueEx(BSTR bstrName, VARIANT* pVal)
  123. {
  124. RETURN_ERROR(GetValue(bstrName, pVal));
  125. // Is it an array ?
  126. if (V_VT(pVal) != (VT_VARIANT | VT_ARRAY))
  127. {
  128. // No, so we have to convert it to one.
  129. try
  130. {
  131. // Save the single value.
  132. _variant_t single(*pVal, false);
  133. // Create a SAFEARRAY with a single element.
  134. CVariantVector<VARIANT> multi(pVal, 1);
  135. // Load the single value in.
  136. multi[0] = single.Detach();
  137. }
  138. CATCH_AND_RETURN()
  139. }
  140. return S_OK;
  141. }
  142. STDMETHODIMP DBObject::PutValue(BSTR bstrName, VARIANT* pVal)
  143. {
  144. if (bstrName == NULL || pVal == NULL) { return E_INVALIDARG; }
  145. try
  146. {
  147. if (isNameProperty(bstrName))
  148. {
  149. // 'name' property must be a BSTR.
  150. if (V_VT(pVal) != VT_BSTR) { return DISP_E_TYPEMISMATCH; }
  151. // 'name' property must be non-null.
  152. if (V_BSTR(pVal) == NULL) { return E_INVALIDARG; }
  153. // Did it actually change?
  154. if (wcscmp(name, V_BSTR(pVal)) != 0)
  155. {
  156. // Yes, so save the new value ...
  157. name = V_BSTR(pVal);
  158. // ... and set the dirty flag.
  159. nameDirty = true;
  160. }
  161. }
  162. else if (V_VT(pVal) != VT_EMPTY)
  163. {
  164. properties.updateValue(bstrName, pVal);
  165. }
  166. else
  167. {
  168. // If the variant is empty, just erase the property.
  169. properties.erase(bstrName);
  170. }
  171. }
  172. CATCH_AND_RETURN()
  173. return S_OK;
  174. }
  175. STDMETHODIMP DBObject::Update()
  176. {
  177. try
  178. {
  179. BEGIN_WRITE_TXN();
  180. // maybe someone created that same object before the update is called
  181. // (concurent MMC scenario)
  182. DBObject* owner = narrow(parent);
  183. if (identity == 0)
  184. {
  185. identity = store->find.execute(owner->identity, name);
  186. }
  187. if (identity == 0)
  188. {
  189. // If we're newly created, then we have to update our record in
  190. // the Objects table.
  191. // An object always has an owner.
  192. _ASSERT(owner != NULL);
  193. store->create.execute(owner->identity, name);
  194. identity = store->find.execute(owner->identity, name);
  195. // This should never happen since the create succeeded.
  196. _ASSERT(identity != 0);
  197. }
  198. else if (nameDirty)
  199. {
  200. store->update.execute(identity, name, narrow(parent)->identity);
  201. }
  202. // Reset the dirty flag.
  203. nameDirty = false;
  204. store->erase.execute(identity);
  205. store->set.execute(identity, properties);
  206. COMMIT_WRITE_TXN();
  207. }
  208. CATCH_AND_RETURN()
  209. return S_OK;
  210. }
  211. STDMETHODIMP DBObject::Restore()
  212. {
  213. try
  214. {
  215. properties.clear();
  216. LOCK_STORE();
  217. store->get.execute(identity, properties);
  218. }
  219. CATCH_AND_RETURN()
  220. return S_OK;
  221. }
  222. STDMETHODIMP DBObject::Item(BSTR bstrName, IDataStoreProperty** pVal)
  223. {
  224. if (pVal == NULL) { return E_INVALIDARG; }
  225. *pVal = NULL;
  226. _variant_t v;
  227. RETURN_ERROR(GetValue(bstrName, &v));
  228. try
  229. {
  230. // Create a new property object.
  231. (*pVal = DSProperty::createInstance(bstrName, v, this))->AddRef();
  232. }
  233. CATCH_AND_RETURN()
  234. return S_OK;
  235. }
  236. STDMETHODIMP DBObject::get_PropertyCount(long* pVal)
  237. {
  238. if (pVal == NULL) { return E_INVALIDARG; }
  239. // Add one for the special 'name' property.
  240. *pVal = properties.size() + 1;
  241. return S_OK;
  242. }
  243. STDMETHODIMP DBObject::get_NewPropertyEnum(IUnknown** pVal)
  244. {
  245. if (pVal == NULL) { return E_INVALIDARG; }
  246. *pVal = NULL;
  247. try
  248. {
  249. // Create a temporary array of items.
  250. std::vector<_variant_t> items(properties.size() + 1);
  251. //////////
  252. // Load the special 'name' property.
  253. //////////
  254. std::vector<_variant_t>::iterator i = items.begin();
  255. *i = DSProperty::createInstance(L"name", name, this);
  256. ++i;
  257. //////////
  258. // Load the regular properties into the temporary array.
  259. //////////
  260. PropertyBag::const_iterator j = properties.begin();
  261. for ( ; j != properties.end(); ++i, ++j)
  262. {
  263. _variant_t value;
  264. j->second.get(&value);
  265. *i = DSProperty::createInstance(j->first, value, this);
  266. }
  267. //////////
  268. // Create and initialize an enumerator for the items.
  269. //////////
  270. CComPtr<EnumVARIANT> newEnum(new CComObject<EnumVARIANT>);
  271. _com_util::CheckError(newEnum->Init(items.begin(),
  272. items.end(),
  273. NULL,
  274. AtlFlagCopy));
  275. // Return it to the caller.
  276. (*pVal = newEnum)->AddRef();
  277. }
  278. CATCH_AND_RETURN()
  279. return S_OK;
  280. }
  281. STDMETHODIMP DBObject::Item(BSTR bstrName, IDataStoreObject** ppObject)
  282. {
  283. if (bstrName == NULL || ppObject == NULL) { return E_INVALIDARG; }
  284. *ppObject = NULL;
  285. try
  286. {
  287. LOCK_STORE();
  288. ULONG childID = store->find.execute(identity, bstrName);
  289. if (childID == 0) { return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); }
  290. *ppObject = spawn(childID, bstrName);
  291. }
  292. CATCH_AND_RETURN()
  293. return S_OK;
  294. }
  295. STDMETHODIMP DBObject::Create(BSTR /* bstrClass */,
  296. BSTR bstrName,
  297. IDataStoreObject** ppObject)
  298. {
  299. if (bstrName == NULL || ppObject == NULL) { return E_INVALIDARG; }
  300. *ppObject = NULL;
  301. try
  302. {
  303. *ppObject = spawn(0, bstrName);
  304. }
  305. CATCH_AND_RETURN()
  306. return S_OK;
  307. }
  308. STDMETHODIMP DBObject::MoveHere(IDataStoreObject* pObject,
  309. BSTR bstrNewName)
  310. {
  311. if (pObject == NULL) { return E_INVALIDARG; }
  312. try
  313. {
  314. // Convert the subject to a DBObject.
  315. DBObject* object = narrow(pObject);
  316. // Can't do this unless the object has been persisted.
  317. if (object->identity == 0) { return E_FAIL; }
  318. // Compute the (possibly changed) RDN of the object.
  319. PCWSTR rdn = bstrNewName ? bstrNewName : object->name;
  320. // Write the new parent ID and possibly name to the database.
  321. BEGIN_WRITE_TXN();
  322. store->update.execute(object->identity, rdn, identity);
  323. COMMIT_WRITE_TXN();
  324. // It succeeded, so save the new name if necessary ...
  325. if (bstrNewName) { object->name = bstrNewName; }
  326. // ... and switch the parent pointer.
  327. object->parent.Release();
  328. object->parent = this;
  329. }
  330. CATCH_AND_RETURN()
  331. return S_OK;
  332. }
  333. STDMETHODIMP DBObject::Remove(BSTR /* bstrClass */, BSTR bstrName)
  334. {
  335. if (bstrName == NULL) { return E_INVALIDARG; }
  336. try
  337. {
  338. BEGIN_WRITE_TXN();
  339. store->destroy.execute(identity, bstrName);
  340. COMMIT_WRITE_TXN();
  341. }
  342. CATCH_AND_RETURN()
  343. return S_OK;
  344. }
  345. STDMETHODIMP DBObject::get_ChildCount(long *pVal)
  346. {
  347. if (pVal == NULL) { return E_INVALIDARG; }
  348. try
  349. {
  350. Rowset rowset;
  351. LOCK_STORE();
  352. store->members.execute(identity, &rowset);
  353. long count = 0;
  354. while (rowset.moveNext()) { ++count; }
  355. // If this is the root, we have to subtract one since the root is a
  356. // child of itself.
  357. if (identity == 1) { --count; }
  358. *pVal = count;
  359. }
  360. CATCH_AND_RETURN()
  361. return S_OK;
  362. }
  363. STDMETHODIMP DBObject::get_NewChildEnum(IUnknown** pVal)
  364. {
  365. if (pVal == NULL) { return E_INVALIDARG; }
  366. try
  367. {
  368. Rowset rowset;
  369. LOCK_STORE();
  370. store->members.execute(identity, &rowset);
  371. (*pVal = new DBEnumerator(this, rowset))->AddRef();
  372. }
  373. CATCH_AND_RETURN()
  374. return S_OK;
  375. }
  376. void DBObject::initialize(
  377. OleDBDataStore* owner,
  378. IDataStoreContainer* container,
  379. ULONG uniqueID,
  380. PCWSTR relativeName
  381. )
  382. {
  383. // Set the class members.
  384. store = owner;
  385. parent = container;
  386. identity = uniqueID;
  387. name = relativeName;
  388. nameDirty = false;
  389. // If this object exists in the persistent store, then get its properties.
  390. if (identity != 0)
  391. {
  392. LOCK_STORE();
  393. store->get.execute(identity, properties);
  394. }
  395. }
  396. DBObject* DBObject::narrow(IUnknown* p)
  397. {
  398. DBObject* object;
  399. using _com_util::CheckError;
  400. CheckError(p->QueryInterface(__uuidof(DBObject), (PVOID*)&object));
  401. // We can get away with InternalRelease since the caller must still
  402. // have a reference to this object.
  403. object->InternalRelease();
  404. return object;
  405. }