HRESULT Reference::invoke (MEMBERID memberid, WORD dispatchFlags, const TypedArguments &arguments, VARIANT *pResult) { if (m_pInterface != 0 && !m_pInterface->dispatchOnly()) { EXCEPINFO excepInfo; memset(&excepInfo, 0, sizeof(excepInfo)); unsigned argErr; // Invoke through virtual function table. ITypeInfo *pTypeInfo = interfaceDesc()->typeInfo(); HRESULT hr = pTypeInfo->Invoke( m_pUnknown, memberid, dispatchFlags, arguments.dispParams(), pResult, &excepInfo, &argErr); if (SUCCEEDED(hr)) { return hr; } if (hr == DISP_E_EXCEPTION) { throwDispatchException(excepInfo); } else if (hr == DISP_E_TYPEMISMATCH || hr == DISP_E_PARAMNOTFOUND) { throw InvokeException(hr, arguments.dispParams()->cArgs - argErr); } } return invokeDispatch(memberid, dispatchFlags, arguments, pResult); }
Error WordViewer::closeLastViewedDocument() { Error errorHR = Success(); HRESULT hr = S_OK; if (idispWord_ == NULL) return Success(); // Find the open document corresponding to the one we last rendered. If we // find it, close it; if we can't find it, do nothing. IDispatch* idispDoc = NULL; errorHR = getDocumentByPath(docPath_, &idispDoc); if (errorHR) return errorHR; if (idispDoc == NULL) return Success(); errorHR = getDocumentPosition(idispDoc, &docScrollX_, &docScrollY_); if (errorHR) LOG_ERROR(errorHR); VERIFY_HRESULT(invokeDispatch(DISPATCH_METHOD, NULL, idispDoc, L"Close", 0)); LErrExit: return errorHR; }
Error WordViewer::setDocumentPosition(IDispatch* idispDoc, int xPos, int yPos) { Error errorHR = Success(); HRESULT hr = S_OK; IDispatch* idispWindow = NULL; VARIANT varPos; varPos.vt = VT_INT; VERIFY_HRESULT(getIDispatchProp(idispDoc, L"ActiveWindow", &idispWindow)); varPos.intVal = xPos; VERIFY_HRESULT(invokeDispatch(DISPATCH_PROPERTYPUT, NULL, idispWindow, L"HorizontalPercentScrolled", 1, varPos)); varPos.intVal = yPos; VERIFY_HRESULT(invokeDispatch(DISPATCH_PROPERTYPUT, NULL, idispWindow, L"VerticalPercentScrolled", 1, varPos)); LErrExit: return errorHR; }
Error WordViewer::showWord() { Error errorHR = Success(); HRESULT hr = S_OK; VARIANT visible; visible.vt = VT_BOOL; visible.boolVal = true; VERIFY_HRESULT(invokeDispatch(DISPATCH_PROPERTYPUT, NULL, idispWord_, L"Visible", 1, visible)); LErrExit: return errorHR; }
// Given a path, searches for the document in the Documents collection that // has the path given. The out parameter is set to that document's IDispatch // pointer, or NULL if no document with the path could be found. Error WordViewer::getDocumentByPath(QString& path, IDispatch** pidispDoc) { Error errorHR = Success(); HRESULT hr = S_OK; IDispatch* idispDocs = NULL; IDispatch* idispDoc = NULL; VARIANT varDocIdx; VARIANT varResult; int docCount = 0; *pidispDoc = NULL; VERIFY_HRESULT(getIDispatchProp(idispWord_, L"Documents", &idispDocs)); VERIFY_HRESULT(getIntProp(idispDocs, L"Count", &docCount)); varDocIdx.vt = VT_INT; for (int i = 1; i <= docCount; i++) { VariantInit(&varResult); varDocIdx.intVal = i; VERIFY_HRESULT(invokeDispatch(DISPATCH_METHOD, &varResult, idispDocs, L"Item", 1, varDocIdx)); idispDoc = varResult.pdispVal; VERIFY_HRESULT(invokeDispatch(DISPATCH_PROPERTYGET, &varResult, idispDoc, L"FullName", 0)); if (path.toStdWString() == varResult.bstrVal) { *pidispDoc = idispDoc; break; } } LErrExit: return errorHR; }
Error WordViewer::showDocument(QString& path) { Error errorHR = Success(); HRESULT hr = S_OK; // Allow Word to become the foreground window. CoAllowSetForegroundWindow // would be preferable here, since we'd be able to restrict activation to // only the process we started, but it is not exposed by MinGW headers. // Note that AllowSetForegroundWindow already limits activation to processes // initiated by the foreground process, and self-expires on user input. AllowSetForegroundWindow(ASFW_ANY); // If we have an active IDispatch pointer to Word, check to see whether // it has been closed if (idispWord_ != NULL) { // Test the interface by looking up a known DISPID const WCHAR* wstrQuit = L"Quit"; DISPID dispid; hr = idispWord_->GetIDsOfNames(IID_NULL, const_cast<WCHAR**>(&wstrQuit), 1, LOCALE_USER_DEFAULT, &dispid); // If the lookup fails, release this IDispatch pointer--it's stale. // We'll CoCreate a new instance of Word below. if (FAILED(hr) && SCODE_CODE(hr) == RPC_S_SERVER_UNAVAILABLE) { idispWord_->Release(); idispWord_ = NULL; } } // Get an IDispatch for the Word Application root object if (idispWord_ == NULL) { CLSID clsid; LPCOLESTR progId = L"Word.Application"; CoInitialize(NULL); VERIFY_HRESULT(CLSIDFromProgID(progId, &clsid)); VERIFY_HRESULT(CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, reinterpret_cast<void**>(&idispWord_))); idispWord_->AddRef(); } // Make Word visible errorHR = showWord(); if (errorHR) return errorHR; IDispatch* idispDocs; IDispatch* idispDoc; VERIFY_HRESULT(getIDispatchProp(idispWord_, L"Documents", &idispDocs)); // Open the documenet path = path.replace(QChar(L'/'), QChar(L'\\')); errorHR = openDocument(path, idispDocs, &idispDoc); if (errorHR) return errorHR; if (docPath_ == path) { // Reopening the last-opened doc: apply the scroll position if we have // one cached if (docScrollX_ > 0 || docScrollY_ > 0) setDocumentPosition(idispDoc, docScrollX_, docScrollY_); } else { // Opening a different doc: forget scroll position and save the doc name docScrollX_ = 0; docScrollY_ = 0; docPath_ = path; } // Bring Word to the foreground VERIFY_HRESULT(invokeDispatch(DISPATCH_METHOD, NULL, idispWord_, L"Activate", 0)); LErrExit: return errorHR; }