fix(windows): support unicode strings properly in logs

Fixes #10604.

Note: does not address limitations in etl2log yet, but allows us to emit
unicode strings to the logs.
This commit is contained in:
Marc Durdin 2024-02-06 14:12:41 +07:00
parent dadbf050c2
commit 810ed35a8a
8 changed files with 93 additions and 45 deletions

View file

@ -30,6 +30,16 @@ int GetActualShiftState() { // I4843
}
extern "C" void _declspec(dllexport) WINAPI Keyman_WriteDebugEvent(char *file, int line, PWCHAR msg) {
// This function exists solely to provide a stable transition between versions
// of Keyman, so that things don't crash if an older version of kmtip.dll
// happens to call this function in a newer installation. It is not used in
// current versions of Keyman. This change came in around 17.0.260-alpha
PWCHAR fileW = strtowstr(file);
Keyman_WriteDebugEventW(fileW, line, msg);
delete[] fileW;
}
extern "C" void _declspec(dllexport) WINAPI Keyman_WriteDebugEventW(PWCHAR file, int line, PWCHAR msg) {
if (file == NULL || msg == NULL) {
return;
}
@ -102,8 +112,6 @@ extern "C" void _declspec(dllexport) WINAPI Keyman_WriteDebugEvent(char *file, i
DWORD platform = 1;
#endif
// TODO Convert to Unicode
PWCHAR fileW = strtowstr(file);
// These must match the manifest template in keyman-debug-etw.man
EventDataDescCreate(&Descriptors[0], &platform, sizeof(DWORD)); // <data name = "Platform" inType = "Platform" / >
@ -115,7 +123,7 @@ extern "C" void _declspec(dllexport) WINAPI Keyman_WriteDebugEvent(char *file, i
EventDataDescCreate(&Descriptors[6], &tickCount, sizeof(DWORD)); // <data name = "TickCount" inType = "win:UInt32" / >
EventDataDescCreate(&Descriptors[7], (PDWORD)&gti.hwndFocus, sizeof(DWORD)); // <data name = "FocusHWND" inType = "win:UInt32" / >
EventDataDescCreate(&Descriptors[8], (PDWORD)&activeHKL, sizeof(DWORD)); // <data name = "ActiveHKL" inType = "win:UInt32" / >
EventDataDescCreate(&Descriptors[9], fileW, (ULONG)(wcslen(fileW) + 1) * sizeof(WCHAR)); // <data name = "SourceFile" inType = "win:UnicodeString" / >
EventDataDescCreate(&Descriptors[9], file, (ULONG)(wcslen(file) + 1) * sizeof(WCHAR)); // <data name = "SourceFile" inType = "win:UnicodeString" / >
EventDataDescCreate(&Descriptors[10], (PDWORD)&line, sizeof(DWORD)); // <data name = "SourceLine" inType = "win:UInt32" / >
EventDataDescCreate(&Descriptors[11], msg, (ULONG)(wcslen(msg) + 1) * sizeof(WCHAR)); // <data name = "Message" inType = "win:UnicodeString" / >
@ -124,6 +132,5 @@ extern "C" void _declspec(dllexport) WINAPI Keyman_WriteDebugEvent(char *file, i
OutputDebugString("Keyman k32_dbg: Failed to call EventWrite");
}
delete fileW;
}
}

View file

@ -137,7 +137,7 @@ BOOL ShouldDebug_1() {
return Globals::get_debug_KeymanLog();
}
int SendDebugMessageFormat_1(HWND hwnd, TSDMState state, int kmn_lineno, char *file, int line, char *fmt, ...)
int SendDebugMessageFormat_1(HWND hwnd, TSDMState state, int kmn_lineno, wchar_t*file, int line, char *fmt, ...)
{
char fmtbuf[256];
@ -150,6 +150,19 @@ int SendDebugMessageFormat_1(HWND hwnd, TSDMState state, int kmn_lineno, char *f
return 0;
}
int SendDebugMessageFormatW_1(HWND hwnd, TSDMState state, int kmn_lineno, wchar_t* file, int line, wchar_t* fmt, ...)
{
wchar_t fmtbuf[256];
va_list vars;
va_start(vars, fmt);
_vsnwprintf_s(fmtbuf, _countof(fmtbuf), _TRUNCATE, fmt, vars); // I2248 // I3547
fmtbuf[255] = 0;
SendDebugMessageW_1(hwnd, state, kmn_lineno, file, line, fmtbuf);
return 0;
}
/*void FillWindowInfo(HWND hwnd, char *sClassName, char *sWindowText)
{
if(hwnd == 0 || !GetClassName(hwnd, sClassName, 32))
@ -169,7 +182,18 @@ int SendDebugMessageFormat_1(HWND hwnd, TSDMState state, int kmn_lineno, char *f
}*/
int SendDebugMessage_1(HWND hwnd, TSDMState state, int kmn_lineno, char *file, int line, char *msg)
int SendDebugMessageW_1(HWND hwnd, TSDMState state, int kmn_lineno, wchar_t*file, int line, wchar_t* msg)
{
UNREFERENCED_PARAMETER(hwnd);
UNREFERENCED_PARAMETER(state); // I3569
UNREFERENCED_PARAMETER(kmn_lineno);
Keyman_WriteDebugEventW(file, line, msg);
return 0;
}
int SendDebugMessage_1(HWND hwnd, TSDMState state, int kmn_lineno, wchar_t*file, int line, char *msg)
{
UNREFERENCED_PARAMETER(hwnd);
UNREFERENCED_PARAMETER(state); // I3569
@ -177,8 +201,8 @@ int SendDebugMessage_1(HWND hwnd, TSDMState state, int kmn_lineno, char *file, i
// TODO: convert debugging to Unicode
PWSTR msgW = strtowstr(msg);
Keyman_WriteDebugEvent(file, line, msgW);
delete msgW;
Keyman_WriteDebugEventW(file, line, msgW);
delete [] msgW;
return 0;
}
@ -264,7 +288,7 @@ BOOL DebugSignalPause(BOOL fIsUp)
return FALSE;
}
void DebugLastError_1(DWORD err, char *context, char *file, int line, char *func)
void DebugLastError_1(DWORD err, char *context, wchar_t *file, int line, char *func)
{
if(ShouldDebug(sdmDebug))
{
@ -308,7 +332,7 @@ char *Debug_UnicodeString(PWSTR s, int x) {
return bufout[x];
}
BOOL DebugAssert_1(BOOL condition, char *message, char *file, int line)
BOOL DebugAssert_1(BOOL condition, char *message, wchar_t *file, int line)
{
if (!(condition)) {
SendDebugMessage_1(0, sdmGlobal, 0, file, line, message);

View file

@ -33,6 +33,7 @@ EXPORTS
Keyman_ResetInitialisation
Keyman_WriteDebugEvent
Keyman_WriteDebugEventW
Keyman_UpdateTouchPanelVisibility

View file

@ -158,24 +158,35 @@ void InitDebugging();
void UninitDebugging();
extern "C" void _declspec(dllexport) WINAPI Keyman_WriteDebugEvent(char* file, int line, PWCHAR msg);
extern "C" void _declspec(dllexport) WINAPI Keyman_WriteDebugEventW(PWCHAR file, int line, PWCHAR msg);
#define SendDebugMessage(hwnd,state,kmn_lineno,msg) (ShouldDebug((state)) ? SendDebugMessage_1((hwnd),(state),(kmn_lineno), __FILE__, __LINE__, (msg)) : 0)
#define SendDebugMessageFormat(hwnd,state,kmn_lineno,msg,...) (ShouldDebug((state)) ? SendDebugMessageFormat_1((hwnd),(state),(kmn_lineno), __FILE__, __LINE__, (msg),__VA_ARGS__) : 0)
// Following macros widen a constant string, ugly it is true
#define __WFILE2__(m) L ## m
#define __WFILE1__(m) __WFILE2__(m)
#define __WFILE__ __WFILE1__(__FILE__)
#define SendDebugMessageW(hwnd,state,kmn_lineno,msg) (ShouldDebug((state)) ? SendDebugMessageW_1((hwnd),(state),(kmn_lineno), __WFILE__, __LINE__, (msg)) : 0)
#define SendDebugMessageFormatW(hwnd,state,kmn_lineno,msg,...) (ShouldDebug((state)) ? SendDebugMessageFormatW_1((hwnd),(state),(kmn_lineno), __WFILE__, __LINE__, (msg),__VA_ARGS__) : 0)
#define SendDebugMessage(hwnd,state,kmn_lineno,msg) (ShouldDebug((state)) ? SendDebugMessage_1((hwnd),(state),(kmn_lineno), __WFILE__, __LINE__, (msg)) : 0)
#define SendDebugMessageFormat(hwnd,state,kmn_lineno,msg,...) (ShouldDebug((state)) ? SendDebugMessageFormat_1((hwnd),(state),(kmn_lineno), __WFILE__, __LINE__, (msg),__VA_ARGS__) : 0)
#define ShouldDebug(state) ShouldDebug_1()
#define DebugLastError(context) (DebugLastError_1(GetLastError(), (context), __FILE__,__LINE__,__FUNCTION__))
#define DebugLastError0(error, context) (DebugLastError_1((error), (context), __FILE__,__LINE__,__FUNCTION__))
#define DebugLastError(context) (DebugLastError_1(GetLastError(), (context), __WFILE__, __LINE__,__FUNCTION__))
#define DebugLastError0(error, context) (DebugLastError_1((error), (context), __WFILE__, __LINE__,__FUNCTION__))
// On failed condition log "message", return FALSE
// and assert if a debugger is attached for a debug build.
#define DebugAssert(condition, message) (DebugAssert_1((condition),(message), __FILE__, __LINE__))
int SendDebugMessage_1(HWND hwnd, TSDMState state, int kmn_lineno, char* file, int line, char* msg);
int SendDebugMessageFormat_1(HWND hwnd, TSDMState state, int kmn_lineno, char* file, int line, char* fmt, ...);
void DebugLastError_1(DWORD err, char* context, char* file, int line, char* func);
#define DebugAssert(condition, message) (DebugAssert_1((condition),(message), __WFILE__, __LINE__))
int SendDebugMessage_1(HWND hwnd, TSDMState state, int kmn_lineno, wchar_t* file, int line, char* msg);
int SendDebugMessageFormat_1(HWND hwnd, TSDMState state, int kmn_lineno, wchar_t* file, int line, char* fmt, ...);
int SendDebugMessageW_1(HWND hwnd, TSDMState state, int kmn_lineno, wchar_t* file, int line, wchar_t* msg);
int SendDebugMessageFormatW_1(HWND hwnd, TSDMState state, int kmn_lineno, wchar_t* file, int line, wchar_t* fmt, ...);
void DebugLastError_1(DWORD err, char* context, wchar_t* file, int line, char* func);
void DebugMessage(LPMSG msg, WPARAM wParam);
void DebugShift(char* function, char* point);
BOOL DebugSignalPause(BOOL fIsUp);
char* Debug_VirtualKey(WORD vk);
char* Debug_UnicodeString(PWSTR s, int x = 0);
BOOL DebugAssert_1(BOOL condition, char* msg, char* file, int line);
BOOL DebugAssert_1(BOOL condition, char* msg, wchar_t* file, int line);
BOOL ShouldDebug_1(); // TSDMState state);
#endif

View file

@ -1,18 +1,18 @@
/*
Name: K32_DBG
Copyright: Copyright (C) SIL International.
Documentation:
Description:
Documentation:
Description:
Create Date: 14 Sep 2006
Modified Date: 23 Feb 2016
Authors: mcdurdin
Related Files:
Dependencies:
Related Files:
Dependencies:
Bugs:
Todo:
Notes:
Bugs:
Todo:
Notes:
History: 14 Sep 2006 - mcdurdin - Rework internal debugging to use mailslot passing to Keyman
05 Dec 2006 - mcdurdin - Disable temporary file-based logging
15 Jan 2007 - mcdurdin - Use _FILELOG define
@ -85,7 +85,7 @@ void InitDebugging() {
}
}
int SendDebugMessageFormat_1(char *file, int line, PWCHAR fmt, ...) {
int SendDebugMessageFormat_1(wchar_t *file, int line, PWCHAR fmt, ...) {
if (ShouldDebug()) {
WCHAR fmtbuf[256];
@ -100,14 +100,14 @@ int SendDebugMessageFormat_1(char *file, int line, PWCHAR fmt, ...) {
return 0;
}
int SendDebugMessage_1(char *file, int line, PWCHAR msg) {
int SendDebugMessage_1(wchar_t *file, int line, PWCHAR msg) {
if (ShouldDebug()) {
Keyman32Interface::WriteDebugEvent(file, line, msg);
}
return 0;
}
void DebugLastError_1(char *file, int line, char *func, PWCHAR msg, DWORD err) {
void DebugLastError_1(wchar_t *file, int line, char *func, PWCHAR msg, DWORD err) {
if(ShouldDebug()) {
WCHAR buf[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, err, 0, buf, _countof(buf), NULL);
@ -121,7 +121,7 @@ void WINAPI Keyman_Diagnostic(int mode) {
}
}
BOOL _LogSUCCEEDED(char *file, int line, PWSTR caller, PSTR callee, HRESULT hr) {
BOOL _LogSUCCEEDED(wchar_t *file, int line, PWSTR caller, PSTR callee, HRESULT hr) {
BOOL result = SUCCEEDED(hr);
if (!result) {
SendDebugMessageFormat_1(file, line, L"CKMTipTextService::Log: call in %s to %hs failed with %x", caller, callee, hr);

View file

@ -52,24 +52,29 @@ void GetDeadkeyFlags(TfEditCookie ec, ITfContext *pContext, PWSTR buf, int n);
// Logging functions
//
// Following macros widen a constant string, ugly it is true
#define __WFILE2__(m) L ## m
#define __WFILE1__(m) __WFILE2__(m)
#define __WFILE__ __WFILE1__(__FILE__)
void Log(WCHAR *fmt, ...);
BOOL ShouldDebug();
int SendDebugMessage_1(char *file, int line, PWCHAR msg); // I4379
int SendDebugMessageFormat_1(char *file, int line, PWCHAR fmt, ...); // I4379
void DebugLastError_1(char *file, int line, char *func, PWCHAR msg, DWORD err);
int SendDebugMessage_1(wchar_t *file, int line, PWCHAR msg); // I4379
int SendDebugMessageFormat_1(wchar_t *file, int line, PWCHAR fmt, ...); // I4379
void DebugLastError_1(wchar_t *file, int line, char *func, PWCHAR msg, DWORD err);
#define SendDebugMessage(msg) (SendDebugMessage_1(__FILE__, __LINE__, (msg)))
#define SendDebugMessageFormat(msg,...) (SendDebugMessageFormat_1(__FILE__, __LINE__, (msg),__VA_ARGS__))
#define SendDebugMessage(msg) (SendDebugMessage_1(__WFILE__, __LINE__, (msg)))
#define SendDebugMessageFormat(msg,...) (SendDebugMessageFormat_1(__WFILE__, __LINE__, (msg),__VA_ARGS__))
#define DebugLastError(msg) (DebugLastError_1(__FILE__,__LINE__,__FUNCTION__,(msg),GetLastError()))
#define DebugLastError0(msg,err) (DebugLastError_1(__FILE__,__LINE__,__FUNCTION__,(msg),(err)))
#define DebugLastError(msg) (DebugLastError_1(__WFILE__,__LINE__,__FUNCTION__,(msg),GetLastError()))
#define DebugLastError0(msg,err) (DebugLastError_1(__WFILE__,__LINE__,__FUNCTION__,(msg),(err)))
#define LogSUCCEEDED(hr) _LogSUCCEEDED(__FILE__, __LINE__, __FUNCTIONW__, (#hr), (hr))
BOOL _LogSUCCEEDED(char *file, int line, PWSTR caller, PSTR callee, HRESULT hr);
#define LogSUCCEEDED(hr) _LogSUCCEEDED(__WFILE__, __LINE__, __FUNCTIONW__, (#hr), (hr))
BOOL _LogSUCCEEDED(wchar_t *file, int line, PWSTR caller, PSTR callee, HRESULT hr);
//#define LogEnter() (SendDebugMessageFormat_1(__FILE__, __LINE__, L"%hs ENTER", __FUNCTION__))
//#define LogExit() (SendDebugMessageFormat_1(__FILE__, __LINE__, L"%hs EXIT", __FUNCTION__))
//#define LogEnter() (SendDebugMessageFormat_1(__WFILE__, __LINE__, L"%hs ENTER", __FUNCTION__))
//#define LogExit() (SendDebugMessageFormat_1(__WFILE__, __LINE__, L"%hs EXIT", __FUNCTION__))
#define LogEnter()
#define LogExit()

View file

@ -2,7 +2,7 @@
#include "kmtip.h"
extern "C" {
BOOL WINAPI Keyman_WriteDebugEvent(char *file, int line, PWCHAR msg);
BOOL WINAPI Keyman_WriteDebugEventW(PWCHAR file, int line, PWCHAR msg);
BOOL WINAPI TIPActivateEx(BOOL fActivate);
BOOL WINAPI TIPActivateKeyboard(GUID *profile);
@ -15,8 +15,8 @@ extern "C" {
BOOL WINAPI TIPIsKeymanRunning();
};
void Keyman32Interface::WriteDebugEvent(char *file, int line, PWCHAR msg) {
::Keyman_WriteDebugEvent(file, line, msg);
void Keyman32Interface::WriteDebugEvent(PWCHAR file, int line, PWCHAR msg) {
::Keyman_WriteDebugEventW(file, line, msg);
// Don't DebugLastError here because it depends on WriteDebugEvent...
}

View file

@ -143,7 +143,7 @@ typedef HRESULT(WINAPI *PKEYMANGETCONTEXTFUNC)(int n, PWSTR buf); // I3567
class Keyman32Interface {
public:
static void WriteDebugEvent(char *file, int line, PWCHAR msg);
static void WriteDebugEvent(PWCHAR file, int line, PWCHAR msg);
static BOOL TIPActivateEx(BOOL fActivate);
static BOOL TIPActivateKeyboard(GUID *profile);