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.

1081 lines
32 KiB

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