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.

1124 lines
33 KiB

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