1082 lines
32 KiB
C
1082 lines
32 KiB
C
#include "shole.h"
|
|
#include "ids.h"
|
|
|
|
#define CLONE_IT_IF_READONLY
|
|
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
|
|
|
|
class CShClientSite : public IOleClientSite, public IAdviseSink2
|
|
{
|
|
public:
|
|
CShClientSite(HWND hwndOwner, LPCTSTR pszCmdLine);
|
|
LPCTSTR ParseCmdLine(LPCTSTR pszCmdLine);
|
|
HRESULT DoVerb(LONG iVerb);
|
|
void CloseOleObject();
|
|
void ReleaseOleObject();
|
|
void ReleaseStorage(void);
|
|
void MaySaveAs(void);
|
|
void Draw(HWND hwnd, HDC hdc);
|
|
void GetFileName(LPTSTR szFile, UINT cchMax);
|
|
void Quit(void) { _hwndOwner = NULL ; _fQuit = TRUE; }
|
|
BOOL FContinue(void) { return !_fQuit; }
|
|
|
|
// IUnKnown
|
|
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID,void **);
|
|
virtual ULONG STDMETHODCALLTYPE AddRef(void);
|
|
virtual ULONG STDMETHODCALLTYPE Release(void);
|
|
|
|
// IOleClientSite
|
|
virtual HRESULT STDMETHODCALLTYPE SaveObject(void);
|
|
virtual HRESULT STDMETHODCALLTYPE GetMoniker(DWORD, DWORD, IMoniker **);
|
|
virtual HRESULT STDMETHODCALLTYPE GetContainer(IOleContainer **);
|
|
virtual HRESULT STDMETHODCALLTYPE ShowObject(void);
|
|
virtual HRESULT STDMETHODCALLTYPE OnShowWindow(BOOL fShow);
|
|
virtual HRESULT STDMETHODCALLTYPE RequestNewObjectLayout(void);
|
|
|
|
// IAdviseSink2
|
|
virtual void STDMETHODCALLTYPE OnDataChange(FORMATETC *,STGMEDIUM *);
|
|
virtual void STDMETHODCALLTYPE OnViewChange(DWORD dwAspect,LONG lindex);
|
|
virtual void STDMETHODCALLTYPE OnRename(IMoniker *pmk);
|
|
virtual void STDMETHODCALLTYPE OnSave(void);
|
|
virtual void STDMETHODCALLTYPE OnClose(void);
|
|
virtual void STDMETHODCALLTYPE OnLinkSrcChange(IMoniker *pmk);
|
|
|
|
protected:
|
|
~CShClientSite();
|
|
|
|
UINT _cRef;
|
|
HWND _hwndOwner;
|
|
LPSTORAGE _pstgDoc; // document
|
|
LPSTORAGE _pstg; // the embedding (only one)
|
|
LPPERSISTSTORAGE _ppstg;
|
|
LPOLEOBJECT _pole;
|
|
BOOL _fDirty:1;
|
|
BOOL _fNeedToSave:1;
|
|
BOOL _fReadOnly:1;
|
|
BOOL _fCloned:1;
|
|
BOOL _fQuit:1;
|
|
BOOL _fCloseImmediately:1;
|
|
DWORD _dwConnection; // non-zero, if valid
|
|
WCHAR _wszFileName[MAX_PATH];
|
|
};
|
|
typedef CShClientSite * LPSHCLIENTSITE;
|
|
|
|
const TCHAR c_szAppName[] = TEXT("ShellOleViewer");
|
|
LRESULT CALLBACK ShWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
|
|
void DisplayError(HWND hwndOwner, HRESULT hres, UINT idsMsg, LPCTSTR szFileName);
|
|
|
|
HINSTANCE g_hinst = NULL;
|
|
|
|
extern "C"
|
|
BOOL APIENTRY LibMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
|
|
{
|
|
switch(dwReason) {
|
|
case DLL_PROCESS_ATTACH:
|
|
g_hinst = (HINSTANCE)hDll;
|
|
DisableThreadLibraryCalls(g_hinst);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
extern "C" void WINAPI
|
|
OpenScrap_RunDLL_Common(HWND hwndStub, HINSTANCE hInstApp, LPTSTR pszCmdLine, int nCmdShow)
|
|
{
|
|
WNDCLASS wc;
|
|
|
|
// wc.cbSize = sizeof(WNDCLASSEX);
|
|
wc.style = CS_DBLCLKS|CS_VREDRAW|CS_HREDRAW ;
|
|
wc.lpfnWndProc = ShWndProc ;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = sizeof(LPSHCLIENTSITE) ;
|
|
wc.hInstance = g_hinst ;
|
|
wc.hIcon = NULL ;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW) ;
|
|
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH) ;
|
|
wc.lpszMenuName = NULL ;
|
|
wc.lpszClassName = c_szAppName ;
|
|
// wc.hIconSm = NULL;
|
|
|
|
RegisterClass(&wc);
|
|
|
|
HWND hwndClientSite = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_OVERLAPPEDWINDOW,
|
|
c_szAppName,
|
|
#ifdef DEBUG
|
|
TEXT("(Debug only) SHOLE.EXE"),
|
|
WS_VISIBLE | WS_OVERLAPPEDWINDOW,
|
|
#else
|
|
TEXT(""),
|
|
WS_OVERLAPPEDWINDOW,
|
|
#endif
|
|
CW_USEDEFAULT, CW_USEDEFAULT,
|
|
128, 128, NULL, NULL, g_hinst, NULL);
|
|
if (hwndClientSite)
|
|
{
|
|
HRESULT hres;
|
|
|
|
hres = OleInitialize(NULL);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
DWORD dwTick;
|
|
LPSHCLIENTSITE pscs= new CShClientSite(hwndClientSite, pszCmdLine);
|
|
|
|
if (pscs)
|
|
{
|
|
UINT cRef;
|
|
|
|
hres = pscs->DoVerb(OLEIVERB_OPEN);
|
|
|
|
if (hres == S_OK)
|
|
{
|
|
MSG msg;
|
|
while (pscs->FContinue() && GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// DoVerb failed.
|
|
|
|
if (FAILED(hres) || (hres>=IDS_HRES_MIN && hres<IDS_HRES_MAX))
|
|
{
|
|
TCHAR szFile[MAX_PATH];
|
|
pscs->GetFileName(szFile, ARRAYSIZE(szFile));
|
|
DisplayError(hwndClientSite, hres, IDS_ERR_DOVERB, szFile);
|
|
}
|
|
DestroyWindow(hwndClientSite);
|
|
}
|
|
|
|
|
|
// We call them just in case, the following Release
|
|
// does not release the object.
|
|
|
|
pscs->ReleaseOleObject();
|
|
pscs->ReleaseStorage();
|
|
pscs->MaySaveAs();
|
|
|
|
cRef = pscs->Release();
|
|
ASSERT(cRef==0);
|
|
}
|
|
|
|
DebugMsg(DM_TRACE, TEXT("so TR - WinMain About to call OleUninitialize"));
|
|
dwTick = GetCurrentTime();
|
|
OleUninitialize();
|
|
DebugMsg(DM_TRACE, TEXT("so TR - WinMain OleUninitialize took %d ticks"), GetCurrentTime()-dwTick);
|
|
}
|
|
|
|
if (IsWindow(hwndClientSite)) {
|
|
DebugMsg(DM_WARNING, TEXT("so WA - WinMain IsWindow(hwndClientSite) is still TRUE"));
|
|
DestroyWindow(hwndClientSite);
|
|
}
|
|
}
|
|
}
|
|
|
|
extern "C" void WINAPI
|
|
OpenScrap_RunDLL(HWND hwndStub, HINSTANCE hAppInstance, LPSTR lpszCmdLine, int nCmdShow)
|
|
{
|
|
#ifdef UNICODE
|
|
UINT iLen = lstrlenA(lpszCmdLine)+1;
|
|
LPWSTR lpwszCmdLine;
|
|
|
|
lpwszCmdLine = (LPWSTR)LocalAlloc(LPTR,iLen*sizeof(WCHAR));
|
|
if (lpwszCmdLine)
|
|
{
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
lpszCmdLine, -1,
|
|
lpwszCmdLine, iLen);
|
|
OpenScrap_RunDLL_Common( hwndStub,
|
|
hAppInstance,
|
|
lpwszCmdLine,
|
|
nCmdShow );
|
|
LocalFree(lpwszCmdLine);
|
|
}
|
|
#else
|
|
OpenScrap_RunDLL_Common( hwndStub,
|
|
hAppInstance,
|
|
lpszCmdLine,
|
|
nCmdShow );
|
|
#endif
|
|
}
|
|
|
|
extern "C" void WINAPI
|
|
OpenScrap_RunDLLW(HWND hwndStub, HINSTANCE hAppInstance, LPWSTR lpwszCmdLine, int nCmdShow)
|
|
{
|
|
#ifdef UNICODE
|
|
OpenScrap_RunDLL_Common( hwndStub,
|
|
hAppInstance,
|
|
lpwszCmdLine,
|
|
nCmdShow );
|
|
#else
|
|
UINT iLen = WideCharToMultiByte(CP_ACP, 0,
|
|
lpwszCmdLine, -1,
|
|
NULL, 0, NULL, NULL)+1;
|
|
LPSTR lpszCmdLine;
|
|
|
|
lpszCmdLine = (LPSTR)LocalAlloc(LPTR,iLen);
|
|
if (lpszCmdLine)
|
|
{
|
|
WideCharToMultiByte(CP_ACP, 0,
|
|
lpwszCmdLine, -1,
|
|
lpszCmdLine, iLen,
|
|
NULL, NULL);
|
|
OpenScrap_RunDLL_Common( hwndStub,
|
|
hAppInstance,
|
|
lpszCmdLine,
|
|
nCmdShow );
|
|
LocalFree(lpszCmdLine);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
// Type checking
|
|
|
|
static RUNDLLPROC lpfnRunDLL=OpenScrap_RunDLL;
|
|
#endif
|
|
|
|
void DisplayError(HWND hwndOwner, HRESULT hres, UINT idsMsg, LPCTSTR pszFileName)
|
|
{
|
|
TCHAR szErrMsg[MAX_PATH*2];
|
|
TCHAR szFancyErr[MAX_PATH*2];
|
|
HRSRC hrsrc;
|
|
|
|
if (HIWORD(hres))
|
|
{
|
|
BOOL fSuccess = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
NULL,
|
|
hres,
|
|
0,
|
|
szErrMsg,
|
|
ARRAYSIZE(szErrMsg),
|
|
(va_list *)&pszFileName);
|
|
if (!fSuccess) {
|
|
idsMsg++; // map IDS_ERR_DOVERB to IDS_ERR_DOVERB_F
|
|
}
|
|
} else {
|
|
LoadString(g_hinst, LOWORD(hres), szErrMsg, ARRAYSIZE(szErrMsg));
|
|
}
|
|
|
|
szFancyErr[0] = TEXT('\0');
|
|
hrsrc = FindResource(g_hinst, MAKEINTRESOURCE(IDR_FANCYERR), RT_RCDATA);
|
|
if (hrsrc)
|
|
{
|
|
HGLOBAL hmem = LoadResource(g_hinst, hrsrc);
|
|
if (hmem)
|
|
{
|
|
HRESULT* phres = (HRESULT*)LockResource(hmem);
|
|
if (phres)
|
|
{
|
|
UINT i;
|
|
LPTSTR pszLoad = szFancyErr;
|
|
int cchLeft = ARRAYSIZE(szFancyErr);
|
|
for (i=0; phres[i] && cchLeft>0; i++) {
|
|
if (phres[i] == hres)
|
|
{
|
|
int cchRead;
|
|
cchRead = LoadString(g_hinst, IDS_FANCYERR+i, pszLoad, cchLeft);
|
|
pszLoad += cchRead;
|
|
cchLeft -= cchRead;
|
|
}
|
|
}
|
|
|
|
|
|
// If we have a fancy error message, hide ugly message
|
|
// from FormatMessage.
|
|
|
|
if (szFancyErr[0]) {
|
|
szErrMsg[0] = TEXT('\0');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ShellMessageBox(g_hinst,
|
|
hwndOwner,
|
|
MAKEINTRESOURCE(idsMsg),
|
|
MAKEINTRESOURCE(IDS_TITLE_ERR),
|
|
MB_OK | MB_ICONWARNING | MB_SETFOREGROUND,
|
|
pszFileName,
|
|
szErrMsg,
|
|
szFancyErr,
|
|
hres);
|
|
}
|
|
|
|
|
|
void CShClientSite::CloseOleObject()
|
|
{
|
|
if (_pole)
|
|
_pole->Close(OLECLOSE_NOSAVE);
|
|
}
|
|
|
|
void CShClientSite::ReleaseOleObject()
|
|
{
|
|
UINT cRef;
|
|
if (_pole)
|
|
{
|
|
if (_dwConnection) {
|
|
_pole->Unadvise(_dwConnection);
|
|
_dwConnection = 0;
|
|
}
|
|
_pole->SetClientSite(NULL);
|
|
cRef = _pole->Release();
|
|
DebugMsg(DM_TRACE, TEXT("so - TR SCS::ReleaseOleObject IOleObj::Rel returned (%d)"), cRef);
|
|
_pole=NULL;
|
|
}
|
|
|
|
if (_ppstg)
|
|
{
|
|
cRef=_ppstg->Release();
|
|
_ppstg=NULL;
|
|
DebugMsg(DM_TRACE, TEXT("so TR - SCS::ReleaseOleObject IPSTG::Release returned (%x)"), cRef);
|
|
}
|
|
}
|
|
|
|
void CShClientSite::ReleaseStorage(void)
|
|
{
|
|
UINT cRef;
|
|
|
|
if (_pstg)
|
|
{
|
|
cRef=_pstg->Release();
|
|
_pstg=NULL;
|
|
DebugMsg(DM_TRACE, TEXT("so TR - SCS::ReleaseStorage _pstg->Release returned (%x)"), cRef);
|
|
}
|
|
|
|
if (_pstgDoc)
|
|
{
|
|
cRef=_pstgDoc->Release();
|
|
_pstgDoc=NULL;
|
|
DebugMsg(DM_TRACE, TEXT("so TR - SCS::ReleaseStorage _pstgDoc->Release returned (%x)"), cRef);
|
|
}
|
|
}
|
|
|
|
void CShClientSite::MaySaveAs()
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("so TR - SCS::MaySaveAs called (%d,%d)"), _fCloned, _fNeedToSave);
|
|
if (_fCloned)
|
|
{
|
|
TCHAR szTempFile[MAX_PATH];
|
|
#ifdef UNICODE
|
|
lstrcpyn(szTempFile,_wszFileName,ARRAYSIZE(szTempFile));
|
|
#else
|
|
WideCharToMultiByte(CP_ACP, 0, _wszFileName, -1, szTempFile, ARRAYSIZE(szTempFile), NULL, NULL);
|
|
#endif
|
|
|
|
UINT id = IDNO;
|
|
if (_fNeedToSave)
|
|
{
|
|
id= ShellMessageBox(g_hinst,
|
|
_hwndOwner,
|
|
MAKEINTRESOURCE(IDS_WOULDYOUSAVEAS),
|
|
MAKEINTRESOURCE(IDS_TITLE),
|
|
MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND,
|
|
NULL);
|
|
}
|
|
|
|
DebugMsg(DM_TRACE, TEXT("so TR - SCS::MaySaveAs id==%d"), id);
|
|
|
|
if (id==IDYES)
|
|
{
|
|
TCHAR szDesktop[MAX_PATH];
|
|
SHGetSpecialFolderPath(NULL, szDesktop, CSIDL_DESKTOP, FALSE);
|
|
|
|
BOOL fContinue;
|
|
do
|
|
{
|
|
fContinue = FALSE;
|
|
|
|
TCHAR szFile[MAX_PATH];
|
|
TCHAR szFilter[64];
|
|
szFile[0] = TEXT('\0');
|
|
LoadString(g_hinst, IDS_SCRAPFILTER, szFilter, ARRAYSIZE(szFilter));
|
|
|
|
OPENFILENAME of = {
|
|
sizeof(OPENFILENAME), // DWORD lStructSize;
|
|
_hwndOwner, // HWND hwndOwner;
|
|
NULL, // HINSTANCE hInstance;
|
|
szFilter, // LPCSTR lpstrFilter;
|
|
NULL, // LPSTR lpstrCustomFilter;
|
|
0, // DWORD nMaxCustFilter;
|
|
1, // DWORD nFilterIndex;
|
|
szFile, // LPSTR lpstrFile;
|
|
ARRAYSIZE(szFile), // DWORD nMaxFile;
|
|
NULL, // LPSTR lpstrFileTitle;
|
|
0, // DWORD nMaxFileTitle;
|
|
szDesktop, // LPCSTR lpstrInitialDir;
|
|
NULL, // LPCSTR lpstrTitle;
|
|
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT
|
|
| OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST,
|
|
// DWORD Flags;
|
|
0, // WORD nFileOffset;
|
|
0, // WORD nFileExtension;
|
|
TEXT("shs"), // LPCSTR lpstrDefExt;
|
|
NULL, // LPARAM lCustData;
|
|
NULL, // LPOFNHOOKPROC lpfnHook;
|
|
NULL, // LPCSTR lpTemplateName;
|
|
};
|
|
|
|
if (GetSaveFileName(&of))
|
|
{
|
|
DeleteFile(szFile);
|
|
BOOL fRet = MoveFile(szTempFile, szFile);
|
|
if (fRet)
|
|
{
|
|
// Indicated that the temp file is moved
|
|
szTempFile[0] = TEXT('\0');
|
|
}
|
|
else
|
|
{
|
|
id = ShellMessageBox(g_hinst,
|
|
_hwndOwner,
|
|
MAKEINTRESOURCE(IDS_MOVEFAILED),
|
|
MAKEINTRESOURCE(IDS_TITLE),
|
|
MB_YESNO | MB_ICONWARNING | MB_SETFOREGROUND);
|
|
if (id==IDYES)
|
|
{
|
|
fContinue = TRUE;
|
|
}
|
|
}
|
|
}
|
|
} while (fContinue);
|
|
}
|
|
|
|
// If the temp file is not moved, delete it.
|
|
if (szTempFile[0])
|
|
{
|
|
DeleteFile(szTempFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CShClientSite::Draw(HWND hwnd, HDC hdc)
|
|
{
|
|
#ifdef DEBUG
|
|
if (_ppstg)
|
|
{
|
|
HRESULT hres;
|
|
RECT rc;
|
|
|
|
GetClientRect(hwnd, &rc);
|
|
|
|
hres = OleDraw(_ppstg, DVASPECT_ICON, hdc, &rc);
|
|
DebugMsg(DM_TRACE, TEXT("so TR - SCS::Draw OleDraw(DVASPECT_ICON) returned %x"), hres);
|
|
|
|
if (FAILED(hres))
|
|
{
|
|
LPVIEWOBJECT2 pview;
|
|
hres = _ppstg->QueryInterface(IID_IViewObject2, (LPVOID*)&pview);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
SIZE size;
|
|
hres = pview->GetExtent(DVASPECT_CONTENT, (DWORD)-1,
|
|
(DVTARGETDEVICE*)NULL, &size);
|
|
DebugMsg(DM_TRACE, TEXT("so TR - SCS::Draw IVO2::GetExtent returned %x"), hres);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
int mmOld = SetMapMode(hdc, MM_HIMETRIC);
|
|
LPtoDP(hdc, (LPPOINT)&size, 1);
|
|
rc.right = size.cx;
|
|
rc.bottom = -size.cy;
|
|
SetMapMode(hdc, mmOld);
|
|
}
|
|
pview->Release();
|
|
}
|
|
hres = OleDraw(_ppstg, DVASPECT_CONTENT, hdc, &rc);
|
|
DebugMsg(DM_TRACE, TEXT("so TR - SCS::Draw OleDraw(DVASPECT_CONTENT,%d,%d) returned %x"),
|
|
hres, rc.right, rc.bottom);
|
|
}
|
|
|
|
LPOLELINK plink;
|
|
if (SUCCEEDED(hres = _ppstg->QueryInterface(IID_IOleLink, (LPVOID *)&plink)))
|
|
{
|
|
LPOLESTR pwsz;
|
|
hres = plink->GetSourceDisplayName(&pwsz);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
#ifdef UNICODE
|
|
TextOut(hdc, 0, 0, pwsz, lstrlen(pwsz));
|
|
#else
|
|
TCHAR szDisplayName[256] = TEXT("##ERROR##");
|
|
WideCharToMultiByte(CP_ACP, 0, pwsz, -1, szDisplayName, ARRAYSIZE(szDisplayName), NULL, NULL);
|
|
TextOut(hdc, 0, 0, szDisplayName, lstrlen(szDisplayName));
|
|
#endif
|
|
CoTaskMemFree(pwsz);
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("so TR SCS:Draw IMK:GetSDN failed %x"), hres);
|
|
}
|
|
plink->Release();
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("so TR SCS:Draw IPSTG:QI failed %x"), hres);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
STDMETHODIMP CShClientSite::QueryInterface(REFIID riid,
|
|
void **ppvObject)
|
|
{
|
|
HRESULT hres;
|
|
if (IsEqualGUID(riid, IID_IOleClientSite) || IsEqualGUID(riid, IID_IUnknown)) {
|
|
_cRef++;
|
|
*ppvObject = (LPOLECLIENTSITE)this;
|
|
hres = NOERROR;
|
|
}
|
|
else if (IsEqualGUID(riid, IID_IAdviseSink) || IsEqualGUID(riid, IID_IAdviseSink2)) {
|
|
_cRef++;
|
|
*ppvObject = (LPADVISESINK2)this;
|
|
hres = NOERROR;
|
|
}
|
|
else
|
|
{
|
|
*ppvObject = NULL;
|
|
hres = ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CShClientSite::AddRef(void)
|
|
{
|
|
return ++_cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CShClientSite::Release(void)
|
|
{
|
|
if (--_cRef>0) {
|
|
return _cRef;
|
|
}
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
|
|
void Scrap_UpdateCachedData(LPSTORAGE pstgDoc, LPOLEOBJECT pole, LPPERSIST pps)
|
|
{
|
|
extern void Scrap_CacheClipboardData(LPSTORAGE pstgDoc, LPDATAOBJECT pdtobj, LPPERSIST pps);
|
|
DebugMsg(DM_TRACE, TEXT("so TR - S_UCD called"));
|
|
if (pstgDoc && pole && pps)
|
|
{
|
|
IDataObject *pdtobj = NULL;
|
|
HRESULT hres = pole->QueryInterface(IID_IDataObject, (LPVOID*)&pdtobj);
|
|
if (SUCCEEDED(hres)) {
|
|
DebugMsg(DM_TRACE, TEXT("so TR - S_UCD QI succeeded"));
|
|
Scrap_CacheClipboardData(pstgDoc, pdtobj, pps);
|
|
pdtobj->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP CShClientSite::SaveObject(void)
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("sc TR - CSCS::SaveObject called"));
|
|
|
|
// NOTES: We need to update the cache here.
|
|
// Doing so on ::OnSave does not work (async)
|
|
// Doing so on ::OnClose is too late.
|
|
|
|
Scrap_UpdateCachedData(_pstgDoc, _pole, _ppstg);
|
|
|
|
HRESULT hres;
|
|
if (_pstg && _ppstg)
|
|
{
|
|
hres = OleSave(_ppstg, _pstg, TRUE);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = _ppstg->SaveCompleted(NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hres = ResultFromScode(E_FAIL);
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
STDMETHODIMP CShClientSite::GetMoniker(DWORD dwAssign,
|
|
DWORD dwWhichMoniker,
|
|
IMoniker **ppmk)
|
|
{
|
|
HRESULT hres;
|
|
|
|
*ppmk = NULL;
|
|
|
|
switch(dwWhichMoniker)
|
|
{
|
|
case OLEWHICHMK_CONTAINER:
|
|
hres = CreateFileMoniker(_wszFileName, ppmk);
|
|
break;
|
|
|
|
case OLEWHICHMK_OBJREL:
|
|
hres = CreateItemMoniker(L"\\", L"Object", ppmk);
|
|
break;
|
|
|
|
case OLEWHICHMK_OBJFULL:
|
|
{
|
|
LPMONIKER pmkItem;
|
|
hres = CreateItemMoniker(L"\\", L"Object", &pmkItem);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
LPMONIKER pmkDoc;
|
|
hres = CreateFileMoniker(_wszFileName, &pmkDoc);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = CreateGenericComposite(pmkDoc, pmkItem, ppmk);
|
|
pmkDoc->Release();
|
|
}
|
|
pmkItem->Release();
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
hres = ResultFromScode(E_INVALIDARG);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
STDMETHODIMP CShClientSite::GetContainer(
|
|
IOleContainer **ppContainer)
|
|
{
|
|
*ppContainer = NULL;
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
STDMETHODIMP CShClientSite::ShowObject(void)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CShClientSite::OnShowWindow(BOOL fShow)
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("so TR - CSCS::OnShowWindow called with %d"), fShow);
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CShClientSite::RequestNewObjectLayout(void)
|
|
{
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
|
|
// _cRef <- 2 because _hwndOwner has a reference count as well.
|
|
|
|
CShClientSite::CShClientSite(HWND hwndOwner, LPCTSTR pszCmdLine)
|
|
: _cRef(2), _hwndOwner(hwndOwner),
|
|
_pstgDoc(NULL), _pstg(NULL), _ppstg(NULL), _pole(NULL),
|
|
_fDirty(FALSE), _fNeedToSave(FALSE),
|
|
_fReadOnly(FALSE), _fCloned(FALSE), _fCloseImmediately(FALSE),
|
|
_fQuit(FALSE)
|
|
{
|
|
LPCTSTR pszFileName = ParseCmdLine(pszCmdLine);
|
|
|
|
|
|
// We'd better deal with quoted LFN name.
|
|
|
|
#ifdef NASHVILLE
|
|
|
|
// Strip out quotes if exists.
|
|
|
|
TCHAR szT[MAX_PATH];
|
|
if (*pszFileName==TEXT('"'))
|
|
{
|
|
lstrcpy(szT, pszFileName+1);
|
|
LPTSTR pszT = CharPrev(szT, szT+lstrlen(szT));
|
|
if (*pszT==TEXT('"')) {
|
|
*pszT=TEXT('\0');
|
|
}
|
|
pszFileName = szT;
|
|
}
|
|
#endif // NASHVILLE
|
|
|
|
#ifdef UNICODE
|
|
lstrcpyn(_wszFileName, pszFileName, ARRAYSIZE(_wszFileName));
|
|
#else
|
|
MultiByteToWideChar(CP_ACP, 0, pszFileName, lstrlen(pszFileName)+1,
|
|
_wszFileName, ARRAYSIZE(_wszFileName));
|
|
#endif
|
|
|
|
ASSERT(_hwndOwner)
|
|
SetWindowLongPtr(_hwndOwner, GWLP_USERDATA, (LONG_PTR)this);
|
|
}
|
|
|
|
CShClientSite::~CShClientSite()
|
|
{
|
|
ReleaseOleObject();
|
|
ReleaseStorage();
|
|
}
|
|
|
|
LPCTSTR _SkipSpace(LPCTSTR psz)
|
|
{
|
|
while(*psz==TEXT(' '))
|
|
psz++;
|
|
return psz;
|
|
}
|
|
|
|
LPCTSTR CShClientSite::ParseCmdLine(LPCTSTR pszCmdLine)
|
|
{
|
|
for (LPCTSTR psz = _SkipSpace(pszCmdLine);
|
|
(*psz == TEXT('/') || *psz == TEXT('-')) && *++psz;
|
|
psz = _SkipSpace(psz))
|
|
{
|
|
switch(*psz++)
|
|
{
|
|
case TEXT('r'):
|
|
case TEXT('R'):
|
|
_fReadOnly = TRUE;
|
|
break;
|
|
|
|
case TEXT('x'):
|
|
case TEXT('X'):
|
|
_fCloseImmediately = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return psz;
|
|
}
|
|
|
|
void CShClientSite::GetFileName(LPTSTR szFile, UINT cchMax)
|
|
{
|
|
#ifdef UNICODE
|
|
lstrcpyn(szFile, _wszFileName, cchMax);
|
|
#else
|
|
WideCharToMultiByte(CP_ACP, 0, _wszFileName, -1, szFile, cchMax, NULL, NULL);
|
|
#endif
|
|
}
|
|
const WCHAR c_wszContents[] = WSTR_SCRAPITEM;
|
|
|
|
|
|
// Returns:
|
|
// S_OK, succeeded. Start the message loop.
|
|
// S_FALSE, succeeded. Release the object.
|
|
// Others, failed.
|
|
|
|
HRESULT CShClientSite::DoVerb(LONG iVerb)
|
|
{
|
|
HRESULT hres;
|
|
DWORD wStgm;
|
|
|
|
// Must be called only once.
|
|
if (_pstgDoc) {
|
|
return ResultFromScode(E_UNEXPECTED);
|
|
}
|
|
|
|
wStgm = _fReadOnly ?
|
|
(STGM_READ | STGM_SHARE_DENY_WRITE) :
|
|
(STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE);
|
|
hres = StgIsStorageFile(_wszFileName);
|
|
if (hres != S_OK)
|
|
{
|
|
if (hres==S_FALSE) {
|
|
hres = IDS_HRES_INVALID_SCRAPFILE;
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
hres = StgOpenStorage(_wszFileName, NULL, wStgm, NULL, 0, &_pstgDoc);
|
|
|
|
#ifndef CLONE_IT_IF_READONLY
|
|
|
|
// If we are opening without read-only flag and StgOpenStorage failed
|
|
// with STG_E_ACCESSDENIED, retry it with read-only mode.
|
|
|
|
if ((hres==STG_E_ACCESSDENIED) && !_fReadOnly)
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("so TR - CSCS::DoVerb first StgOpenStorage failed, retrying it in read-only mode"));
|
|
_fReadOnly = TRUE;
|
|
wStgm = (STGM_READ | STGM_SHARE_DENY_WRITE);
|
|
hres = StgOpenStorage(_wszFileName, NULL, wStgm, NULL, 0, &_pstgDoc);
|
|
}
|
|
#else // CLONE_IT_IF_READONLY
|
|
|
|
// If we are opening without read-only flag and StgOpenStorage failed
|
|
// with STG_E_ACCESSDENIED, retry it with read-only mode.
|
|
|
|
if ((hres==STG_E_ACCESSDENIED) && !_fReadOnly)
|
|
{
|
|
LPSTORAGE pstgRead;
|
|
DebugMsg(DM_TRACE, TEXT("so TR - CSCS::DoVerb first StgOpenStorage failed, retrying it in read-only mode"));
|
|
hres = StgOpenStorage(_wszFileName, NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &pstgRead);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
TCHAR szDesktop[MAX_PATH];
|
|
TCHAR szTempFile[MAX_PATH];
|
|
SHGetSpecialFolderPath(_hwndOwner, szDesktop, CSIDL_DESKTOP, FALSE);
|
|
GetTempFileName(szDesktop, TEXT("Sh"), 0, szTempFile);
|
|
#ifdef UNICODE
|
|
lstrcpyn(_wszFileName,szTempFile,ARRAYSIZE(szTempFile));
|
|
#else
|
|
MultiByteToWideChar(CP_ACP, 0, szTempFile, -1, _wszFileName, ARRAYSIZE(_wszFileName));
|
|
#endif
|
|
|
|
hres = StgCreateDocfile(_wszFileName,
|
|
STGM_DIRECT | STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
|
|
0, &_pstgDoc);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = pstgRead->CopyTo(0, NULL, NULL, _pstgDoc);
|
|
_pstgDoc->Release();
|
|
_pstgDoc = NULL;
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = StgOpenStorage(_wszFileName, NULL, wStgm, NULL, 0, &_pstgDoc);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
_fCloned = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DeleteFile(szTempFile);
|
|
}
|
|
}
|
|
pstgRead->Release();
|
|
}
|
|
}
|
|
#endif // CLONE_IT_IF_READONLY
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
if (_fReadOnly) {
|
|
wStgm = STGM_READ|STGM_SHARE_EXCLUSIVE;
|
|
}
|
|
hres = _pstgDoc->OpenStorage(c_wszContents, NULL, wStgm, NULL, 0, &_pstg);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = OleLoad(_pstg, IID_IPersistStorage, this, (LPVOID *)&_ppstg);
|
|
|
|
if (SUCCEEDED(hres)) {
|
|
hres = _ppstg->QueryInterface(IID_IOleObject, (LPVOID *)&_pole);
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = _pole->Advise(this, &_dwConnection);
|
|
DebugMsg(DM_TRACE, TEXT("so TR - CSCS::DoVerb IOleObject::Advise returned %x"), hres);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
TCHAR szTitle[MAX_PATH];
|
|
WCHAR wszTitle[MAX_PATH];
|
|
LoadString(g_hinst, IDS_TITLE, szTitle, ARRAYSIZE(szTitle));
|
|
#ifdef UNICODE
|
|
lstrcpyn(wszTitle,szTitle,ARRAYSIZE(wszTitle));
|
|
#else
|
|
MultiByteToWideChar(CP_ACP, 0, szTitle, lstrlen(szTitle)+1,
|
|
wszTitle, ARRAYSIZE(wszTitle));
|
|
#endif
|
|
|
|
GetFileName(szTitle, ARRAYSIZE(szTitle));
|
|
LPCWSTR pwszDisplayName = _wszFileName;
|
|
#ifndef UNICODE
|
|
WCHAR wszDisplayName[MAX_PATH];
|
|
#endif
|
|
SHFILEINFO info;
|
|
DWORD result = (DWORD)SHGetFileInfo(szTitle, 0,
|
|
&info, sizeof(info), SHGFI_DISPLAYNAME);
|
|
|
|
if(result && *info.szDisplayName)
|
|
{
|
|
#ifdef UNICODE
|
|
pwszDisplayName = info.szDisplayName;
|
|
#else
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
info.szDisplayName, -1,
|
|
wszDisplayName, ARRAYSIZE(wszDisplayName));
|
|
pwszDisplayName = wszDisplayName;
|
|
#endif
|
|
}
|
|
|
|
_pole->SetHostNames(wszTitle, pwszDisplayName);
|
|
|
|
|
|
// OLEBUG? Unless _hwndOwner has the input focus, 16-bit
|
|
// server won't get the input focus.
|
|
|
|
SetFocus(_hwndOwner);
|
|
|
|
hres = _pole->DoVerb(iVerb, NULL, this, 0, _hwndOwner, NULL);
|
|
DebugMsg(DM_TRACE, TEXT("so TR - CSCS::DoVerb IOleObject::DoVerb returned %x"), hres);
|
|
if (SUCCEEDED(hres) && _fCloseImmediately) {
|
|
hres = S_FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("so ER - CSCS::DoVerb IPSTG::QI failed %x"), hres);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("so ER - CSCS::DoVerb OleLoad failed %x"), hres);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("so ER - CSCS::DoVerb _pstgDoc->OpenStorage failed %x"), hres);
|
|
|
|
|
|
// Notes: If we just return this hres as is, the user will see
|
|
// "Can't open file, FOO.SHS", which is bogus. We need to
|
|
// translate it into a much informative message.
|
|
|
|
hres = IDS_HRES_INVALID_SCRAPFILE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("so ER - CSCS::DoVerb StgOpenStg failed %x"), hres);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
STDMETHODIMP_(void) CShClientSite::OnDataChange(FORMATETC *pFormatetc, STGMEDIUM *pStgmed)
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("so TR - CSCS::OnDataChange called"));
|
|
_fDirty = TRUE;
|
|
}
|
|
|
|
STDMETHODIMP_(void) CShClientSite::OnViewChange(DWORD dwAspect, LONG lindex)
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("so TR - CSCS::OnViewChange called"));
|
|
_fDirty = TRUE;
|
|
}
|
|
|
|
STDMETHODIMP_(void) CShClientSite::OnRename(IMoniker *pmk)
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("so TR - CSCS::OnRename called"));
|
|
_fDirty = TRUE;
|
|
}
|
|
|
|
STDMETHODIMP_(void) CShClientSite::OnSave(void)
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("so TR - CSCS::OnSave called"));
|
|
_fNeedToSave = TRUE;
|
|
}
|
|
|
|
STDMETHODIMP_(void) CShClientSite::OnClose(void)
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("so TR - CSCS::OnClose called"));
|
|
if (_fNeedToSave /* && _fDirty */)
|
|
{
|
|
HRESULT hres;
|
|
hres=OleSave(_ppstg, _pstg, TRUE); // fSameStorage=TRUE
|
|
DebugMsg(DM_TRACE, TEXT("so TR - CSCS:OnClose OleSave returned (%x)"), hres);
|
|
hres=_ppstg->HandsOffStorage();
|
|
DebugMsg(DM_TRACE, TEXT("so TR - CSCS:OnClose IPS:HandsOffStorage returned (%x)"), hres);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = _pstg->Commit(STGC_OVERWRITE);
|
|
DebugMsg(DM_TRACE, TEXT("so TR - CSCS:OnClose _psg->Commit returned (%x)"), hres);
|
|
hres = _pstgDoc->Commit(STGC_OVERWRITE);
|
|
DebugMsg(DM_TRACE, TEXT("so TR - CSCS:OnClose _psgDoc->Commit returned (%x)"), hres);
|
|
}
|
|
}
|
|
|
|
|
|
// WARNING:
|
|
|
|
// OLE1 server pukes if we release object here. However, we need to
|
|
// call IOleObject::UnAdvice and IOleObject::SetClientSite(NULL) here
|
|
// to avoid memory leak (RPC keeps 3 reference counts to IOleClientSite
|
|
// if we delay it as well).
|
|
|
|
// ReleaseOleObject();
|
|
|
|
if (_dwConnection) {
|
|
_pole->Unadvise(_dwConnection);
|
|
_dwConnection = 0;
|
|
}
|
|
_pole->SetClientSite(NULL);
|
|
|
|
PostMessage(_hwndOwner, WM_USER, 0, 0);
|
|
}
|
|
|
|
STDMETHODIMP_(void) CShClientSite::OnLinkSrcChange
|
|
(
|
|
IMoniker *pmk
|
|
)
|
|
{
|
|
DebugMsg(DM_TRACE, TEXT("so TR - CSCS::OnLinkSrcChange called"));
|
|
_fDirty = TRUE;
|
|
}
|
|
|
|
LRESULT CALLBACK ShWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
HDC hdc;
|
|
LPSHCLIENTSITE pscs = (LPSHCLIENTSITE)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
|
|
switch(uMsg)
|
|
{
|
|
case WM_PAINT:
|
|
hdc = BeginPaint(hwnd, &ps);
|
|
if (pscs)
|
|
{
|
|
pscs->Draw(hwnd, hdc);
|
|
}
|
|
EndPaint(hwnd, &ps);
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
if (pscs)
|
|
{
|
|
pscs->CloseOleObject();
|
|
DestroyWindow(hwnd);
|
|
}
|
|
break;
|
|
|
|
case WM_USER:
|
|
if (pscs)
|
|
{
|
|
pscs->ReleaseOleObject();
|
|
PostMessage(hwnd, WM_CLOSE, 0, 0);
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
DebugMsg(DM_WARNING, TEXT("so WA - ShWndProc processing WM_DESTROY"));
|
|
if (pscs)
|
|
{
|
|
pscs->Quit();
|
|
pscs->Release();
|
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
|
|
}
|
|
else
|
|
{
|
|
DebugMsg(DM_WARNING, TEXT("so WA - ShWndProc pscs==NULL on WM_DESTROY"));
|
|
}
|
|
|
|
#if 0
|
|
|
|
// Process all the pending messages, before we post WM_QUIT message.
|
|
|
|
MSG msg;
|
|
while (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
return 0;
|
|
}
|