📄 dsofdocobj.cpp
字号:
/***************************************************************************
* DSOFDOCOBJ.CPP
*
* CDsoDocObject: ActiveX Document Single Instance Frame/Site Object
*
* Copyright ?999-2004; Microsoft Corporation. All rights reserved.
* Written by Microsoft Developer Support Office Integration (PSS DSOI)
*
* This code is provided via KB 311765 as a sample. It is not a formal
* product and has not been tested with all containers or servers. Use it
* for educational purposes only. See the EULA.TXT file included in the
* KB download for full terms of use and restrictions.
*
* THIS CODE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
*
***************************************************************************/
#include "dsoframer.h"
#include "xmlhttpclient.h"
////////////////////////////////////////////////////////////////////////
// CDsoDocObject - The DocObject Site Class
//
// This class wraps the functionality for DocObject hosting. Right now
// we are setup for one active site at a time, but this could be changed
// to allow multiple sites (although only one could be UI active at any
// given time).
//
CDsoDocObject::CDsoDocObject()
{
ODS("CDsoDocObject::CDsoDocObject\n");
m_bNewCreate = TRUE;
m_pParentCtrl = NULL;
m_hwnd = NULL;
m_hwndCtl = NULL;
m_pcmdCtl = NULL;
m_rcViewRect.left = m_rcViewRect.top = m_rcViewRect.right = m_rcViewRect.bottom = 0;
m_pwszSourceFile = NULL;
m_pstgSourceFile = NULL;
m_pmkSourceObject = NULL;
m_idxSourceName = 0;
m_pstgroot = NULL;
m_pstgfile = NULL;
m_pstmview = NULL;
m_pwszWebResource = NULL;
m_pstmWebResource = NULL;
m_punkRosebud = NULL;
m_pwszUsername = NULL;
m_pwszPassword = NULL;
m_pwszHostName = NULL;
memset(&m_clsidObject, 0, sizeof(CLSID));
m_pole = NULL;
m_pipobj = NULL;
m_pipactive = NULL;
m_pdocv = NULL;
m_pcmdt = NULL;
m_pprtprv = NULL;
m_hMenuActive = NULL;
m_hMenuMerged = NULL;
m_holeMenu = NULL;
m_hwndMenuObj = NULL;
m_hwndIPObject = NULL;
m_hwndUIActiveObj = NULL;
m_dwObjectThreadID = 0;
memset(&m_bwToolSpace, 0, sizeof(BORDERWIDTHS));
m_fDisconnectOnQuit = 0;
m_fAppWindowActive = 0;
m_fOpenReadOnly = 0;
m_fObjectInModalCondition = 0;
m_fObjectIPActive = 0;
m_fObjectUIActive = 0;
m_fObjectActivateComplete = 0;
m_fLockedServerRunning = 0;
m_fLoadedFromAuto = 0;
m_fInClose = 0;
m_cRef = 1;
m_fDisplayTools = TRUE;
}
CDsoDocObject::~CDsoDocObject(void)
{
ODS("CDsoDocObject::~CDsoDocObject\n");
if (m_pole) Close();
if (m_hwnd) DestroyWindow(m_hwnd);
SAFE_FREESTRING(m_pwszUsername);
SAFE_FREESTRING(m_pwszPassword);
SAFE_FREESTRING(m_pwszHostName);
SAFE_RELEASE_INTERFACE(m_punkRosebud);
SAFE_RELEASE_INTERFACE(m_pcmdCtl);
SAFE_RELEASE_INTERFACE(m_pstgroot);
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::InitializeNewInstance
//
// Sets up the docobject site. We must a control site to attach to and
// a bounding rect. The IOleCommandTarget is used to forward toolbar
// commands back to the host if a user selects one.
//
STDMETHODIMP CDsoDocObject::InitializeNewInstance(HWND hwndCtl, LPRECT prcPlace, LPWSTR pwszHost, IOleCommandTarget* pcmdCtl)
{
HRESULT hr = E_UNEXPECTED;
WNDCLASS wndclass;
ODS("CDsoDocObject::InitializeNewInstance()\n");
// As an AxDoc site, we need a valid parent window...
if ((!hwndCtl) || (!IsWindow(hwndCtl)))
return hr;
// Create a temp storage for this docobj site (if one already exists, bomb out)...
if ((m_pstgroot) || FAILED(hr = StgCreateDocfile(NULL, STGM_TRANSACTED | STGM_READWRITE |
STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_DELETEONRELEASE, 0, &m_pstgroot)))
return hr;
// If our site window class has not been registered before, we should register it...
// This is protected by a critical section just for fun. The fact we had to single
// instance the OCX because of the host hook makes having multiple instances conflict here
// very unlikely. However, that could change sometime, so better to be safe than sorry.
EnterCriticalSection(&v_csecThreadSynch);
if (GetClassInfo(v_hModule, "DSOFramerDocWnd", &wndclass) == 0)
{
memset(&wndclass, 0, sizeof(WNDCLASS));
wndclass.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
wndclass.lpfnWndProc = CDsoDocObject::FrameWindowProc;
wndclass.hInstance = v_hModule;
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.lpszClassName = "DSOFramerDocWnd";
if (RegisterClass(&wndclass) == 0)
hr = E_WIN32_LASTERROR;
}
LeaveCriticalSection(&v_csecThreadSynch);
if (FAILED(hr)) return hr;
// Save the place RECT (and validate as needed)...
CopyRect(&m_rcViewRect, prcPlace);
if (m_rcViewRect.top > m_rcViewRect.bottom) {m_rcViewRect.top = 0; m_rcViewRect.bottom = 0;}
if (m_rcViewRect.left > m_rcViewRect.right) {m_rcViewRect.left = 0; m_rcViewRect.right = 0;}
// Create our site window at the give location (we are child of the control window)...
m_hwnd = CreateWindowEx(0, "DSOFramerDocWnd", NULL, WS_CHILD | WS_VISIBLE,
m_rcViewRect.left, m_rcViewRect.top,
(m_rcViewRect.right - m_rcViewRect.left),
(m_rcViewRect.bottom - m_rcViewRect.top),
hwndCtl, NULL, v_hModule, NULL);
if (!m_hwnd) return E_OUTOFMEMORY;
SetWindowLong(m_hwnd, GWL_USERDATA, (LONG)this);
m_hwndCtl = hwndCtl;
m_pwszHostName = DsoCopyString(((pwszHost) ? pwszHost : L"DsoFramerControl"));
SAFE_SET_INTERFACE(m_pcmdCtl, pcmdCtl);
return S_OK;
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::InitObjectStorage
//
// Creates and fills the
//
STDMETHODIMP CDsoDocObject::InitObjectStorage(REFCLSID rclsid, IStorage *pstg)
{
HRESULT hr;
ODS("CDsoDocObject::InitObjectStorage()\n");
CHECK_NULL_RETURN(pstg, E_POINTER);
// Create a new storage for this CLSID...
if (FAILED(hr = CreateObjectStorage(rclsid)))
return hr;
// Copy data into the new storage and commit the change...
hr = pstg->CopyTo(0, NULL, NULL, m_pstgfile);
if (SUCCEEDED(hr)) hr = m_pstgfile->Commit(STGC_OVERWRITE);
return hr;
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::CreateDocObject
//
// This does the actual embedding. It is called no matter how you load
// an object, and does some checking to make sure the CLSID is for a
// a docobj server. If the function succeeds, we have an embedded object.
// To activate and show the object, you must call IPActivateView().
//
STDMETHODIMP CDsoDocObject::CreateDocObject(REFCLSID rclsid)
{
HRESULT hr;
BOOL fInitNew;
CLSID clsid;
DWORD dwMiscStatus = 0;
IOleObject* pole = NULL;
IPersistStorage* pipstg = NULL;
ODS("CDsoDocObject::CreateDocObject()\n");
ASSERT(!(m_pole));
IUnknown * pUnk=NULL;
if(::GetActiveObject(rclsid,NULL,&pUnk) == S_OK){
ODS("CDsoDocObject: Object is aleady open\n");
m_bNewCreate = FALSE;
}else{
ODS("CDsoDocObject: Object is new\n");
m_bNewCreate = TRUE;
}
// Don't load if an object has already been loaded...
if (m_pole) return E_UNEXPECTED;
// First, check the server to make sure it is AxDoc server...
if (FAILED(hr = ValidateDocObjectServer(rclsid)))
return hr;
// If we haven't loaded a storage, create a new one and remember to
// call InitNew (instead of Load) later on...
if ((fInitNew = (!m_pstgfile)) && FAILED(hr = CreateObjectStorage(rclsid)))
return hr;
// It is possible that someone picked an older ProgId/CLSID that
// will AutoConvert on CoCreate, so fix up the storage with the
// new CLSID info. We we actually call CoCreate on the new CLSID...
if (fInitNew && SUCCEEDED(OleGetAutoConvert(rclsid, &clsid)))
{
OleDoAutoConvert(m_pstgfile, &clsid);
}
else clsid = rclsid;
// We are ready to create an instance. Call CoCreate to make an
// inproc handler and ask for IOleObject (all docobjs must support this)...
if (FAILED(hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC, IID_IOleObject, (void**)&pole)))
return hr;
// Do a quick check to see if server wants us to set client site before the load...
if (SUCCEEDED(hr = pole->GetMiscStatus(DVASPECT_CONTENT, &dwMiscStatus)) &&
(dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST))
pole->SetClientSite((IOleClientSite*)&m_xOleClientSite);
// Load up the bloody thing...
if (SUCCEEDED(hr = pole->QueryInterface(IID_IPersistStorage, (void**)&pipstg)))
{
// Remember to InitNew if this is a new storage...
hr = ((fInitNew) ? pipstg->InitNew(m_pstgfile) : pipstg->Load(m_pstgfile));
pipstg->Release();
}
// Assuming all the above worked we should have an OLE Embeddable
// object and should finish the initialization (set object running)...
if (SUCCEEDED(hr))
{
// Save the IOleObject* and do a disconnect on quit...
m_fDisconnectOnQuit = TRUE;
m_pole = pole;
// Make sure the object is running (uses IRunnableObject)...
hr = EnsureOleServerRunning(TRUE);
if (SUCCEEDED(hr))
{
// If we didn't do so already, set our client site...
if (!(dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST))
m_pole->SetClientSite((IOleClientSite*)&m_xOleClientSite);
// Set the host names and then lock running...
m_pole->SetHostNames(m_pwszHostName, m_pwszHostName);
// Keep server CLSID for this object
m_clsidObject = clsid;
// Ask object to save (if dirty)...
if (IsStorageDirty()) SaveObjectStorage();
}
}
// If we hit an error, cleanup (release should free the obj)...
if (FAILED(hr))
{
if (dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST)
pole->SetClientSite(NULL);
pole->Release();
m_pole = NULL;
}
return hr;
}
////////////////////////////////////////////////////////////////////////
// CDsoDocObject::LoadStorageFromFile
//
// Loads the internal IStorage from a file (local or UNC).
//
// We handle three types of files: (1) BIFF files, which will just copy
// their storage into our own; (2) non-BIFF files that are associated
// with Office and can be loaded by IMoniker; and (3) non-BIFF files
// that are not associated with Office but may be loaded in Office using
// IPersistFile and then IPersistStorage (if an alternate CLSID is given),
//
// We do a special check for HTML/TXT files because they are associated
// with IE, and we don't support IE files per se. Instead, you should pass
// an alternate CLSID for the Office app you want to open that file in.
//
STDMETHODIMP CDsoDocObject::LoadStorageFromFile(LPWSTR pwszFile, REFCLSID rclsid, BOOL fReadOnly)
{
HRESULT hr;
CLSID clsid;
CLSID clsidConv;
DWORD dwBindFlgs;
IStorage *pstg = NULL;
IBindCtx *pbctx = NULL;
IMoniker *pmkfile = NULL;
IPersistStorage *pipstg = NULL;
BOOL fLoadFromAltCLSID = (rclsid != GUID_NULL);
if (!(pwszFile) || ((*pwszFile) == L'\0'))
return E_INVALIDARG;
TRACE1("CDsoDocObject::LoadStorageFromFile(%S)\n", pwszFile);
// First. we'll try to find the associated CLSID for the given file,
// and then set it to the alternate if not found. If we don't have a
// CLSID by the end of this, because user didn't specify alternate
// and GetClassFile failed, then we error out...
if (FAILED(GetClassFile(pwszFile, &clsid)) && !(fLoadFromAltCLSID))
return DSO_E_INVALIDSERVER;
// We should try to load from alternate CLSID if provided one...
if (fLoadFromAltCLSID) clsid = rclsid;
// We should also handle auto-convert to start "newest" server...
if (SUCCEEDED(OleGetAutoConvert(clsid, &clsidConv)))
clsid = clsidConv;
// Validate that we have a DocObject server...
if ((clsid == GUID_NULL) || FAILED(ValidateDocObjectServer(clsid)))
return DSO_E_INVALIDSERVER;
// We should have a CLSID, and can now create our substorage...
if (FAILED(hr = CreateObjectStorage(clsid)))
return hr;
// Check for IE cache items since these are read-only as far as user is concerned...
if (FIsIECacheFile(pwszFile)) fReadOnly = TRUE;
dwBindFlgs = (STGM_TRANSACTED | STGM_SHARE_DENY_WRITE | (fReadOnly ? STGM_READ : STGM_READWRITE));
// If these are native Office BiFF files, we can streamline the process to
// copy the main storage into our sub-storage, without any involvement from
// the server to fill our substorage. This will account for most Office loads...
if (SUCCEEDED(hr = StgOpenStorage(pwszFile, NULL, dwBindFlgs, NULL, 0, &pstg)))
{
hr = pstg->CopyTo(0, NULL, NULL, m_pstgfile);
if (SUCCEEDED(hr)) m_pstgfile->Commit(STGC_OVERWRITE);
// Should that fail, we have to do things the more "formal" way (asking server
// to properly save itself into our substorage)...
}
else if (fLoadFromAltCLSID)
{
// If we are loading using an alternate CLSID that is either associated
// with another app or is a non-Structured Storage doc not belonging to
// to Office, then we have to explictily create an instance of the
// alternate server (not the inproc handler), and load using IPersistFile,
// then ask the server to save itself as OLE object using IPersistStorage.
// This is an expensive way to copy a storage, so we only do this when
// we are forced to use the alternate CLSID. This will typically be
// the case for files like *.htm or *.asp that are not associated with
// Office, but can be opened in Office...
IPersistFile *pipf;
if (SUCCEEDED(hr = CoCreateInstance(clsid, NULL, CLSCTX_SERVER,
IID_IPersistFile, (void**)&pipf)))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -