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.

532 lines
8.4 KiB

  1. #pragma hdrstop
  2. #include <ctballs.hxx>
  3. #include <sem32.hxx>
  4. // We need a semaphore to synchronize loads and releases.
  5. CMutexSem mxsLoadRelease;
  6. SAFE_INTERFACE_PTR(XIStream, IStream)
  7. #define XPOS L"XPOS"
  8. #define YPOS L"YPOS"
  9. HRESULT ReadPos(IStorage *pstg, LPOLESTR pwszStream, ULONG *pulPos)
  10. {
  11. HRESULT hr;
  12. BEGIN_BLOCK
  13. XIStream xstrm;
  14. // Read the streams for xpos and ypos
  15. hr = pstg->OpenStream(pwszStream, NULL,
  16. STGM_READ | STGM_SHARE_EXCLUSIVE, NULL, &xstrm);
  17. if (FAILED(hr))
  18. {
  19. EXIT_BLOCK;
  20. }
  21. ULONG cb;
  22. hr = xstrm->Read(pulPos, sizeof(*pulPos), &cb);
  23. if (FAILED(hr))
  24. {
  25. EXIT_BLOCK;
  26. }
  27. hr = ResultFromScode(S_OK);
  28. END_BLOCK
  29. return hr;
  30. }
  31. HRESULT WritePos(IStorage *pstg, LPOLESTR pwszStream, ULONG ulPos)
  32. {
  33. HRESULT hr;
  34. BEGIN_BLOCK
  35. XIStream xstrm;
  36. // Read the streams for xpos and ypos
  37. hr = pstg->CreateStream(pwszStream,
  38. STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, NULL, NULL,
  39. &xstrm);
  40. if (FAILED(hr))
  41. {
  42. EXIT_BLOCK;
  43. }
  44. ULONG cb;
  45. hr = xstrm->Write(&ulPos, sizeof(ulPos), &cb);
  46. if (FAILED(hr))
  47. {
  48. EXIT_BLOCK;
  49. }
  50. hr = ResultFromScode(S_OK);
  51. END_BLOCK
  52. return hr;
  53. }
  54. CTestBalls::CTestBalls(REFCLSID rclsid)
  55. : _rclsid(rclsid), _fDirty(FALSE), _xPos(0), _yPos(0),
  56. _fSaveInprogress(FALSE), _pstg(NULL), _dwRegister(0), _cRefs(1)
  57. {
  58. // Use as a flag for whether a file name has been assigned
  59. _awszCurFile[0] = 0;
  60. GlobalRefs(TRUE);
  61. }
  62. CTestBalls::~CTestBalls(void)
  63. {
  64. if (_pstg != NULL)
  65. {
  66. // Release the storage because we are done with it
  67. ULONG ulCnt = _pstg->Release();
  68. #if 0
  69. // this test is not valud when running stress
  70. if (ulCnt != 0)
  71. {
  72. DebugBreak();
  73. }
  74. #endif
  75. }
  76. if (_dwRegister)
  77. {
  78. IRunningObjectTable *prot;
  79. GetRunningObjectTable(NULL, &prot);
  80. prot->Revoke(_dwRegister);
  81. prot->Release();
  82. }
  83. GlobalRefs(FALSE);
  84. }
  85. STDMETHODIMP CTestBalls::QueryInterface(REFIID iid, void **ppv)
  86. {
  87. HRESULT hr = ResultFromScode(S_OK);
  88. // We support IUnknown, IPersistFile and IBalls
  89. if (IsEqualIID(iid, IID_IUnknown))
  90. {
  91. *ppv = (IBalls *) this;
  92. }
  93. else if (IsEqualIID(iid, IID_IPersistFile))
  94. {
  95. *ppv = (IPersistFile *) this;
  96. }
  97. else if (IsEqualIID(iid, IID_IPersistStorage))
  98. {
  99. *ppv = (IPersistStorage *) this;
  100. }
  101. else if (IsEqualIID(iid, IID_IBalls))
  102. {
  103. *ppv = (IBalls *) this;
  104. }
  105. else
  106. {
  107. *ppv = NULL;
  108. hr = ResultFromScode(E_NOINTERFACE);
  109. }
  110. if (SUCCEEDED(hr))
  111. {
  112. AddRef();
  113. }
  114. return hr;
  115. }
  116. STDMETHODIMP_(ULONG) CTestBalls::AddRef(void)
  117. {
  118. InterlockedIncrement(&_cRefs);
  119. return _cRefs;
  120. }
  121. STDMETHODIMP_(ULONG) CTestBalls::Release(void)
  122. {
  123. CLock lck(mxsLoadRelease);
  124. if (InterlockedDecrement(&_cRefs) == 0)
  125. {
  126. delete this;
  127. return 0;
  128. }
  129. return _cRefs;
  130. }
  131. STDMETHODIMP CTestBalls::GetClassID(LPCLSID lpClassID)
  132. {
  133. *lpClassID = _rclsid;
  134. return ResultFromScode(S_OK);
  135. }
  136. STDMETHODIMP CTestBalls::IsDirty()
  137. {
  138. return (_fDirty) ? ResultFromScode(S_OK) : ResultFromScode(S_FALSE);
  139. }
  140. STDMETHODIMP CTestBalls::Load(LPCOLESTR lpszFileName, DWORD grfMode)
  141. {
  142. CLock lck(mxsLoadRelease);
  143. HRESULT hr;
  144. BEGIN_BLOCK
  145. hr = StgOpenStorage(lpszFileName, NULL,
  146. STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, NULL, &_pstg);
  147. if (FAILED(hr))
  148. {
  149. #if 0
  150. // this test is not valid when running stress
  151. if (hr == STG_E_LOCKVIOLATION)
  152. {
  153. DebugBreak();
  154. }
  155. #endif
  156. EXIT_BLOCK;
  157. }
  158. // Get the saved xposition
  159. hr = GetData();
  160. if (FAILED(hr))
  161. {
  162. EXIT_BLOCK;
  163. }
  164. // Since everything went Ok save the file name
  165. olestrcpy(_awszCurFile, lpszFileName);
  166. // Create a file moniker for the object
  167. IMoniker *pmk;
  168. CreateFileMoniker(lpszFileName, &pmk);
  169. // Register it in the running object table.
  170. IRunningObjectTable *prot;
  171. GetRunningObjectTable(NULL, &prot);
  172. prot->Register(NULL, (IPersistFile *) this, pmk, &_dwRegister);
  173. // Release the temporary objects
  174. pmk->Release();
  175. prot->Release();
  176. END_BLOCK
  177. return hr;
  178. }
  179. STDMETHODIMP CTestBalls::Save(LPCOLESTR lpszFileName, BOOL fRemember)
  180. {
  181. HRESULT hr;
  182. BEGIN_BLOCK
  183. IStorage *pstgNew;
  184. // Save the data
  185. if (olestrcmp(lpszFileName, _awszCurFile) == 0)
  186. {
  187. pstgNew = _pstg;
  188. _fDirty = FALSE;
  189. }
  190. else
  191. {
  192. hr = StgCreateDocfile(lpszFileName,
  193. STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  194. NULL, &pstgNew);
  195. }
  196. if (FAILED(hr))
  197. {
  198. EXIT_BLOCK;
  199. }
  200. WriteClassStg(pstgNew, _rclsid);
  201. hr = SaveData(pstgNew);
  202. if (FAILED(hr))
  203. {
  204. EXIT_BLOCK;
  205. }
  206. if (fRemember)
  207. {
  208. // Save the file name
  209. olestrcpy(_awszCurFile, lpszFileName);
  210. // Replace the storage
  211. if (_pstg && pstgNew != _pstg)
  212. {
  213. _pstg->Release();
  214. }
  215. _pstg = pstgNew;
  216. _fDirty = FALSE;
  217. }
  218. else
  219. {
  220. pstgNew->Release();
  221. }
  222. _fSaveInprogress = TRUE;
  223. hr = ResultFromScode(S_OK);
  224. END_BLOCK;
  225. return hr;
  226. }
  227. STDMETHODIMP CTestBalls::SaveCompleted(LPCOLESTR lpszFileName)
  228. {
  229. _fSaveInprogress = FALSE;
  230. return ResultFromScode(S_OK);
  231. }
  232. STDMETHODIMP CTestBalls::GetCurFile(LPOLESTR FAR * lpszFileName)
  233. {
  234. // Allocate a buffer for the file and copy in the data
  235. if (_awszCurFile[0] == 0)
  236. {
  237. return ResultFromScode(S_FALSE);
  238. }
  239. IMalloc *pIMalloc;
  240. HRESULT hr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);
  241. if (SUCCEEDED(hr))
  242. {
  243. *lpszFileName = (WCHAR *) pIMalloc->Alloc(
  244. olestrlen((_awszCurFile) + 1) * sizeof(WCHAR));
  245. olestrcpy(*lpszFileName, _awszCurFile);
  246. hr = ResultFromScode(S_OK);
  247. }
  248. return hr;
  249. }
  250. STDMETHODIMP CTestBalls::MoveBall(ULONG xPos, ULONG yPos)
  251. {
  252. if (!_fSaveInprogress)
  253. {
  254. _fDirty = TRUE;
  255. _xPos = xPos;
  256. _yPos = yPos;
  257. return S_OK;
  258. }
  259. // Can't change state because a save is still pending
  260. return ResultFromScode(E_UNEXPECTED);
  261. }
  262. STDMETHODIMP CTestBalls::GetBallPos(ULONG *xPos, ULONG *yPos)
  263. {
  264. *xPos = _xPos;
  265. *yPos = _yPos;
  266. return S_OK;
  267. }
  268. STDMETHODIMP CTestBalls::IsOverLapped(IBalls *pIBall)
  269. {
  270. ULONG xPos;
  271. ULONG yPos;
  272. HRESULT hr = pIBall->GetBallPos(&xPos, &yPos);
  273. if (SUCCEEDED(hr))
  274. {
  275. if ((xPos == _xPos) && (yPos == _yPos))
  276. {
  277. hr = ResultFromScode(S_OK);
  278. }
  279. else
  280. {
  281. hr = ResultFromScode(S_FALSE);
  282. }
  283. }
  284. return hr;
  285. }
  286. STDMETHODIMP CTestBalls::IsContainedIn(ICube *pICube)
  287. {
  288. ULONG xPos;
  289. ULONG yPos;
  290. HRESULT hr = pICube->GetCubePos(&xPos, &yPos);
  291. if (SUCCEEDED(hr))
  292. {
  293. if ((xPos == _xPos) && (yPos == _yPos))
  294. {
  295. hr = ResultFromScode(S_OK);
  296. }
  297. else
  298. {
  299. hr = ResultFromScode(S_FALSE);
  300. }
  301. }
  302. return hr;
  303. }
  304. STDMETHODIMP CTestBalls::Clone(IBalls **ppIBall)
  305. {
  306. CTestBalls *ptballs = new CTestBalls(_rclsid);
  307. ptballs->_xPos = _xPos;
  308. ptballs->_yPos = _yPos;
  309. ptballs->_fDirty = _fDirty;
  310. _pstg->AddRef();
  311. ptballs->_pstg = _pstg;
  312. lstrcpy(ptballs->_awszCurFile, _awszCurFile);
  313. return ResultFromScode(S_OK);
  314. }
  315. STDMETHODIMP CTestBalls::Echo(IUnknown *punkIn, IUnknown**ppunkOut)
  316. {
  317. *ppunkOut = punkIn;
  318. return S_OK;
  319. }
  320. STDMETHODIMP CTestBalls::InitNew(LPSTORAGE pStg)
  321. {
  322. pStg->AddRef();
  323. _pstg = pStg;
  324. WriteClassStg(_pstg, _rclsid);
  325. return ResultFromScode(S_OK);
  326. }
  327. STDMETHODIMP CTestBalls::Load(LPSTORAGE pStg)
  328. {
  329. HRESULT hr;
  330. _pstg = pStg;
  331. hr = GetData();
  332. if (SUCCEEDED(hr))
  333. {
  334. _pstg->AddRef();
  335. }
  336. else
  337. {
  338. _pstg = NULL;
  339. }
  340. return hr;
  341. }
  342. STDMETHODIMP CTestBalls::Save(
  343. LPSTORAGE pStgSave,
  344. BOOL fSameAsLoad)
  345. {
  346. HRESULT hr;
  347. if (!fSameAsLoad)
  348. {
  349. if (_pstg)
  350. _pstg->Release();
  351. _pstg = pStgSave;
  352. pStgSave->AddRef();
  353. }
  354. else
  355. {
  356. pStgSave = _pstg;
  357. }
  358. WriteClassStg(pStgSave, _rclsid);
  359. hr = SaveData(pStgSave);
  360. _fSaveInprogress = TRUE;
  361. return hr;
  362. }
  363. STDMETHODIMP CTestBalls::SaveCompleted(LPSTORAGE pStgSaved)
  364. {
  365. _fSaveInprogress = FALSE;
  366. return ResultFromScode(S_OK);
  367. }
  368. STDMETHODIMP CTestBalls::HandsOffStorage(void)
  369. {
  370. // Figure out what to do here!
  371. return ResultFromScode(E_UNEXPECTED);
  372. }
  373. HRESULT CTestBalls::GetData(void)
  374. {
  375. HRESULT hr;
  376. BEGIN_BLOCK
  377. // Get the saved xposition
  378. hr = ReadPos(_pstg, XPOS, &_xPos);
  379. if (FAILED(hr))
  380. {
  381. EXIT_BLOCK;
  382. }
  383. // Get the saved yposition
  384. hr = ReadPos(_pstg, YPOS, &_yPos);
  385. END_BLOCK
  386. return hr;
  387. }
  388. HRESULT CTestBalls::SaveData(IStorage *pstg)
  389. {
  390. HRESULT hr;
  391. BEGIN_BLOCK
  392. // Get the saved xposition
  393. hr = WritePos(pstg, XPOS, _xPos);
  394. if (FAILED(hr))
  395. {
  396. EXIT_BLOCK;
  397. }
  398. // Get the saved yposition
  399. hr = WritePos(pstg, YPOS, _yPos);
  400. END_BLOCK
  401. return hr;
  402. }