Details
-
Bug
-
Resolution: Unresolved
-
P4: Low
-
None
-
5.12.6
-
None
-
Windows 7/10, Office 2010
Description
Code:
CoInitialize(NULL); QAxObject *app = new QAxObject("Word.Application"); app->setProperty("Visible", QVariant(true)); QAxObject *documents = app->querySubObject("Documents"); QAxObject *document = documents->querySubObject("Open(const QString&)", QVariant("z:/a.doc")); QAxObject *window = document->querySubObject("ActiveWindow");
On some system, the last line will return a nullptr and throw out an error
QAxBase::querySubObject: ActiveWindow: Method or property is not of interface type in ({00020906-0000-0000-C000-000000000046})
I've tried on 20+ PCs, only a few have this problem.
On some of the affected systems, adding qApp->processEvents() or waiting a few moments before last line will solve this bug. The others still say ActiveWindow is not found.
If the line in a.doc was deleted, the code works again on all previously affected systems. But I can't delete it in the real life document.
I found out that on the affected systems, the disp->GetIDsOfNames in QAxMetaObject::dispIDofName returned VBA_E_INVALIDSTATE (0x800A8029) or VBA_E_CANTEXITDESIGNMODE (0x800ADF21), and the dispid was set to DISPID_VALUE
// qaxbase.cpp inline DISPID QAxMetaObject::dispIDofName(const QByteArray &name, IDispatch *disp) { DISPID dispid = dispIDs.value(name, DISPID_UNKNOWN); if (dispid == DISPID_UNKNOWN) { // get the Dispatch ID from the object QString unicodeName = QLatin1String(name); OLECHAR *names = reinterpret_cast<wchar_t *>(const_cast<ushort *>(unicodeName.utf16())); disp->GetIDsOfNames(IID_NULL, &names, 1, LOCALE_USER_DEFAULT, &dispid); if (dispid != DISPID_UNKNOWN) dispIDs.insert(name, dispid); } return dispid; }
Checking the returned value is not enough, because the document will be still in an invalid state. Googling 0x800ADF21 and 0x800A8029 will show that some other people suffered the same problem.
Although the IDispatch::GetIDsOfNames returns VBA_E_INVALIDSTATE or VBA_E_CANTEXITDESIGNMODE, I found a way to get id from the ITypeInfo interface. Here is my ugly patch
--- qaxbase.cpp 2019-11-05 15:47:56.878410600 +0800 +++ qaxbase.cpp 2020-01-21 13:51:15.094494100 +0800 @@ -219,8 +219,28 @@ // get the Dispatch ID from the object QString unicodeName = QLatin1String(name); OLECHAR *names = reinterpret_cast<wchar_t *>(const_cast<ushort *>(unicodeName.utf16())); - disp->GetIDsOfNames(IID_NULL, &names, 1, LOCALE_USER_DEFAULT, &dispid); - if (dispid != DISPID_UNKNOWN) + HRESULT hres = disp->GetIDsOfNames(IID_NULL, &names, 1, LOCALE_USER_DEFAULT, &dispid); + // VBA_E_INVALIDSTATE or VBA_E_CANTEXITDESIGNMODE + if (hres == static_cast<HRESULT>(0x800A8029) || hres == static_cast<HRESULT>(0x800ADF21)) { + ITypeInfo *typeInfo; + if (disp->GetTypeInfo(0, LOCALE_USER_DEFAULT, &typeInfo) == S_OK) { + hres = typeInfo->GetIDsOfNames(&names, 1, &dispid); + if (hres == E_NOTIMPL) { + BSTR members[32]; + UINT c; + for (DISPID id = 0; id <= 65536; id++) { + if (typeInfo->GetNames(id, members, 32, &c) == S_OK) { + if (wcscmp(names, members[0]) == 0) { + dispid = id; + hres = S_OK; + break; + } + } + } + } + } + } + if (hres == S_OK && dispid != DISPID_UNKNOWN) dispIDs.insert(name, dispid); } return dispid;
Attachments
Issue Links
- relates to
-
QTBUG-81543 Cannot find Application.WordBasic.DisableAutoMacros
- Closed