shole.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 34k
Category:

Windows Kernel

Development Platform:

Visual C++

  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('');
  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('');
  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('');
  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('');
  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('');
  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.     HRESULT hres = that->Load();
  983.     DebugMsg(DM_TRACE, TEXT("sc TRACE: CShClientSite::Load returned %x"), hres);
  984.     return that;
  985. }
  986. void CShClientSite_Release(IOleClientSite* pcli)
  987. {
  988.     CShClientSite* pscs;
  989.     if (SUCCEEDED(pcli->QueryInterface(CLSID_CShClientSite, (void**)&pscs)))
  990.     {
  991. pscs->ReleaseOleObject();
  992. pscs->ReleaseStorage();
  993. pscs->MaySaveAs();
  994. pscs->Release();
  995.     }
  996.     UINT cRef = pcli->Release();
  997.     Assert(cRef==0);
  998. }