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.

1073 lines
33 KiB

  1. #include "shole.h"
  2. #include "ids.h"
  3. #include "scguid.h"
  4. #include <strsafe.h>
  5. #define CLONE_IT_IF_READONLY
  6. class CShClientSite : public IOleClientSite, public IAdviseSink2
  7. {
  8. public:
  9. CShClientSite(HWND hwndOwner, LPCTSTR pszCmdLine);
  10. LPCTSTR ParseCmdLine(LPCTSTR pszCmdLine);
  11. HRESULT Load();
  12. HRESULT DoVerb(LONG iVerb);
  13. void CloseOleObject();
  14. void ReleaseOleObject();
  15. void ReleaseStorage(void);
  16. void MaySaveAs(void);
  17. void Draw(HWND hwnd, HDC hdc);
  18. HRESULT GetFileName(LPTSTR szFile, UINT cchMax);
  19. void Quit(void) { _hwndOwner = NULL ; _fQuit = TRUE; }
  20. BOOL FContinue(void) { return !_fQuit; }
  21. // IUnKnown
  22. virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID,void **);
  23. virtual ULONG STDMETHODCALLTYPE AddRef(void);
  24. virtual ULONG STDMETHODCALLTYPE Release(void);
  25. // IOleClientSite
  26. virtual HRESULT STDMETHODCALLTYPE SaveObject(void);
  27. virtual HRESULT STDMETHODCALLTYPE GetMoniker(DWORD, DWORD, IMoniker **);
  28. virtual HRESULT STDMETHODCALLTYPE GetContainer(IOleContainer **);
  29. virtual HRESULT STDMETHODCALLTYPE ShowObject(void);
  30. virtual HRESULT STDMETHODCALLTYPE OnShowWindow(BOOL fShow);
  31. virtual HRESULT STDMETHODCALLTYPE RequestNewObjectLayout(void);
  32. // IAdviseSink2
  33. virtual void STDMETHODCALLTYPE OnDataChange(FORMATETC *,STGMEDIUM *);
  34. virtual void STDMETHODCALLTYPE OnViewChange(DWORD dwAspect,LONG lindex);
  35. virtual void STDMETHODCALLTYPE OnRename(IMoniker *pmk);
  36. virtual void STDMETHODCALLTYPE OnSave(void);
  37. virtual void STDMETHODCALLTYPE OnClose(void);
  38. virtual void STDMETHODCALLTYPE OnLinkSrcChange(IMoniker *pmk);
  39. protected:
  40. ~CShClientSite();
  41. UINT _cRef;
  42. HWND _hwndOwner;
  43. LPSTORAGE _pstgDoc; // document
  44. LPSTORAGE _pstg; // the embedding (only one)
  45. LPPERSISTSTORAGE _ppstg;
  46. LPOLEOBJECT _pole;
  47. BOOL _fDirty:1;
  48. BOOL _fNeedToSave:1;
  49. BOOL _fReadOnly:1;
  50. BOOL _fCloned:1;
  51. BOOL _fQuit:1;
  52. BOOL _fCloseImmediately:1;
  53. DWORD _dwConnection; // non-zero, if valid
  54. WCHAR _wszFileName[MAX_PATH];
  55. };
  56. typedef CShClientSite * LPSHCLIENTSITE;
  57. const TCHAR c_szAppName[] = TEXT("ShellOleViewer");
  58. LRESULT CALLBACK ShWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
  59. void DisplayError(HWND hwndOwner, HRESULT hres, UINT idsMsg, LPCTSTR szFileName);
  60. HINSTANCE g_hinst = NULL;
  61. extern "C"
  62. BOOL APIENTRY LibMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
  63. {
  64. switch(dwReason) {
  65. case DLL_PROCESS_ATTACH:
  66. g_hinst = (HINSTANCE)hDll;
  67. DisableThreadLibraryCalls(g_hinst);
  68. break;
  69. default:
  70. break;
  71. }
  72. return TRUE;
  73. }
  74. void WINAPI
  75. OpenScrap_RunDLL_Common(HWND hwndStub, HINSTANCE hInstApp, LPTSTR pszCmdLine, int nCmdShow)
  76. {
  77. CShClientSite_RegisterClass();
  78. HWND hwndClientSite = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_OVERLAPPEDWINDOW,
  79. c_szAppName,
  80. #ifdef DEBUG
  81. TEXT("(Debug only) SHOLE.EXE"),
  82. WS_VISIBLE | WS_OVERLAPPEDWINDOW,
  83. #else
  84. TEXT(""),
  85. WS_OVERLAPPEDWINDOW,
  86. #endif
  87. CW_USEDEFAULT, CW_USEDEFAULT,
  88. 128, 128, NULL, NULL, g_hinst, NULL);
  89. if (hwndClientSite)
  90. {
  91. HRESULT hres;
  92. hres = OleInitialize(NULL);
  93. if (SUCCEEDED(hres))
  94. {
  95. DWORD dwTick;
  96. LPSHCLIENTSITE pscs= new CShClientSite(hwndClientSite, pszCmdLine);
  97. if (pscs)
  98. {
  99. UINT cRef;
  100. hres = pscs->Load();
  101. if (SUCCEEDED(hres)) {
  102. hres = pscs->DoVerb(OLEIVERB_OPEN);
  103. }
  104. if (hres == S_OK)
  105. {
  106. MSG msg;
  107. while (pscs->FContinue() && GetMessage(&msg, NULL, 0, 0))
  108. {
  109. TranslateMessage(&msg);
  110. DispatchMessage(&msg);
  111. }
  112. }
  113. else
  114. {
  115. // DoVerb failed.
  116. if (FAILED(hres) || (hres>=IDS_HRES_MIN && hres<IDS_HRES_MAX))
  117. {
  118. TCHAR szFile[MAX_PATH];
  119. HRESULT hrInner = pscs->GetFileName(szFile, ARRAYSIZE(szFile));
  120. if (SUCCEEDED(hrInner))
  121. {
  122. DisplayError(hwndClientSite, hres, IDS_ERR_DOVERB, szFile);
  123. }
  124. }
  125. DestroyWindow(hwndClientSite);
  126. }
  127. //
  128. // We call them just in case, the following Release
  129. // does not release the object.
  130. //
  131. pscs->ReleaseOleObject();
  132. pscs->ReleaseStorage();
  133. pscs->MaySaveAs();
  134. cRef = pscs->Release();
  135. Assert(cRef==0);
  136. }
  137. DebugMsg(DM_TRACE, TEXT("so TR - WinMain About to call OleUninitialize"));
  138. dwTick = GetCurrentTime();
  139. OleUninitialize();
  140. DebugMsg(DM_TRACE, TEXT("so TR - WinMain OleUninitialize took %d ticks"), GetCurrentTime()-dwTick);
  141. }
  142. if (IsWindow(hwndClientSite)) {
  143. DebugMsg(DM_WARNING, TEXT("so WA - WinMain IsWindow(hwndClientSite) is still TRUE"));
  144. DestroyWindow(hwndClientSite);
  145. }
  146. }
  147. }
  148. extern "C" void WINAPI
  149. OpenScrap_RunDLL(HWND hwndStub, HINSTANCE hAppInstance, LPSTR lpszCmdLine, int nCmdShow)
  150. {
  151. UINT iLen = lstrlenA(lpszCmdLine)+1;
  152. LPWSTR lpwszCmdLine;
  153. lpwszCmdLine = (LPWSTR)LocalAlloc(LPTR,iLen*sizeof(WCHAR));
  154. if (lpwszCmdLine)
  155. {
  156. MultiByteToWideChar(CP_ACP, 0,
  157. lpszCmdLine, -1,
  158. lpwszCmdLine, iLen);
  159. OpenScrap_RunDLL_Common( hwndStub,
  160. hAppInstance,
  161. lpwszCmdLine,
  162. nCmdShow );
  163. LocalFree(lpwszCmdLine);
  164. }
  165. }
  166. extern "C" void WINAPI
  167. OpenScrap_RunDLLW(HWND hwndStub, HINSTANCE hAppInstance, LPWSTR lpwszCmdLine, int nCmdShow)
  168. {
  169. OpenScrap_RunDLL_Common( hwndStub,
  170. hAppInstance,
  171. lpwszCmdLine,
  172. nCmdShow );
  173. }
  174. #ifdef DEBUG
  175. //
  176. // Type checking
  177. //
  178. static RUNDLLPROCA lpfnRunDLLA=OpenScrap_RunDLL;
  179. static RUNDLLPROCW lpfnRunDLLW=OpenScrap_RunDLLW;
  180. #endif
  181. void DisplayError(HWND hwndOwner, HRESULT hres, UINT idsMsg, LPCTSTR pszFileName)
  182. {
  183. TCHAR szErrMsg[MAX_PATH*2];
  184. TCHAR szFancyErr[MAX_PATH*2];
  185. HRSRC hrsrc;
  186. if (HIWORD(hres))
  187. {
  188. BOOL fSuccess = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  189. NULL,
  190. hres,
  191. 0,
  192. szErrMsg,
  193. ARRAYSIZE(szErrMsg),
  194. (va_list *)&pszFileName);
  195. if (!fSuccess) {
  196. idsMsg++; // map IDS_ERR_DOVERB to IDS_ERR_DOVERB_F
  197. }
  198. } else {
  199. LoadString(g_hinst, LOWORD(hres), szErrMsg, ARRAYSIZE(szErrMsg));
  200. }
  201. szFancyErr[0] = TEXT('\0');
  202. hrsrc = FindResource(g_hinst, MAKEINTRESOURCE(IDR_FANCYERR), RT_RCDATA);
  203. if (hrsrc)
  204. {
  205. HGLOBAL hmem = LoadResource(g_hinst, hrsrc);
  206. if (hmem)
  207. {
  208. HRESULT* phres = (HRESULT*)LockResource(hmem);
  209. if (phres)
  210. {
  211. UINT i;
  212. LPTSTR pszLoad = szFancyErr;
  213. int cchLeft = ARRAYSIZE(szFancyErr);
  214. for (i=0; phres[i] && cchLeft>0; i++) {
  215. if (phres[i] == hres)
  216. {
  217. int cchRead;
  218. cchRead = LoadString(g_hinst, IDS_FANCYERR+i, pszLoad, cchLeft);
  219. pszLoad += cchRead;
  220. cchLeft -= cchRead;
  221. }
  222. }
  223. //
  224. // If we have a fancy error message, hide ugly message
  225. // from FormatMessage.
  226. //
  227. if (szFancyErr[0]) {
  228. szErrMsg[0] = TEXT('\0');
  229. }
  230. }
  231. }
  232. }
  233. ShellMessageBox(g_hinst,
  234. hwndOwner,
  235. MAKEINTRESOURCE(idsMsg),
  236. MAKEINTRESOURCE(IDS_TITLE_ERR),
  237. MB_OK | MB_ICONWARNING | MB_SETFOREGROUND,
  238. pszFileName,
  239. szErrMsg,
  240. szFancyErr,
  241. hres);
  242. }
  243. void CShClientSite::CloseOleObject()
  244. {
  245. if (_pole)
  246. _pole->Close(OLECLOSE_NOSAVE);
  247. }
  248. void CShClientSite::ReleaseOleObject()
  249. {
  250. UINT cRef;
  251. if (_pole)
  252. {
  253. if (_dwConnection) {
  254. _pole->Unadvise(_dwConnection);
  255. _dwConnection = 0;
  256. }
  257. _pole->SetClientSite(NULL);
  258. cRef = _pole->Release();
  259. DebugMsg(DM_TRACE, TEXT("so - TR SCS::ReleaseOleObject IOleObj::Rel returned (%d)"), cRef);
  260. _pole=NULL;
  261. }
  262. if (_ppstg)
  263. {
  264. cRef=_ppstg->Release();
  265. _ppstg=NULL;
  266. DebugMsg(DM_TRACE, TEXT("so TR - SCS::ReleaseOleObject IPSTG::Release returned (%x)"), cRef);
  267. }
  268. }
  269. void CShClientSite::ReleaseStorage(void)
  270. {
  271. UINT cRef;
  272. if (_pstg)
  273. {
  274. cRef=_pstg->Release();
  275. _pstg=NULL;
  276. DebugMsg(DM_TRACE, TEXT("so TR - SCS::ReleaseStorage _pstg->Release returned (%x)"), cRef);
  277. }
  278. if (_pstgDoc)
  279. {
  280. cRef=_pstgDoc->Release();
  281. _pstgDoc=NULL;
  282. DebugMsg(DM_TRACE, TEXT("so TR - SCS::ReleaseStorage _pstgDoc->Release returned (%x)"), cRef);
  283. }
  284. }
  285. void CShClientSite::MaySaveAs()
  286. {
  287. DebugMsg(DM_TRACE, TEXT("so TR - SCS::MaySaveAs called (%d,%d)"), _fCloned, _fNeedToSave);
  288. if (_fCloned)
  289. {
  290. TCHAR szTempFile[MAX_PATH];
  291. HRESULT hr = StringCchCopy(szTempFile, ARRAYSIZE(szTempFile), _wszFileName);
  292. if (SUCCEEDED(hr))
  293. {
  294. UINT id = IDNO;
  295. if (_fNeedToSave)
  296. {
  297. id= ShellMessageBox(g_hinst,
  298. _hwndOwner,
  299. MAKEINTRESOURCE(IDS_WOULDYOUSAVEAS),
  300. MAKEINTRESOURCE(IDS_TITLE),
  301. MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND,
  302. NULL);
  303. }
  304. DebugMsg(DM_TRACE, TEXT("so TR - SCS::MaySaveAs id==%d"), id);
  305. if (id==IDYES)
  306. {
  307. TCHAR szDesktop[MAX_PATH];
  308. SHGetSpecialFolderPath(NULL, szDesktop, CSIDL_DESKTOP, FALSE);
  309. BOOL fContinue;
  310. do
  311. {
  312. fContinue = FALSE;
  313. TCHAR szFile[MAX_PATH];
  314. TCHAR szFilter[64];
  315. szFile[0] = TEXT('\0');
  316. LoadString(g_hinst, IDS_SCRAPFILTER, szFilter, ARRAYSIZE(szFilter));
  317. OPENFILENAME of = {
  318. SIZEOF(OPENFILENAME), // DWORD lStructSize;
  319. _hwndOwner, // HWND hwndOwner;
  320. NULL, // HINSTANCE hInstance;
  321. szFilter, // LPCSTR lpstrFilter;
  322. NULL, // LPSTR lpstrCustomFilter;
  323. 0, // DWORD nMaxCustFilter;
  324. 1, // DWORD nFilterIndex;
  325. szFile, // LPSTR lpstrFile;
  326. ARRAYSIZE(szFile), // DWORD nMaxFile;
  327. NULL, // LPSTR lpstrFileTitle;
  328. 0, // DWORD nMaxFileTitle;
  329. szDesktop, // LPCSTR lpstrInitialDir;
  330. NULL, // LPCSTR lpstrTitle;
  331. OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT
  332. | OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST,
  333. // DWORD Flags;
  334. 0, // WORD nFileOffset;
  335. 0, // WORD nFileExtension;
  336. TEXT("shs"), // LPCSTR lpstrDefExt;
  337. NULL, // LPARAM lCustData;
  338. NULL, // LPOFNHOOKPROC lpfnHook;
  339. NULL, // LPCSTR lpTemplateName;
  340. };
  341. if (GetSaveFileName(&of))
  342. {
  343. DeleteFile(szFile);
  344. BOOL fRet = MoveFile(szTempFile, szFile);
  345. if (fRet)
  346. {
  347. // Indicated that the temp file is moved
  348. szTempFile[0] = TEXT('\0');
  349. }
  350. else
  351. {
  352. id = ShellMessageBox(g_hinst,
  353. _hwndOwner,
  354. MAKEINTRESOURCE(IDS_MOVEFAILED),
  355. MAKEINTRESOURCE(IDS_TITLE),
  356. MB_YESNO | MB_ICONWARNING | MB_SETFOREGROUND);
  357. if (id==IDYES)
  358. {
  359. fContinue = TRUE;
  360. }
  361. }
  362. }
  363. } while (fContinue);
  364. }
  365. // If the temp file is not moved, delete it.
  366. if (szTempFile[0])
  367. {
  368. DeleteFile(szTempFile);
  369. }
  370. }
  371. }
  372. }
  373. void CShClientSite::Draw(HWND hwnd, HDC hdc)
  374. {
  375. if (_ppstg)
  376. {
  377. HRESULT hres;
  378. RECT rc;
  379. GetClientRect(hwnd, &rc);
  380. hres = OleDraw(_ppstg, DVASPECT_ICON, hdc, &rc);
  381. DebugMsg(DM_TRACE, TEXT("so TR - SCS::Draw OleDraw(DVASPECT_ICON) returned %x"), hres);
  382. if (FAILED(hres))
  383. {
  384. LPVIEWOBJECT2 pview;
  385. hres = _ppstg->QueryInterface(IID_IViewObject2, (LPVOID*)&pview);
  386. if (SUCCEEDED(hres))
  387. {
  388. SIZE size;
  389. hres = pview->GetExtent(DVASPECT_CONTENT, (DWORD)-1,
  390. (DVTARGETDEVICE*)NULL, &size);
  391. DebugMsg(DM_TRACE, TEXT("so TR - SCS::Draw IVO2::GetExtent returned %x"), hres);
  392. if (SUCCEEDED(hres))
  393. {
  394. int mmOld = SetMapMode(hdc, MM_HIMETRIC);
  395. LPtoDP(hdc, (LPPOINT)&size, 1);
  396. rc.right = size.cx;
  397. rc.bottom = -size.cy;
  398. SetMapMode(hdc, mmOld);
  399. }
  400. pview->Release();
  401. }
  402. hres = OleDraw(_ppstg, DVASPECT_CONTENT, hdc, &rc);
  403. DebugMsg(DM_TRACE, TEXT("so TR - SCS::Draw OleDraw(DVASPECT_CONTENT,%d,%d) returned %x"),
  404. hres, rc.right, rc.bottom);
  405. }
  406. LPOLELINK plink;
  407. if (SUCCEEDED(hres = _ppstg->QueryInterface(IID_IOleLink, (LPVOID *)&plink)))
  408. {
  409. LPOLESTR pwsz;
  410. hres = plink->GetSourceDisplayName(&pwsz);
  411. if (SUCCEEDED(hres))
  412. {
  413. TextOut(hdc, 0, 0, pwsz, lstrlen(pwsz));
  414. CoTaskMemFree(pwsz);
  415. }
  416. else
  417. {
  418. DebugMsg(DM_TRACE, TEXT("so TR SCS:Draw IMK:GetSDN failed %x"), hres);
  419. }
  420. plink->Release();
  421. }
  422. else
  423. {
  424. DebugMsg(DM_TRACE, TEXT("so TR SCS:Draw IPSTG:QI failed %x"), hres);
  425. }
  426. }
  427. }
  428. STDMETHODIMP CShClientSite::QueryInterface(REFIID riid,
  429. void **ppvObject)
  430. {
  431. HRESULT hres;
  432. if (IsEqualGUID(riid, CLSID_CShClientSite)) {
  433. _cRef++;
  434. *ppvObject = this;
  435. hres = NOERROR;
  436. }
  437. else if (IsEqualGUID(riid, IID_IOleClientSite) || IsEqualGUID(riid, IID_IUnknown)) {
  438. _cRef++;
  439. *ppvObject = (LPOLECLIENTSITE)this;
  440. hres = NOERROR;
  441. }
  442. else if (IsEqualGUID(riid, IID_IAdviseSink) || IsEqualGUID(riid, IID_IAdviseSink2)) {
  443. _cRef++;
  444. *ppvObject = (LPADVISESINK2)this;
  445. hres = NOERROR;
  446. }
  447. else
  448. {
  449. *ppvObject = NULL;
  450. hres = ResultFromScode(E_NOINTERFACE);
  451. }
  452. return hres;
  453. }
  454. STDMETHODIMP_(ULONG) CShClientSite::AddRef(void)
  455. {
  456. return ++_cRef;
  457. }
  458. STDMETHODIMP_(ULONG) CShClientSite::Release(void)
  459. {
  460. if (--_cRef>0) {
  461. return _cRef;
  462. }
  463. delete this;
  464. return 0;
  465. }
  466. void Scrap_UpdateCachedData(LPSTORAGE pstgDoc, LPOLEOBJECT pole, LPPERSIST pps)
  467. {
  468. extern void Scrap_CacheClipboardData(LPSTORAGE pstgDoc, LPDATAOBJECT pdtobj, LPPERSIST pps);
  469. DebugMsg(DM_TRACE, TEXT("so TR - S_UCD called"));
  470. if (pstgDoc && pole && pps)
  471. {
  472. IDataObject *pdtobj = NULL;
  473. HRESULT hres = pole->QueryInterface(IID_IDataObject, (LPVOID*)&pdtobj);
  474. if (SUCCEEDED(hres)) {
  475. DebugMsg(DM_TRACE, TEXT("so TR - S_UCD QI succeeded"));
  476. Scrap_CacheClipboardData(pstgDoc, pdtobj, pps);
  477. pdtobj->Release();
  478. }
  479. }
  480. }
  481. STDMETHODIMP CShClientSite::SaveObject(void)
  482. {
  483. DebugMsg(DM_TRACE, TEXT("sc TR - CSCS::SaveObject called"));
  484. //
  485. // NOTES: We need to update the cache here.
  486. // Doing so on ::OnSave does not work (async)
  487. // Doing so on ::OnClose is too late.
  488. //
  489. Scrap_UpdateCachedData(_pstgDoc, _pole, _ppstg);
  490. HRESULT hres;
  491. if (_pstg && _ppstg)
  492. {
  493. hres = OleSave(_ppstg, _pstg, TRUE);
  494. if (SUCCEEDED(hres))
  495. {
  496. hres = _ppstg->SaveCompleted(NULL);
  497. }
  498. }
  499. else
  500. {
  501. hres = ResultFromScode(E_FAIL);
  502. }
  503. return hres;
  504. }
  505. STDMETHODIMP CShClientSite::GetMoniker(DWORD dwAssign,
  506. DWORD dwWhichMoniker,
  507. IMoniker **ppmk)
  508. {
  509. HRESULT hres;
  510. *ppmk = NULL;
  511. switch(dwWhichMoniker)
  512. {
  513. case OLEWHICHMK_CONTAINER:
  514. hres = CreateFileMoniker(_wszFileName, ppmk);
  515. break;
  516. case OLEWHICHMK_OBJREL:
  517. hres = CreateItemMoniker(L"\\", L"Object", ppmk);
  518. break;
  519. case OLEWHICHMK_OBJFULL:
  520. {
  521. LPMONIKER pmkItem;
  522. hres = CreateItemMoniker(L"\\", L"Object", &pmkItem);
  523. if (SUCCEEDED(hres))
  524. {
  525. LPMONIKER pmkDoc;
  526. hres = CreateFileMoniker(_wszFileName, &pmkDoc);
  527. if (SUCCEEDED(hres))
  528. {
  529. hres = CreateGenericComposite(pmkDoc, pmkItem, ppmk);
  530. pmkDoc->Release();
  531. }
  532. pmkItem->Release();
  533. }
  534. }
  535. break;
  536. default:
  537. hres = ResultFromScode(E_INVALIDARG);
  538. }
  539. return hres;
  540. }
  541. STDMETHODIMP CShClientSite::GetContainer(
  542. IOleContainer **ppContainer)
  543. {
  544. *ppContainer = NULL;
  545. return ResultFromScode(E_NOINTERFACE);
  546. }
  547. STDMETHODIMP CShClientSite::ShowObject(void)
  548. {
  549. return NOERROR;
  550. }
  551. STDMETHODIMP CShClientSite::OnShowWindow(BOOL fShow)
  552. {
  553. DebugMsg(DM_TRACE, TEXT("so TR - CSCS::OnShowWindow called with %d"), fShow);
  554. return NOERROR;
  555. }
  556. STDMETHODIMP CShClientSite::RequestNewObjectLayout(void)
  557. {
  558. return ResultFromScode(E_NOTIMPL);
  559. }
  560. //
  561. // _cRef <- 2 because _hwndOwner has a reference count as well.
  562. //
  563. CShClientSite::CShClientSite(HWND hwndOwner, LPCTSTR pszCmdLine)
  564. : _cRef(2), _hwndOwner(hwndOwner),
  565. _pstgDoc(NULL), _pstg(NULL), _ppstg(NULL), _pole(NULL),
  566. _fDirty(FALSE), _fNeedToSave(FALSE),
  567. _fReadOnly(FALSE), _fCloned(FALSE), _fCloseImmediately(FALSE),
  568. _fQuit(FALSE)
  569. {
  570. LPCTSTR pszFileName = ParseCmdLine(pszCmdLine);
  571. //
  572. // We'd better deal with quoted LFN name.
  573. //
  574. #ifdef NASHVILLE
  575. //
  576. // Strip out quotes if exists.
  577. //
  578. TCHAR szT[MAX_PATH];
  579. if (*pszFileName==TEXT('"'))
  580. {
  581. StringCchCopy(szT, ARRAYSIZE(szT), pszFileName+1);
  582. LPTSTR pszT = CharPrev(szT, szT+lstrlen(szT));
  583. if (*pszT==TEXT('"')) {
  584. *pszT=TEXT('\0');
  585. }
  586. pszFileName = szT;
  587. }
  588. #endif // NASHVILLE
  589. StringCchCopy(_wszFileName, ARRAYSIZE(_wszFileName), pszFileName);
  590. Assert(_hwndOwner)
  591. SetWindowLongPtr(_hwndOwner, GWLP_USERDATA, (LPARAM)this);
  592. }
  593. CShClientSite::~CShClientSite()
  594. {
  595. ReleaseOleObject();
  596. ReleaseStorage();
  597. DebugMsg(DM_TRACE, TEXT("sc - CShClientSite is being deleted"));
  598. }
  599. LPCTSTR _SkipSpace(LPCTSTR psz)
  600. {
  601. while(*psz==TEXT(' '))
  602. psz++;
  603. return psz;
  604. }
  605. LPCTSTR CShClientSite::ParseCmdLine(LPCTSTR pszCmdLine)
  606. {
  607. for (LPCTSTR psz = _SkipSpace(pszCmdLine);
  608. (*psz == TEXT('/') || *psz == TEXT('-')) && *++psz;
  609. psz = _SkipSpace(psz))
  610. {
  611. switch(*psz++)
  612. {
  613. case TEXT('r'):
  614. case TEXT('R'):
  615. _fReadOnly = TRUE;
  616. break;
  617. case TEXT('x'):
  618. case TEXT('X'):
  619. _fCloseImmediately = TRUE;
  620. break;
  621. }
  622. }
  623. return psz;
  624. }
  625. HRESULT CShClientSite::GetFileName(LPTSTR szFile, UINT cchMax)
  626. {
  627. return StringCchCopy(szFile, cchMax, _wszFileName);
  628. }
  629. const WCHAR c_wszContents[] = WSTR_SCRAPITEM;
  630. //
  631. // Returns:
  632. // S_OK, succeeded. Start the message loop.
  633. // S_FALSE, succeeded. Release the object.
  634. // Others, failed.
  635. //
  636. HRESULT CShClientSite::Load()
  637. {
  638. HRESULT hres;
  639. DWORD wStgm;
  640. // Must be called only once.
  641. if (_pstgDoc) {
  642. return ResultFromScode(E_UNEXPECTED);
  643. }
  644. wStgm = _fReadOnly ?
  645. (STGM_READ | STGM_SHARE_DENY_WRITE) :
  646. (STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE);
  647. hres = StgIsStorageFile(_wszFileName);
  648. if (hres != S_OK)
  649. {
  650. if (hres==S_FALSE) {
  651. hres = IDS_HRES_INVALID_SCRAPFILE;
  652. }
  653. return hres;
  654. }
  655. hres = StgOpenStorage(_wszFileName, NULL, wStgm, NULL, 0, &_pstgDoc);
  656. #ifndef CLONE_IT_IF_READONLY
  657. //
  658. // If we are opening without read-only flag and StgOpenStorage failed
  659. // with STG_E_ACCESSDENIED, retry it with read-only mode.
  660. //
  661. if ((hres==STG_E_ACCESSDENIED) && !_fReadOnly)
  662. {
  663. DebugMsg(DM_TRACE, TEXT("so TR - CSCS::DoVerb first StgOpenStorage failed, retrying it in read-only mode"));
  664. _fReadOnly = TRUE;
  665. wStgm = (STGM_READ | STGM_SHARE_DENY_WRITE);
  666. hres = StgOpenStorage(_wszFileName, NULL, wStgm, NULL, 0, &_pstgDoc);
  667. }
  668. #else // CLONE_IT_IF_READONLY
  669. //
  670. // If we are opening without read-only flag and StgOpenStorage failed
  671. // with STG_E_ACCESSDENIED, retry it with read-only mode.
  672. //
  673. if ((hres==STG_E_ACCESSDENIED) && !_fReadOnly)
  674. {
  675. LPSTORAGE pstgRead;
  676. DebugMsg(DM_TRACE, TEXT("so TR - CSCS::DoVerb first StgOpenStorage failed, retrying it in read-only mode"));
  677. hres = StgOpenStorage(_wszFileName, NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &pstgRead);
  678. if (SUCCEEDED(hres))
  679. {
  680. TCHAR szDesktop[MAX_PATH];
  681. TCHAR szTempFile[MAX_PATH];
  682. SHGetSpecialFolderPath(_hwndOwner, szDesktop, CSIDL_DESKTOP, FALSE);
  683. GetTempFileName(szDesktop, TEXT("Sh"), 0, szTempFile);
  684. hres = StringCchCopy(_wszFileName, ARRAYSIZE(_wszFileName), szTempFile);
  685. if (SUCCEEDED(hres))
  686. {
  687. hres = StgCreateDocfile(_wszFileName,
  688. STGM_DIRECT | STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
  689. 0, &_pstgDoc);
  690. if (SUCCEEDED(hres))
  691. {
  692. hres = pstgRead->CopyTo(0, NULL, NULL, _pstgDoc);
  693. _pstgDoc->Release();
  694. _pstgDoc = NULL;
  695. if (SUCCEEDED(hres))
  696. {
  697. hres = StgOpenStorage(_wszFileName, NULL, wStgm, NULL, 0, &_pstgDoc);
  698. if (SUCCEEDED(hres))
  699. {
  700. _fCloned = TRUE;
  701. }
  702. }
  703. else
  704. {
  705. DeleteFile(szTempFile);
  706. }
  707. }
  708. }
  709. pstgRead->Release();
  710. }
  711. }
  712. #endif // CLONE_IT_IF_READONLY
  713. if (SUCCEEDED(hres))
  714. {
  715. if (_fReadOnly) {
  716. wStgm = STGM_READ|STGM_SHARE_EXCLUSIVE;
  717. }
  718. hres = _pstgDoc->OpenStorage(c_wszContents, NULL, wStgm, NULL, 0, &_pstg);
  719. if (SUCCEEDED(hres))
  720. {
  721. hres = OleLoad(_pstg, IID_IPersistStorage, this, (LPVOID *)&_ppstg);
  722. }
  723. else
  724. {
  725. DebugMsg(DM_TRACE, TEXT("so ER - CSCS::DoVerb _pstgDoc->OpenStorage failed %x"), hres);
  726. //
  727. // Notes: If we just return this hres as is, the user will see
  728. // "Can't open file, FOO.SHS", which is bogus. We need to
  729. // translate it into a much informative message.
  730. //
  731. hres = IDS_HRES_INVALID_SCRAPFILE;
  732. }
  733. }
  734. else
  735. {
  736. DebugMsg(DM_TRACE, TEXT("so ER - CSCS::DoVerb StgOpenStg failed %x"), hres);
  737. }
  738. return hres;
  739. }
  740. HRESULT CShClientSite::DoVerb(LONG iVerb)
  741. {
  742. HRESULT hres;
  743. hres = _ppstg->QueryInterface(IID_IOleObject, (LPVOID *)&_pole);
  744. if (SUCCEEDED(hres))
  745. {
  746. hres = _pole->Advise(this, &_dwConnection);
  747. DebugMsg(DM_TRACE, TEXT("so TR - CSCS::DoVerb IOleObject::Advise returned %x"), hres);
  748. if (SUCCEEDED(hres))
  749. {
  750. TCHAR szTitle[MAX_PATH];
  751. WCHAR wszTitle[MAX_PATH];
  752. LoadString(g_hinst, IDS_TITLE, szTitle, ARRAYSIZE(szTitle));
  753. hres = StringCchCopy(wszTitle, ARRAYSIZE(wszTitle), szTitle);
  754. if (SUCCEEDED(hres))
  755. {
  756. hres = GetFileName(szTitle, ARRAYSIZE(szTitle));
  757. if (SUCCEEDED(hres))
  758. {
  759. LPCWSTR pwszDisplayName = _wszFileName;
  760. SHFILEINFO info;
  761. DWORD_PTR result = SHGetFileInfo(szTitle, 0, &info, SIZEOF(info), SHGFI_DISPLAYNAME);
  762. if(result && *info.szDisplayName)
  763. {
  764. pwszDisplayName = info.szDisplayName;
  765. }
  766. _pole->SetHostNames(wszTitle, pwszDisplayName);
  767. //
  768. // OLEBUG? Unless _hwndOwner has the input focus, 16-bit
  769. // server won't get the input focus.
  770. //
  771. SetFocus(_hwndOwner);
  772. hres = _pole->DoVerb(iVerb, NULL, this, 0, _hwndOwner, NULL);
  773. DebugMsg(DM_TRACE, TEXT("so TR - CSCS::DoVerb IOleObject::DoVerb returned %x"), hres);
  774. if (SUCCEEDED(hres) && _fCloseImmediately)
  775. {
  776. hres = S_FALSE;
  777. }
  778. }
  779. }
  780. }
  781. }
  782. else
  783. {
  784. DebugMsg(DM_TRACE, TEXT("so ER - CSCS::DoVerb IPSTG::QI failed %x"), hres);
  785. }
  786. return hres;
  787. }
  788. STDMETHODIMP_(void) CShClientSite::OnDataChange(FORMATETC *pFormatetc, STGMEDIUM *pStgmed)
  789. {
  790. DebugMsg(DM_TRACE, TEXT("so TR - CSCS::OnDataChange called"));
  791. _fDirty = TRUE;
  792. }
  793. STDMETHODIMP_(void) CShClientSite::OnViewChange(DWORD dwAspect, LONG lindex)
  794. {
  795. DebugMsg(DM_TRACE, TEXT("so TR - CSCS::OnViewChange called"));
  796. _fDirty = TRUE;
  797. }
  798. STDMETHODIMP_(void) CShClientSite::OnRename(IMoniker *pmk)
  799. {
  800. DebugMsg(DM_TRACE, TEXT("so TR - CSCS::OnRename called"));
  801. _fDirty = TRUE;
  802. }
  803. STDMETHODIMP_(void) CShClientSite::OnSave(void)
  804. {
  805. DebugMsg(DM_TRACE, TEXT("so TR - CSCS::OnSave called"));
  806. _fNeedToSave = TRUE;
  807. }
  808. STDMETHODIMP_(void) CShClientSite::OnClose(void)
  809. {
  810. DebugMsg(DM_TRACE, TEXT("so TR - CSCS::OnClose called"));
  811. if (_fNeedToSave /* && _fDirty */)
  812. {
  813. HRESULT hres;
  814. hres=OleSave(_ppstg, _pstg, TRUE); // fSameStorage=TRUE
  815. DebugMsg(DM_TRACE, TEXT("so TR - CSCS:OnClose OleSave returned (%x)"), hres);
  816. hres=_ppstg->HandsOffStorage();
  817. DebugMsg(DM_TRACE, TEXT("so TR - CSCS:OnClose IPS:HandsOffStorage returned (%x)"), hres);
  818. if (SUCCEEDED(hres))
  819. {
  820. hres = _pstg->Commit(STGC_OVERWRITE);
  821. DebugMsg(DM_TRACE, TEXT("so TR - CSCS:OnClose _psg->Commit returned (%x)"), hres);
  822. hres = _pstgDoc->Commit(STGC_OVERWRITE);
  823. DebugMsg(DM_TRACE, TEXT("so TR - CSCS:OnClose _psgDoc->Commit returned (%x)"), hres);
  824. }
  825. }
  826. //
  827. // WARNING:
  828. //
  829. // OLE1 server pukes if we release object here. However, we need to
  830. // call IOleObject::UnAdvice and IOleObject::SetClientSite(NULL) here
  831. // to avoid memory leak (RPC keeps 3 reference counts to IOleClientSite
  832. // if we delay it as well).
  833. //
  834. // ReleaseOleObject();
  835. //
  836. if (_dwConnection) {
  837. _pole->Unadvise(_dwConnection);
  838. _dwConnection = 0;
  839. }
  840. _pole->SetClientSite(NULL);
  841. PostMessage(_hwndOwner, WM_USER, 0, 0);
  842. }
  843. STDMETHODIMP_(void) CShClientSite::OnLinkSrcChange
  844. (
  845. IMoniker *pmk
  846. )
  847. {
  848. DebugMsg(DM_TRACE, TEXT("so TR - CSCS::OnLinkSrcChange called"));
  849. _fDirty = TRUE;
  850. }
  851. LRESULT CALLBACK ShWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  852. {
  853. PAINTSTRUCT ps;
  854. HDC hdc;
  855. LPSHCLIENTSITE pscs = (LPSHCLIENTSITE)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  856. switch(uMsg)
  857. {
  858. case WM_PAINT:
  859. hdc = BeginPaint(hwnd, &ps);
  860. if (pscs && IsWindowVisible(hwnd))
  861. {
  862. pscs->Draw(hwnd, hdc);
  863. }
  864. EndPaint(hwnd, &ps);
  865. break;
  866. case WM_CLOSE:
  867. if (pscs)
  868. {
  869. pscs->CloseOleObject();
  870. DestroyWindow(hwnd);
  871. }
  872. break;
  873. case WM_USER:
  874. if (pscs)
  875. {
  876. pscs->ReleaseOleObject();
  877. PostMessage(hwnd, WM_CLOSE, 0, 0);
  878. }
  879. break;
  880. case WM_DESTROY:
  881. DebugMsg(DM_WARNING, TEXT("so WA - ShWndProc processing WM_DESTROY"));
  882. if (pscs)
  883. {
  884. pscs->Quit();
  885. pscs->Release();
  886. SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
  887. }
  888. else
  889. {
  890. DebugMsg(DM_WARNING, TEXT("so WA - ShWndProc pscs==NULL on WM_DESTROY"));
  891. }
  892. #if 0
  893. //
  894. // Process all the pending messages, before we post WM_QUIT message.
  895. //
  896. MSG msg;
  897. while (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
  898. {
  899. TranslateMessage(&msg);
  900. DispatchMessage(&msg);
  901. }
  902. #endif
  903. break;
  904. default:
  905. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  906. }
  907. return 0;
  908. }
  909. //===========================================================================
  910. // Global functions
  911. //===========================================================================
  912. void CShClientSite_RegisterClass()
  913. {
  914. WNDCLASS wc;
  915. // wc.cbSize = SIZEOF(WNDCLASSEX);
  916. wc.style = CS_DBLCLKS|CS_VREDRAW|CS_HREDRAW ;
  917. wc.lpfnWndProc = ShWndProc ;
  918. wc.cbClsExtra = 0;
  919. wc.cbWndExtra = SIZEOF(LPSHCLIENTSITE) + SIZEOF(LPVOID);
  920. wc.hInstance = g_hinst ;
  921. wc.hIcon = NULL ;
  922. wc.hCursor = LoadCursor(NULL, IDC_ARROW) ;
  923. wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH) ;
  924. wc.lpszMenuName = NULL ;
  925. wc.lpszClassName = c_szAppName ;
  926. // wc.hIconSm = NULL;
  927. RegisterClass(&wc);
  928. }
  929. IOleClientSite* CShClientSite_Create(HWND hwndOwner, LPCTSTR pszFileName)
  930. {
  931. DebugMsg(DM_TRACE, TEXT("sc TR:CShClientSite_Create called with %s"), pszFileName);
  932. CShClientSite* that = new CShClientSite(hwndOwner, pszFileName);
  933. if (that)
  934. {
  935. HRESULT hres = that->Load();
  936. DebugMsg(DM_TRACE, TEXT("sc TRACE: CShClientSite::Load returned %x"), hres);
  937. }
  938. return that;
  939. }
  940. void CShClientSite_Release(IOleClientSite* pcli)
  941. {
  942. CShClientSite* pscs;
  943. if (SUCCEEDED(pcli->QueryInterface(CLSID_CShClientSite, (void**)&pscs)))
  944. {
  945. pscs->ReleaseOleObject();
  946. pscs->ReleaseStorage();
  947. pscs->MaySaveAs();
  948. pscs->Release();
  949. }
  950. UINT cRef = pcli->Release();
  951. Assert(cRef==0);
  952. }