diff --git a/docs/ReleaseNotes.html b/docs/ReleaseNotes.html
index 907e765..e43e019 100644
--- a/docs/ReleaseNotes.html
+++ b/docs/ReleaseNotes.html
@@ -20,15 +20,15 @@
| Bugs |
-
- | 1775889 |
- (M4) Fixed leak SafeArray setString(int[],value) and other setString() methods |
-
| 1793362 |
(M5) ERROR_MORE_DATA causes failures. Fix submitted for defect found while porting
Jameleon to use current release of Jacob. |
+
+ | 1775889 |
+ (M4) Fixed leak SafeArray setString(int[],value) and other setString() methods |
+
| |
|
@@ -37,11 +37,12 @@
Patches |
- | 1709841 |
- (M1) Compiled with Visual Studio 2005. Jacob now requires
- 2005 or later libraries.
- See the UsingJacob.html file for impact this has on NT, 2000 and Server 2003 users.
- |
+ 1794811 |
+ (M5) Support Unicode strings in COM failure messages |
+
+
+ | 1793346 |
+ (M5) Replaced use of deprecated API and removed unused variables. |
| 1701995 |
@@ -51,8 +52,11 @@
- | 1793346 |
- (M5) Replaced use of deprecated API and removed unused variables. |
+ 1709841 |
+ (M1) Compiled with Visual Studio 2005. Jacob now requires
+ 2005 or later libraries.
+ See the UsingJacob.html file for impact this has on NT, 2000 and Server 2003 users.
+ |
| |
@@ -61,15 +65,15 @@
| Feature Requests |
+
+ | 1772783 |
+ (M4) Added VT_DECIMAL support for BigDecimals whose scale less than 28 |
+
| 1761727 |
(M3) unittest directory test programs
converted to JUnit 3.8.1. New ANT target created to run all unit tests. |
-
- | 1772783 |
- (M4) Added VT_DECIMAL support for BigDecimals whose scale less than 28 |
-
| |
|
diff --git a/jni/Dispatch.cpp b/jni/Dispatch.cpp
index 285427d..81868e6 100644
--- a/jni/Dispatch.cpp
+++ b/jni/Dispatch.cpp
@@ -322,28 +322,41 @@ static char* BasicToCharString(const BSTR inBasicString)
size_t convertedSize;
::wcstombs_s(&convertedSize, charString, charStrSize, inBasicString, charStrSize);
}
- else
+ else
+ {
charString = ::_strdup("");
-
+ }
return charString;
}
-static char* CreateErrorMsgFromResult(HRESULT inResult)
+static wchar_t* CreateErrorMsgFromResult(HRESULT inResult)
{
- char* msg = NULL;
- ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ wchar_t* msg = NULL;
+ ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, NULL, inResult,MAKELANGID(LANG_NEUTRAL,
- SUBLANG_DEFAULT), (LPTSTR) &msg, 0, NULL);
+ SUBLANG_DEFAULT), (LPWSTR) &msg, 0, NULL);
if (msg == NULL)
- msg = ::_strdup("An unknown COM error has occured.");
+ {
+ const wchar_t* message_text = L"An unknown COM error has occured.";
+ size_t bufferLength = (wcslen(message_text) + 1) * sizeof(wchar_t);
+ msg = (wchar_t*) ::LocalAlloc(LPTR, bufferLength);
+ wcscpy_s(msg, bufferLength, message_text);
+ }
return msg;
}
-static char* CreateErrorMsgFromInfo(HRESULT inResult, EXCEPINFO* ioInfo,
+static wchar_t* CreateErrorMsgFromInfo(HRESULT inResult, EXCEPINFO* ioInfo,
const char* methName)
{
- char* msg = NULL;
+ wchar_t* msg = NULL;
+ size_t methNameWSize = 0;
+
+ mbstowcs_s(&methNameWSize, NULL, 0, methName, _TRUNCATE);
+
+ wchar_t* methNameW = new wchar_t[methNameWSize];
+
+ mbstowcs_s(NULL, methNameW, methNameWSize, methName, _TRUNCATE);
// If this is a dispatch exception (triggered by an Invoke message),
// then we have to take some additional steps to process the error
@@ -356,35 +369,34 @@ static char* CreateErrorMsgFromInfo(HRESULT inResult, EXCEPINFO* ioInfo,
(*(ioInfo->pfnDeferredFillIn))(ioInfo);
// Build the error message from exception information content.
- char* source = ::BasicToCharString(ioInfo->bstrSource);
- char* desc = ::BasicToCharString(ioInfo->bstrDescription);
- const size_t MSG_LEN = ::strlen(methName) + ::strlen(source) + ::strlen(desc) + 128;
- msg = new char[MSG_LEN];
- ::strncpy_s(msg, MSG_LEN, "Invoke of: ", strlen("Invoke of: "));
- ::strncat_s(msg, MSG_LEN, methName, strlen(methName));
- ::strncat_s(msg, MSG_LEN, "\nSource: ", strlen("\nSource: "));
- ::strncat_s(msg, MSG_LEN, source, strlen(source));
- ::strncat_s(msg, MSG_LEN, "\nDescription: ", strlen("\nDescription: "));
- ::strncat_s(msg, MSG_LEN, desc, strlen(desc));
- ::strncat_s(msg, MSG_LEN, "\n", strlen("\n"));
- delete source;
- delete desc;
+ int sourceLen = SysStringLen(ioInfo->bstrSource);
+ int descLen = SysStringLen(ioInfo->bstrDescription);
+ const size_t MSG_LEN = ::wcslen(methNameW) + sourceLen + descLen + 128;
+ msg = new wchar_t[MSG_LEN];
+ ::wcsncpy_s(msg, MSG_LEN, L"Invoke of: ", wcslen(L"Invoke of: "));
+ ::wcsncat_s(msg, MSG_LEN, methNameW, wcslen(methNameW));
+ ::wcsncat_s(msg, MSG_LEN, L"\nSource: ", wcslen(L"\nSource: "));
+ ::wcsncat_s(msg, MSG_LEN, ioInfo->bstrSource, sourceLen);
+ ::wcsncat_s(msg, MSG_LEN, L"\nDescription: ", wcslen(L"\nDescription: "));
+ ::wcsncat_s(msg, MSG_LEN, ioInfo->bstrDescription, descLen);
+ ::wcsncat_s(msg, MSG_LEN, L"\n", wcslen(L"\n"));
}
else
{
- char* msg2 = CreateErrorMsgFromResult(inResult);
- const size_t MSG_LEN = ::strlen(methName) + ::strlen(msg2) + 128;
- msg = new char[MSG_LEN];
- ::strncpy_s(msg, MSG_LEN,
- "A COM exception has been encountered:\nAt Invoke of: ",
- strlen("A COM exception has been encountered:\nAt Invoke of: "));
- ::strncat_s(msg, MSG_LEN, methName, strlen(methName));
- ::strncat_s(msg, MSG_LEN, "\nDescription: ", strlen("\nDescription: "));
- ::strncat_s(msg, MSG_LEN, msg2, strlen(msg2));
+ wchar_t* msg2 = CreateErrorMsgFromResult(inResult);
+ const size_t MSG_LEN = ::wcslen(methNameW) + ::wcslen(msg2) + 256;
+ msg = new wchar_t[MSG_LEN];
+ ::wcsncpy_s(msg, MSG_LEN,
+ L"A COM exception has been encountered:\nAt Invoke of: ",
+ wcslen(L"A COM exception has been encountered:\nAt Invoke of: "));
+ ::wcsncat_s(msg, MSG_LEN, methNameW, wcslen(methNameW));
+ ::wcsncat_s(msg, MSG_LEN, L"\nDescription: ", wcslen(L"\nDescription: "));
+ ::wcsncat_s(msg, MSG_LEN, msg2, wcslen(msg2));
// jacob-msg 1075 - SF 1053872 : Documentation says "use LocalFree"!!
//delete msg2;
LocalFree(msg2);
}
+ delete methNameW;
return msg;
}
@@ -505,7 +517,7 @@ JNIEXPORT jobject JNICALL Java_com_jacob_com_Dispatch_invokev
// check for error and display a somewhat verbose error message
if (!SUCCEEDED(hr)) {
// two buffers that may have to be freed later
- char *buf = NULL;
+ wchar_t *buf = NULL;
char *dispIdAsName = NULL;
// this method can get called with a name or a dispatch id
// we need to handle both SF 1114159
@@ -534,7 +546,7 @@ JNIEXPORT jobject JNICALL Java_com_jacob_com_Dispatch_invokev
}
}
- ThrowComFail(env, buf, hr);
+ ThrowComFailUnicode(env, buf, hr);
if (buf) delete buf;
if (dispIdAsName) delete dispIdAsName;
return NULL;
diff --git a/jni/util.cpp b/jni/util.cpp
index 268bd27..3ef1e5c 100644
--- a/jni/util.cpp
+++ b/jni/util.cpp
@@ -36,12 +36,28 @@ void ThrowComFail(JNIEnv *env, const char* desc, jint hr)
// call the constructor that takes hr and message
jmethodID failCons =
env->GetMethodID(failClass, "", "(ILjava/lang/String;)V");
- if (!desc) desc = "Java/COM Error";
+ if (!desc) {
+ desc = "Java/COM Error";
+ }
jstring js = env->NewStringUTF(desc);
jthrowable fail = (jthrowable)env->NewObject(failClass, failCons, hr, js);
env->Throw(fail);
}
+void ThrowComFailUnicode(JNIEnv *env, const wchar_t* desc, jint hr)
+{
+ if (!desc) {
+ ThrowComFail(env, "Java/COM Error", hr);
+ }
+ jclass failClass = env->FindClass("com/jacob/com/ComFailException");
+ // call the constructor that takes hr and message
+ jmethodID failCons =
+ env->GetMethodID(failClass, "", "(ILjava/lang/String;)V");
+ jstring js = env->NewString((const jchar *) desc, wcslen(desc));
+ jthrowable fail = (jthrowable)env->NewObject(failClass, failCons, hr, js);
+ env->Throw(fail);
+}
+
// if env's are different throw on the 1st env
int CheckEnv(JNIEnv *env1, JNIEnv *env2)
{
diff --git a/jni/util.h b/jni/util.h
index 2fc570c..863ef0e 100644
--- a/jni/util.h
+++ b/jni/util.h
@@ -21,6 +21,7 @@
extern "C" {
VARIANT *extractVariant(JNIEnv *env, jobject arg);
void ThrowComFail(JNIEnv *env, const char* desc, jint hr);
+ void ThrowComFailUnicode(JNIEnv *env, const wchar_t* desc, jint hr);
IDispatch *extractDispatch(JNIEnv *env, jobject arg);
SAFEARRAY *extractSA(JNIEnv *env, jobject arg);
void setSA(JNIEnv *env, jobject arg, SAFEARRAY *sa, int copy);
diff --git a/unittest/com/jacob/test/errors/UnicodeErrorTest.java b/unittest/com/jacob/test/errors/UnicodeErrorTest.java
new file mode 100644
index 0000000..d6f60a7
--- /dev/null
+++ b/unittest/com/jacob/test/errors/UnicodeErrorTest.java
@@ -0,0 +1,28 @@
+package com.jacob.test.errors;
+
+import com.jacob.test.BaseTestCase;
+import com.jacob.activeX.ActiveXComponent;
+import com.jacob.com.ComException;
+
+/**
+ * This test verifies patch SF 1794811 .
+ * It shows how unicode filenames throw exceptions in 1.13M4 and earlier.
+ * @author justme84
+ *
+ */
+public class UnicodeErrorTest extends BaseTestCase {
+
+ public void testUnicodeCharactersInErrorMessage() {
+ ActiveXComponent application = new ActiveXComponent("Word.Application");
+ ActiveXComponent documents = application.getPropertyAsComponent("Documents");
+ String fileName = "abc\u0411\u0412\u0413\u0414def";
+ try {
+ documents.invoke("Open", fileName);
+ fail("Should have thrown an exception");
+ } catch (ComException e) {
+ assertTrue("Error message should contain file name with unicode " +
+ "characters in it. "+e.getMessage(),
+ e.getMessage().indexOf(fileName) > 0);
+ }
+ }
+}
\ No newline at end of file