SF 1794811 Support unicode in COM error messages.
This commit is contained in:
@@ -20,15 +20,15 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td width="100%" colspan="2"><b>Bugs</b></td>
|
<td width="100%" colspan="2"><b>Bugs</b></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td width="13%" valign="top">1775889</td>
|
|
||||||
<td width="87%" valign="top">(M4) Fixed leak SafeArray setString(int[],value) and other setString() methods</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td width="13%" valign="top">1793362</td>
|
<td width="13%" valign="top">1793362</td>
|
||||||
<td width="87%" valign="top">(M5) ERROR_MORE_DATA causes failures. Fix submitted for defect found while porting
|
<td width="87%" valign="top">(M5) ERROR_MORE_DATA causes failures. Fix submitted for defect found while porting
|
||||||
Jameleon to use current release of Jacob. </td>
|
Jameleon to use current release of Jacob. </td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="13%" valign="top">1775889</td>
|
||||||
|
<td width="87%" valign="top">(M4) Fixed leak SafeArray setString(int[],value) and other setString() methods</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="13%" valign="top"> </td>
|
<td width="13%" valign="top"> </td>
|
||||||
<td width="87%" valign="top"> </td>
|
<td width="87%" valign="top"> </td>
|
||||||
@@ -37,11 +37,12 @@
|
|||||||
<td width="100%" colspan="2"><b>Patches</b></td>
|
<td width="100%" colspan="2"><b>Patches</b></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="13%" valign="top">1709841 </td>
|
<td width="13%" valign="top">1794811 </td>
|
||||||
<td width="87%" valign="top">(M1) Compiled with Visual Studio 2005. Jacob now requires
|
<td width="87%" valign="top">(M5) Support Unicode strings in COM failure messages</td>
|
||||||
2005 or later libraries.
|
</tr>
|
||||||
See the UsingJacob.html file for impact this has on NT, 2000 and Server 2003 users.
|
<tr>
|
||||||
</td>
|
<td width="13%" valign="top">1793346</td>
|
||||||
|
<td width="87%" valign="top">(M5) Replaced use of deprecated API and removed unused variables.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="13%" valign="top">1701995 </td>
|
<td width="13%" valign="top">1701995 </td>
|
||||||
@@ -51,8 +52,11 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="13%" valign="top">1793346</td>
|
<td width="13%" valign="top">1709841 </td>
|
||||||
<td width="87%" valign="top">(M5) Replaced use of deprecated API and removed unused variables.</td>
|
<td width="87%" valign="top">(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.
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="13%" valign="top"> </td>
|
<td width="13%" valign="top"> </td>
|
||||||
@@ -61,15 +65,15 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td width="100%" colspan="2"><b>Feature Requests</b></td>
|
<td width="100%" colspan="2"><b>Feature Requests</b></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="13%" valign="top">1772783 </td>
|
||||||
|
<td width="87%" valign="top">(M4) Added VT_DECIMAL support for BigDecimals whose scale less than 28 </td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="13%" valign="top">1761727</td>
|
<td width="13%" valign="top">1761727</td>
|
||||||
<td width="87%" valign="top">(M3) unittest directory test programs
|
<td width="87%" valign="top">(M3) unittest directory test programs
|
||||||
converted to JUnit 3.8.1. New ANT target created to run all unit tests. </td>
|
converted to JUnit 3.8.1. New ANT target created to run all unit tests. </td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td width="13%" valign="top">1772783 </td>
|
|
||||||
<td width="87%" valign="top">(M4) Added VT_DECIMAL support for BigDecimals whose scale less than 28 </td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td width="13%" valign="top"> </td>
|
<td width="13%" valign="top"> </td>
|
||||||
<td width="87%" valign="top"> </td>
|
<td width="87%" valign="top"> </td>
|
||||||
|
|||||||
@@ -323,27 +323,40 @@ static char* BasicToCharString(const BSTR inBasicString)
|
|||||||
::wcstombs_s(&convertedSize, charString, charStrSize, inBasicString, charStrSize);
|
::wcstombs_s(&convertedSize, charString, charStrSize, inBasicString, charStrSize);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
charString = ::_strdup("");
|
charString = ::_strdup("");
|
||||||
|
}
|
||||||
return charString;
|
return charString;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* CreateErrorMsgFromResult(HRESULT inResult)
|
static wchar_t* CreateErrorMsgFromResult(HRESULT inResult)
|
||||||
{
|
{
|
||||||
char* msg = NULL;
|
wchar_t* msg = NULL;
|
||||||
::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||||
FORMAT_MESSAGE_FROM_SYSTEM, NULL, inResult,MAKELANGID(LANG_NEUTRAL,
|
FORMAT_MESSAGE_FROM_SYSTEM, NULL, inResult,MAKELANGID(LANG_NEUTRAL,
|
||||||
SUBLANG_DEFAULT), (LPTSTR) &msg, 0, NULL);
|
SUBLANG_DEFAULT), (LPWSTR) &msg, 0, NULL);
|
||||||
if (msg == 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;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* CreateErrorMsgFromInfo(HRESULT inResult, EXCEPINFO* ioInfo,
|
static wchar_t* CreateErrorMsgFromInfo(HRESULT inResult, EXCEPINFO* ioInfo,
|
||||||
const char* methName)
|
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),
|
// If this is a dispatch exception (triggered by an Invoke message),
|
||||||
// then we have to take some additional steps to process the error
|
// 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);
|
(*(ioInfo->pfnDeferredFillIn))(ioInfo);
|
||||||
|
|
||||||
// Build the error message from exception information content.
|
// Build the error message from exception information content.
|
||||||
char* source = ::BasicToCharString(ioInfo->bstrSource);
|
int sourceLen = SysStringLen(ioInfo->bstrSource);
|
||||||
char* desc = ::BasicToCharString(ioInfo->bstrDescription);
|
int descLen = SysStringLen(ioInfo->bstrDescription);
|
||||||
const size_t MSG_LEN = ::strlen(methName) + ::strlen(source) + ::strlen(desc) + 128;
|
const size_t MSG_LEN = ::wcslen(methNameW) + sourceLen + descLen + 128;
|
||||||
msg = new char[MSG_LEN];
|
msg = new wchar_t[MSG_LEN];
|
||||||
::strncpy_s(msg, MSG_LEN, "Invoke of: ", strlen("Invoke of: "));
|
::wcsncpy_s(msg, MSG_LEN, L"Invoke of: ", wcslen(L"Invoke of: "));
|
||||||
::strncat_s(msg, MSG_LEN, methName, strlen(methName));
|
::wcsncat_s(msg, MSG_LEN, methNameW, wcslen(methNameW));
|
||||||
::strncat_s(msg, MSG_LEN, "\nSource: ", strlen("\nSource: "));
|
::wcsncat_s(msg, MSG_LEN, L"\nSource: ", wcslen(L"\nSource: "));
|
||||||
::strncat_s(msg, MSG_LEN, source, strlen(source));
|
::wcsncat_s(msg, MSG_LEN, ioInfo->bstrSource, sourceLen);
|
||||||
::strncat_s(msg, MSG_LEN, "\nDescription: ", strlen("\nDescription: "));
|
::wcsncat_s(msg, MSG_LEN, L"\nDescription: ", wcslen(L"\nDescription: "));
|
||||||
::strncat_s(msg, MSG_LEN, desc, strlen(desc));
|
::wcsncat_s(msg, MSG_LEN, ioInfo->bstrDescription, descLen);
|
||||||
::strncat_s(msg, MSG_LEN, "\n", strlen("\n"));
|
::wcsncat_s(msg, MSG_LEN, L"\n", wcslen(L"\n"));
|
||||||
delete source;
|
|
||||||
delete desc;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char* msg2 = CreateErrorMsgFromResult(inResult);
|
wchar_t* msg2 = CreateErrorMsgFromResult(inResult);
|
||||||
const size_t MSG_LEN = ::strlen(methName) + ::strlen(msg2) + 128;
|
const size_t MSG_LEN = ::wcslen(methNameW) + ::wcslen(msg2) + 256;
|
||||||
msg = new char[MSG_LEN];
|
msg = new wchar_t[MSG_LEN];
|
||||||
::strncpy_s(msg, MSG_LEN,
|
::wcsncpy_s(msg, MSG_LEN,
|
||||||
"A COM exception has been encountered:\nAt Invoke of: ",
|
L"A COM exception has been encountered:\nAt Invoke of: ",
|
||||||
strlen("A COM exception has been encountered:\nAt Invoke of: "));
|
wcslen(L"A COM exception has been encountered:\nAt Invoke of: "));
|
||||||
::strncat_s(msg, MSG_LEN, methName, strlen(methName));
|
::wcsncat_s(msg, MSG_LEN, methNameW, wcslen(methNameW));
|
||||||
::strncat_s(msg, MSG_LEN, "\nDescription: ", strlen("\nDescription: "));
|
::wcsncat_s(msg, MSG_LEN, L"\nDescription: ", wcslen(L"\nDescription: "));
|
||||||
::strncat_s(msg, MSG_LEN, msg2, strlen(msg2));
|
::wcsncat_s(msg, MSG_LEN, msg2, wcslen(msg2));
|
||||||
// jacob-msg 1075 - SF 1053872 : Documentation says "use LocalFree"!!
|
// jacob-msg 1075 - SF 1053872 : Documentation says "use LocalFree"!!
|
||||||
//delete msg2;
|
//delete msg2;
|
||||||
LocalFree(msg2);
|
LocalFree(msg2);
|
||||||
}
|
}
|
||||||
|
delete methNameW;
|
||||||
return msg;
|
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
|
// check for error and display a somewhat verbose error message
|
||||||
if (!SUCCEEDED(hr)) {
|
if (!SUCCEEDED(hr)) {
|
||||||
// two buffers that may have to be freed later
|
// two buffers that may have to be freed later
|
||||||
char *buf = NULL;
|
wchar_t *buf = NULL;
|
||||||
char *dispIdAsName = NULL;
|
char *dispIdAsName = NULL;
|
||||||
// this method can get called with a name or a dispatch id
|
// this method can get called with a name or a dispatch id
|
||||||
// we need to handle both SF 1114159
|
// 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 (buf) delete buf;
|
||||||
if (dispIdAsName) delete dispIdAsName;
|
if (dispIdAsName) delete dispIdAsName;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
18
jni/util.cpp
18
jni/util.cpp
@@ -36,12 +36,28 @@ void ThrowComFail(JNIEnv *env, const char* desc, jint hr)
|
|||||||
// call the constructor that takes hr and message
|
// call the constructor that takes hr and message
|
||||||
jmethodID failCons =
|
jmethodID failCons =
|
||||||
env->GetMethodID(failClass, "<init>", "(ILjava/lang/String;)V");
|
env->GetMethodID(failClass, "<init>", "(ILjava/lang/String;)V");
|
||||||
if (!desc) desc = "Java/COM Error";
|
if (!desc) {
|
||||||
|
desc = "Java/COM Error";
|
||||||
|
}
|
||||||
jstring js = env->NewStringUTF(desc);
|
jstring js = env->NewStringUTF(desc);
|
||||||
jthrowable fail = (jthrowable)env->NewObject(failClass, failCons, hr, js);
|
jthrowable fail = (jthrowable)env->NewObject(failClass, failCons, hr, js);
|
||||||
env->Throw(fail);
|
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, "<init>", "(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
|
// if env's are different throw on the 1st env
|
||||||
int CheckEnv(JNIEnv *env1, JNIEnv *env2)
|
int CheckEnv(JNIEnv *env1, JNIEnv *env2)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
VARIANT *extractVariant(JNIEnv *env, jobject arg);
|
VARIANT *extractVariant(JNIEnv *env, jobject arg);
|
||||||
void ThrowComFail(JNIEnv *env, const char* desc, jint hr);
|
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);
|
IDispatch *extractDispatch(JNIEnv *env, jobject arg);
|
||||||
SAFEARRAY *extractSA(JNIEnv *env, jobject arg);
|
SAFEARRAY *extractSA(JNIEnv *env, jobject arg);
|
||||||
void setSA(JNIEnv *env, jobject arg, SAFEARRAY *sa, int copy);
|
void setSA(JNIEnv *env, jobject arg, SAFEARRAY *sa, int copy);
|
||||||
|
|||||||
28
unittest/com/jacob/test/errors/UnicodeErrorTest.java
Normal file
28
unittest/com/jacob/test/errors/UnicodeErrorTest.java
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user