📄 dsofdocobj.cpp
字号:
SAFE_RELEASE_INTERFACE(m_pstgSourceFile);
SAFE_RELEASE_INTERFACE(m_pmkSourceObject);
// Free any temp file we might have...
if ((m_pstmWebResource) && (m_pwszSourceFile))
FPerformShellOp(FO_DELETE, m_pwszSourceFile, NULL);
SAFE_RELEASE_INTERFACE(m_pstmWebResource);
SAFE_FREESTRING(m_pwszWebResource);
SAFE_FREESTRING(m_pwszSourceFile);
m_idxSourceName = 0;
if (m_fDisconnectOnQuit)
{
CoDisconnectObject((IUnknown*)this, 0);
m_fDisconnectOnQuit = FALSE;
}
SAFE_RELEASE_INTERFACE(m_pstmview);
SAFE_RELEASE_INTERFACE(m_pstgfile);
ClearMergedMenu();
m_fInClose = FALSE;
return;
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject Notification Functions - The OCX should call these to
// let the doc site update the object as needed.
//
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::OnNotifySizeChange
//
// Resets the size of the site window and tells UI active object to
// resize as well. If we are UI active, we'll call ResizeBorder to
// re-negotiate toolspace (allow toolbars to shrink and grow), otherwise
// we'll just set the IP active view rect (minus any toolspace, which
// should be none since object is not UI active!).
//
STDMETHODIMP_(void) CDsoDocObject::OnNotifySizeChange(LPRECT prc)
{
RECT rc;
SetRect(&rc, 0, 0, (prc->right - prc->left), (prc->bottom - prc->top));
if (rc.right < 0) rc.right = 0;
if (rc.top < 0) rc.top = 0;
// First, resize our frame site window tot he new size (don't change focus)...
if (m_hwnd)
{
m_rcViewRect = *prc;
SetWindowPos(m_hwnd, NULL, m_rcViewRect.left, m_rcViewRect.top,
rc.right, rc.bottom, SWP_NOACTIVATE | SWP_NOZORDER);
UpdateWindow(m_hwnd);
}
// If we have an active object (i.e., Document is still UI active) we should
// tell it of the resize so it can re-negotiate border space...
if ((m_fObjectUIActive) && (m_pipactive))
{
m_pipactive->ResizeBorder(&rc, (IOleInPlaceUIWindow*)&m_xOleInPlaceFrame, TRUE);
}
else if ((m_fObjectIPActive) && (m_pdocv))
{
rc.left += m_bwToolSpace.left; rc.right -= m_bwToolSpace.right;
rc.top += m_bwToolSpace.top; rc.bottom -= m_bwToolSpace.bottom;
m_pdocv->SetRect(&rc);
}
return;
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::OnNotifyAppActivate
//
// Notify doc object when the top-level frame window goes active and
// deactive so it can handle window focs and paiting correctly. Failure
// to not forward this notification leads to bad behavior.
//
STDMETHODIMP_(void) CDsoDocObject::OnNotifyAppActivate(BOOL fActive, DWORD dwThreadID)
{
// This is critical for DocObject servers, so forward these messages
// when the object is UI active...
if (m_pipactive)
{
// We should always tell obj server when our frame activates, but
// don't tell it to go deactive if the thread gaining focus is
// the server's since our frame may have lost focus because of
// a top-level modeless dialog (ex., the RefEdit dialog of Excel)...
//if ((fActive) || (dwThreadID != m_dwObjectThreadID))
m_pipactive->OnFrameWindowActivate(fActive);
}
m_fAppWindowActive = fActive;
}
STDMETHODIMP_(void) CDsoDocObject::OnNotifyHostSetFocus()
{
HWND hwnd;
if ((m_pipactive) && SUCCEEDED(m_pipactive->GetWindow(&hwnd)))
SetFocus(hwnd);
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::OnNotifyPaletteChanged
//
// Give the object first chance at realizing a palette. Important on
// 256 color machines, but not so critical these days when everyone is
// running full 32-bit True Color graphic cards.
//
STDMETHODIMP_(void) CDsoDocObject::OnNotifyPaletteChanged(HWND hwndPalChg)
{
if ((m_fObjectUIActive) && (m_hwndUIActiveObj))
SendMessage(m_hwndUIActiveObj, WM_PALETTECHANGED, (WPARAM)hwndPalChg, 0L);
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::OnNotifyChangeToolState
//
// This should be called to get object to show/hide toolbars as needed.
//
STDMETHODIMP_(void) CDsoDocObject::OnNotifyChangeToolState(BOOL fShowTools)
{
// Can't change toolbar state in print preview (sorry)...
if (InPrintPreview()) return;
// If we want to show/hide toolbars, we can do the following...
if (fShowTools != (BOOL)m_fDisplayTools)
{
OLECMD cmd;
cmd.cmdID = OLECMDID_HIDETOOLBARS;
m_fDisplayTools = fShowTools;
// Use IOleCommandTarget(OLECMDID_HIDETOOLBARS) to toggle on/off. We have
// to check that server supports it and if its state matches our own so
// when toggle, we do the correct thing by the user...
if ((m_pcmdt) && SUCCEEDED(m_pcmdt->QueryStatus(NULL, 1, &cmd, NULL)) &&
((cmd.cmdf & OLECMDF_SUPPORTED) || (cmd.cmdf & OLECMDF_ENABLED)))
{
if (((fShowTools) && (cmd.cmdf & OLECMDF_LATCHED)) ||
(!(fShowTools) && !(cmd.cmdf & OLECMDF_LATCHED)))
{
m_pcmdt->Exec(NULL, OLECMDID_HIDETOOLBARS, OLECMDEXECOPT_PROMPTUSER, NULL, NULL);
}
// There can be focus issues when turning them off, so make sure
// the object is on top of the z-order...
if ((!m_fDisplayTools) && (m_hwndIPObject))
BringWindowToTop(m_hwndIPObject);
// If user toggles off the toolbar while the object is UI active, and
// we are not still in activation process, we need to explictly tell Office
// apps to also hide the "Web" toolbar. For Office, OLECMDID_HIDETOOLBARS puts
// the app into a "web view" which (in some apps) brings up the web toolbar.
// Since we intend to have no tools, we have to turn it off by code...
if ((!m_fDisplayTools) && (m_fObjectUIActive) && (m_fObjectActivateComplete))
TurnOffWebToolbar();
}
else if (m_pdocv)
{
// If we have a DocObj server, but no IOleCommandTarget, do things the hard
// way and resize. When server attempts to resize window it will have to
// re-negotiate BorderSpace and we fail there, so server "should" not
// display its tools (at least that is the idea!<g>)...
RECT rc; GetClientRect(m_hwnd, &rc);
MapWindowPoints(m_hwnd, m_hwndCtl, (LPPOINT)&rc, 2);
OnNotifySizeChange(&rc);
}
}
return;
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject Protected Functions -- Helpers
//
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::CreateObjectStorage (protected)
//
// Makes the internal IStorage to host the object and assigns the CLSID.
//
STDMETHODIMP CDsoDocObject::CreateObjectStorage(REFCLSID rclsid)
{
HRESULT hr;
LPWSTR pwszName;
DWORD dwid;
CHAR szbuf[256];
if ((!m_pstgroot)) return E_UNEXPECTED;
// Next, create a new object storage (with unique name) in our
// temp root storage "file" (this keeps an OLE integrity some servers
// need to function correctly instead of IP activating from file directly).
// We make a fake object storage name...
dwid = ((rclsid.Data1)|GetTickCount());
wsprintf(szbuf, "OLEDocument%X", dwid);
if (!(pwszName = DsoConvertToLPWSTR(szbuf)))
return E_OUTOFMEMORY;
// Create the sub-storage...
hr = m_pstgroot->CreateStorage(pwszName,
STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &m_pstgfile);
DsoMemFree(pwszName);
if (FAILED(hr)) return hr;
// We'll also create a stream for OLE view settings (non-critical)...
if (pwszName = DsoConvertToLPWSTR(szbuf))
{
m_pstgroot->CreateStream(pwszName,
STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &m_pstmview);
DsoMemFree(pwszName);
}
// Finally, write out the CLSID for the new substorage...
hr = WriteClassStg(m_pstgfile, rclsid);
return hr;
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::SaveObjectStorage (protected)
//
// Saves the object back to the internal IStorage. Returns S_FALSE if
// there is no file storage for this document (it depends on how file
// was loaded). In most cases we should have one, and this copies data
// into the internal storage for save.
//
STDMETHODIMP CDsoDocObject::SaveObjectStorage()
{
HRESULT hr = S_FALSE;
IPersistStorage *pipstg = NULL;
// Got to have object to save state...
if (!m_pole) return E_UNEXPECTED;
// If we have file storage, ask for IPersist and Save (commit changes)...
if ((m_pstgfile) &&
SUCCEEDED(hr = m_pole->QueryInterface(IID_IPersistStorage, (void**)&pipstg)))
{
if (SUCCEEDED(hr = pipstg->Save(m_pstgfile, TRUE)))
hr = pipstg->SaveCompleted(NULL);
hr = m_pstgfile->Commit(STGC_DEFAULT);
pipstg->Release();
}
// Go ahead and save the view state if view still active (non-critical)...
if ((m_pdocv) && (m_pstmview))
{
m_pdocv->SaveViewState(m_pstmview);
m_pstmview->Commit(STGC_DEFAULT);
}
return hr;
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::ValidateDocObjectServer (protected)
//
// Quick validation check to see if CLSID is for DocObject server.
//
// Officially, the only way to determine if a server supports ActiveX
// Document embedding is to IP activate it and ask for IOleDocument,
// but that means going through the IP process just to fail if IOleDoc
// is not supported. Therefore, we are going to rely on the server's
// honesty in setting its reg keys to include the "DocObject" sub key
// under their CLSID.
//
// This is 99% accurate. For those servers that fail, too bad charlie!
//
STDMETHODIMP CDsoDocObject::ValidateDocObjectServer(REFCLSID rclsid)
{
HRESULT hr = DSO_E_INVALIDSERVER;
CHAR szKeyCheck[256];
LPSTR pszClsid;
HKEY hkey;
// We don't handle MSHTML even though it is DocObject server...
const GUID CLSID_MSHTMLDOC = {0x25336920,0x03F9,0x11CF,{0x8F,0xD0,0x00,0xAA,0x00,0x68,0x6F,0x13}};
if (rclsid == CLSID_MSHTMLDOC) return hr;
// Convert the CLSID to a string and check for DocObject sub key...
if (pszClsid = DsoCLSIDtoLPSTR(rclsid))
{
wsprintf(szKeyCheck, "CLSID\\%s\\DocObject", pszClsid);
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, szKeyCheck, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
{
hr = S_OK;
RegCloseKey(hkey);
}
DsoMemFree(pszClsid);
}
else hr = E_OUTOFMEMORY;
return hr;
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::ValidateFileExtension (protected)
//
// Adds a default extension to save file path if user didn't provide
// one (uses CLSID and registry to determine default extension).
//
STDMETHODIMP_(BOOL) CDsoDocObject::ValidateFileExtension(WCHAR* pwszFile, WCHAR** ppwszOut)
{
BOOL fHasExt = FALSE;
BOOL fChangedExt = FALSE;
LPWSTR pwszT;
LPSTR pszClsid;
DWORD dw;
if ((pwszFile) && (dw = lstrlenW(pwszFile)) && (ppwszOut))
{
*ppwszOut = NULL;
pwszT = (pwszFile + dw);
while ((pwszT != pwszFile) &&
(*(--pwszT)) && ((*pwszT != L'\\') && (*pwszT != L'/')))
{
if (*pwszT == L'.') fHasExt = TRUE;
}
if (!(fHasExt) && (pszClsid = DsoCLSIDtoLPSTR(m_clsidObject)))
{
HKEY hk;
DWORD dwType, dwSize;
LPWSTR pwszExt;
CHAR szkey[255];
CHAR szbuf[128];
wsprintf(szkey, "CLSID\\%s\\DefaultExtension", pszClsid);
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, szkey, 0, KEY_READ, &hk) == ERROR_SUCCESS)
{
LPSTR pszT = szbuf;
dwSize = 128;
if (RegQueryValueEx(hk, NULL, 0, &dwType, (BYTE*)pszT, &dwSize) == ERROR_SUCCESS)
{
while (*(pszT++) && (*pszT != ','))
(void)(0);
*pszT = '\0';
}
else lstrcpy(szbuf, ".ole");
RegCloseKey(hk);
}
else lstrcpy(szbuf, ".ole");
if (pwszExt = DsoConvertToLPWSTR(szbuf))
*ppwszOut = DsoCopyStringCat(pwszFile, pwszExt);
fChangedExt = ((*ppwszOut) != NULL);
DsoMemFree(pszClsid);
}
}
return fChangedExt;
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::CreateRosebudIPP (protected)
//
// Returns an instance of MSDAIPP (a.k.a., "Rosebud") which is used by
// Office/Windows for Web Folders (HTTP with DAV/FPSE).
//
// This is used to open web resources, lock them for editing, and save
// changes back up to the server as needed. If the provider is not
// installed or cannot be initialized, the functions returns NULL.
//
STDMETHODIMP_(IUnknown*) CDsoDocObject::CreateRosebudIPP()
{
HRESULT hr;
IDBProperties* pdbprops = NULL;
IBindResource* pres = NULL;
DBPROPSET rdbpset;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -