From 2c4a47190cdc64690f8f4c1c89a2ffac2fee962e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Bl=C3=A4sing?= Date: Wed, 4 May 2016 22:07:02 +0200 Subject: [PATCH] Exception from COMBindingBaseObject swallows real reason + HRESULT The exception thrown from COMBindingBaseObject when instatiation fails is misleading: COM object with CLSID {0002DF01-0000-0000-C000-000000000046} not registered properly! In the concrete case COM was not properly initialized, the same error now reports (in german locale): CoInitialize wurde nicht aufgerufen.(HRESULT: 800401f0) (puArgErr=) For english locale this should be along the lines of: CoInitialize was not called.(HRESULT: 800401f0) (puArgErr=) The message now points out the correct problem (as far as the windows error code translation works) and the HRESULT can be used for a locale independend report + search. Closes #646 --- CHANGES.md | 1 + .../win32/COM/COMBindingBaseObject.java | 64 ++++++------------- ...ComExceptionWithoutInitializationTest.java | 54 ++++++++++++++++ 3 files changed, 74 insertions(+), 45 deletions(-) create mode 100644 contrib/platform/test/com/sun/jna/platform/win32/COM/ComExceptionWithoutInitializationTest.java diff --git a/CHANGES.md b/CHANGES.md index 672f0aa4e1..f4e03016cc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -68,6 +68,7 @@ Bug Fixes * [#610](https://github.com/java-native-access/jna/pull/610): Fixed issue #604: Kernel32#GetLastError() always returns ERROR_SUCCESS [@lgoldstein](https://github.com/lgoldstein). * [#633](https://github.com/java-native-access/jna/pull/633): Restore default usage of platform native encoding for Java strings passed to native functions (was hard-coded to UTF-8 in 4.0 and later) [@amake](https://github.com/amake) * [#634](https://github.com/java-native-access/jna/pull/634): Improve BSTR handling and add `SysStringByteLen` and `SysStringLen` to `com.sun.jna.platform.win32.OleAuto` - [@matthiasblaesing](https://github.com/matthiasblaesing). +* [#646](https://github.com/java-native-access/jna/issues/646): `platform.win32.COM.COMBindingBaseObject` swallows reason if instantiation fails - [@matthiasblaesing](https://github.com/matthiasblaesing). Release 4.2.1 ============= diff --git a/contrib/platform/src/com/sun/jna/platform/win32/COM/COMBindingBaseObject.java b/contrib/platform/src/com/sun/jna/platform/win32/COM/COMBindingBaseObject.java index 857ecd2a14..dcefeaa605 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/COM/COMBindingBaseObject.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/COM/COMBindingBaseObject.java @@ -15,6 +15,7 @@ import com.sun.jna.WString; import com.sun.jna.platform.win32.Guid; import com.sun.jna.platform.win32.Guid.CLSID; +import com.sun.jna.platform.win32.Guid.GUID; import com.sun.jna.platform.win32.Guid.REFIID; import com.sun.jna.platform.win32.Kernel32; import com.sun.jna.platform.win32.OaIdl; @@ -74,52 +75,34 @@ public COMBindingBaseObject(CLSID clsid, boolean useActiveInstance, int dwClsContext) { assert COMUtils.comIsInitialized() : "COM not initialized"; - HRESULT hr; - - if (useActiveInstance) { - hr = OleAuto.INSTANCE.GetActiveObject(clsid, null, this.pUnknown); - - if (COMUtils.SUCCEEDED(hr)) { - this.iUnknown = new Unknown(this.pUnknown.getValue()); - hr = iUnknown.QueryInterface(new REFIID( IDispatch.IID_IDISPATCH), - this.pDispatch); - } else { - hr = Ole32.INSTANCE.CoCreateInstance(clsid, null, dwClsContext, - IDispatch.IID_IDISPATCH, this.pDispatch); - } - } else { - hr = Ole32.INSTANCE.CoCreateInstance(clsid, null, dwClsContext, - IDispatch.IID_IDISPATCH, this.pDispatch); - } - - if (COMUtils.FAILED(hr)) { - throw new COMException("COM object with CLSID " - + clsid.toGuidString() + " not registered properly!"); - } - - this.iDispatch = new Dispatch(this.pDispatch.getValue()); + init(useActiveInstance, clsid, dwClsContext); } public COMBindingBaseObject(String progId, boolean useActiveInstance, int dwClsContext) throws COMException { assert COMUtils.comIsInitialized() : "COM not initialized"; - - HRESULT hr; - // Get CLSID for Word.Application... CLSID.ByReference clsid = new CLSID.ByReference(); - hr = Ole32.INSTANCE.CLSIDFromProgID(progId, clsid); + HRESULT hr = Ole32.INSTANCE.CLSIDFromProgID(progId, clsid); - if (COMUtils.FAILED(hr)) { - throw new COMException("CLSIDFromProgID() failed!"); - } + COMUtils.checkRC(hr); + + init(useActiveInstance, clsid, dwClsContext); + } + + public COMBindingBaseObject(String progId, boolean useActiveInstance) + throws COMException { + this(progId, useActiveInstance, WTypes.CLSCTX_SERVER); + } + private void init(boolean useActiveInstance, GUID clsid, int dwClsContext) throws COMException { + HRESULT hr; if (useActiveInstance) { hr = OleAuto.INSTANCE.GetActiveObject(clsid, null, this.pUnknown); if (COMUtils.SUCCEEDED(hr)) { this.iUnknown = new Unknown(this.pUnknown.getValue()); - hr = iUnknown.QueryInterface(new REFIID(IDispatch.IID_IDISPATCH), + hr = iUnknown.QueryInterface(new REFIID( IDispatch.IID_IDISPATCH), this.pDispatch); } else { hr = Ole32.INSTANCE.CoCreateInstance(clsid, null, dwClsContext, @@ -129,21 +112,12 @@ public COMBindingBaseObject(String progId, boolean useActiveInstance, hr = Ole32.INSTANCE.CoCreateInstance(clsid, null, dwClsContext, IDispatch.IID_IDISPATCH, this.pDispatch); } - - if (COMUtils.FAILED(hr)) { - throw new COMException("COM object with ProgID '" + progId - + "' and CLSID " + clsid.toGuidString() - + " not registered properly!"); - } - + + COMUtils.checkRC(hr); + this.iDispatch = new Dispatch(this.pDispatch.getValue()); } - - public COMBindingBaseObject(String progId, boolean useActiveInstance) - throws COMException { - this(progId, useActiveInstance, WTypes.CLSCTX_SERVER); - } - + /** * Gets the i dispatch. * diff --git a/contrib/platform/test/com/sun/jna/platform/win32/COM/ComExceptionWithoutInitializationTest.java b/contrib/platform/test/com/sun/jna/platform/win32/COM/ComExceptionWithoutInitializationTest.java new file mode 100644 index 0000000000..cf3cf226ed --- /dev/null +++ b/contrib/platform/test/com/sun/jna/platform/win32/COM/ComExceptionWithoutInitializationTest.java @@ -0,0 +1,54 @@ +package com.sun.jna.platform.win32.COM; + +import com.sun.jna.platform.win32.Guid; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +public class ComExceptionWithoutInitializationTest { + + @Test + public void testCorrectExceptionOnFailedInitialization() { + String message = null; + try { + InternetExplorer ie = new InternetExplorer(); + } catch (COMException ex) { + message = ex.getMessage(); + } + + // This invocation must raise an exception, as the COM thread is not + // initialized, in the message it is expected, that the HRESULT is reported + // and the HRESULT resulting from calling into COM with it being initialized + // is 800401f0. The message is also expected to point the to correct + // initialization via CoInitialize + assertNotNull(message); + assertTrue(message.contains("HRESULT")); + assertTrue(message.contains("800401f0")); + assertTrue(message.contains("CoInitialize")); + } + + /** + * InternetExplorer / IWebBrowser2 - see + * http://msdn.microsoft.com/en-us/library/aa752127(v=vs.85).aspx + */ + private static class InternetExplorer extends COMLateBindingObject { + + public InternetExplorer(IDispatch iDispatch) { + super(iDispatch); + } + + public InternetExplorer() { + super(new Guid.CLSID("{0002DF01-0000-0000-C000-000000000046}"), true); + } + + /** + * IWebBrowser2::get_LocationURL
+ * Read-only COM property.
+ * + * @return the URL of the resource that is currently displayed. + */ + public String getURL() { + return getStringProperty("LocationURL"); + } + } +}