Windows skipping language-specific resources [duplicate] - winapi

This question already has answers here:
LoadString works only if I don't have an English string table
(3 answers)
Closed 9 years ago.
I'm playing around with the Windows API, and I'm trying to use multilingual resources to load language-specific menus and stuff. However, for some reason, Windows absolutely refuses to load Bosnian (Latin) resources if there are US English alternatives. Loading resources via FindResourceEx works. I'm on XP SP3 and Bosnian (Latin) is set in my regional settings.
main.c
#include <Windows.h>
#include "resource.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PTSTR pCmdLine, int nCmdShow)
{
TCHAR string[64];
/* Message box properly outputs "This is German (DE)." here. */
SetThreadLocale(MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT));
LoadString(hInstance, TEST_STRING, string, sizeof(string)/sizeof(string[0]));
MessageBox(NULL, string, TEXT("Message"), MB_OK);
/* Message box outputs "This is English (US)." - WTF?! */
SetThreadLocale(MAKELCID(MAKELANGID(LANG_BOSNIAN, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN), SORT_DEFAULT));
LoadString(hInstance, TEST_STRING, string, sizeof(string)/sizeof(string[0]));
MessageBox(NULL, string, TEXT("Message"), MB_OK);
return 0;
}
resources.rc
#include <windows.h>
#include "resource.h"
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
STRINGTABLE
{
TEST_STRING "This is English (US)."
}
LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
STRINGTABLE
{
TEST_STRING "This is German (DE)."
}
LANGUAGE LANG_BOSNIAN, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN
STRINGTABLE
{
TEST_STRING "This is Bosnian (Latin)."
}
LANGUAGE LANG_FRENCH, SUBLANG_FRENCH
STRINGTABLE
{
TEST_STRING "This is French (FR)."
}
resource.h
#define TEST_STRING 40000

The language selection mechanism in LoadString (and in general all resource retrieving APIs) was broken starting with Vista (because of the MUI mechanism addition at system level).
The best current practice is to store each language in a separate resource only dll and you access the resources using the DLL's hInstance. And you can and either load the dll yourself, or use the newer MUI API to do that (http://msdn.microsoft.com/library/dd319076%28VS.85%29.aspx)

Related

C++ Messagebox in Chinese [duplicate]

This question already has answers here:
Why does my simple C++ GUI application show a message box in Chinese?
(3 answers)
Why does message box in C++ show chinese message [duplicate]
(3 answers)
Closed 6 years ago.
ConsoleApplication.cpp
// ConsoleApplication2.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
int main()
{
std::cout << "Hello World" << std::endl;
MessageBox(0, LPTSTR("Text Here"), LPTSTR("Text Here"), MB_OK);
std::cin.clear();
std::cout << "Press Enter to continue" << std::endl;
std::cin.ignore(32767, '\n');
std::cin.get();
return 0;
}
stdafx.h
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <Windows.h>
#include <sstream>
Whenever I run the MessageBox code, it comes out in Chinese characters.
The code is above.
Your LPTSTR type-cast is wrong. When compiling with UNICODE defined, MessageBox() resolves to MessageBoxW(), and LPTSTR resolves to wchar*, so you are really doing this:
MessageBoxW(0, (wchar*)"Text Here", (wchar*)"Text Here", MB_OK);
You are telling the compiler to type-cast narrow strings as if they were wide strings. The narrow string "Text Here" consists of bytes 54 65 78 74 20 48 65 72 65. When those same bytes are interpreted as a wide string, they produce the Chinese string "敔瑸䠠牥e".
If you are going to use TCHAR-based APIs, like MessageBox(), you need to use the TEXT() macro when passing char/string literals to them at compile-time, eg:
MessageBox(0, TEXT("Text Here"), TEXT("Text Here"), MB_OK);
When UNICODE is defined, TEXT() compiles a literal as wide. When UNICODE is not defined, TEXT() compiles a literal as narrow.
Otherwise, do not rely on TCHAR-based APIs at all. Use Ansi/Unicode versions explicitly, eg:
MessageBoxA(0, "Text Here", "Text Here", MB_OK);
MessageBoxW(0, L"Text Here", L"Text Here", MB_OK);
On a side note: your call to cin.ignore() should use std::numeric_limits instead of hard-coding the length:
#include <limits>
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

Why winmain parameters doesn't match to each other?

Why QApp constructor fails with WinMain parameters?
int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPTSTR _lpCmdLine, int _nShowCmd) {
QApplication app(_nShowCmd, & _lpCmdLine);
And here it fail with exception:
Exception at adress 0x0F3621DC (Qt5Guid.dll) in updater_app.exe: 0xC0000005
Whats wrong? how to fix it?
UPD:
And it works in such way:
int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPTSTR _lpCmdLine, int _nShowCmd) {
int nShowCmd(0);
QApplication app(nShowCmd, & _lpCmdLine);
_lpCmdLine is 10 and _nShowCmd is empty string - so it doesn't match. Why?
The Qt application QApplication main object supposed to be created in the standard main function:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// more app objects initialization
return app.exec();
}
and you do:
int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPTSTR _lpCmdLine, int _nShowCmd)
{
QApplication app(nShowCmd, & _lpCmdLine);
return app.exec();
}
Which implies that &_lpCdLine being equivalent to argv but:
LPTSTR _lpCmdLine which is an equivalent to char* and you take an address of it so &_lpCmdLine matches char** when _lpCmdLine is pointing to a contiguous buffer of characters and not an array of character strings as argv.
It makes sense to consider how main() function is implemented on Windows. There is a good discussion: WINMAIN and main() in C++ (Extended) Mind that the C runtime must be initialized before main() function runs and that may depend on compiler/linker. And also find an example of Qt application main function.
I guess that the case when you make your code not to crash by introducingn nShowCmd == 0 makes QApplication object not to read the command line which prevents an incorrect access via random content interpreted as addresses in _lpCmdLine. But that is still wrong and an incomplete intitialization of QApplication object.
The authors fails to see the window and sees the console instead and that relates to incomplete code of main function not launching any window. Also, QML application main.cpp might help.
Since this problem becomes relevant again with Qt6, here is a very simple solution for VisualStudio with using WinMain as entry point:
QApplication app(__argc, __argv);
__argc and __argv are populated by the microsoft compiler
(found this suggestion here: https://codingmisadventures.wordpress.com/2009/03/10/retrieving-command-line-parameters-from-winmain-in-win32/)
Short explanation of the problem: using main() with VC requires to use Subsystem:Console, but this always opens a console window, which you wanna avoid usually. You cannot get rid of this console, except with some very dirty hacks. So you need to switch to Subsystem:Windows to have a "silent" application launch, but this requires to use WinMain() as application entry point. Up to Qt5 there was an own implementation of WinMain() in qtmain.lib, which you simply linked in, and which forwards to the main()-function, but this has been kicked out in Qt6. The problem exists afaik only for MSVC users, because with mingw you can disable the console window and continue using main(), as shown in the Qt-examples.

Make a exported function ansi and unicode aware in win32 dll with the use of TCHAR

I'm trying to make a win32 dll that are able to handle ansi and unicode depending what specify in the character set on properties. Unicode or Not Set. ANSI when building in Visual Studio.
The dll has the definition
extern "C" int __stdcall calc(TCHAR *foo)
The definition file is as follow
typedef int (CALLBACK* LPFNDLLCALC)( TCHAR *foo)
Inside the MFC Calling app i load the dll as this
HINSTANCE DllFoo = LoadLibrary(L"foo.dll");
LPFNDLLCALC lpfnDllcalc = (LPFNDLLCALC)GetProcAddress(DllFoo ,"calc");
CString C_SerialNumber;
mvSerialNumber.GetWindowText(C_SerialNumber);
TCHAR* SerialNumber = C_SerialNumber.GetBuffer(0);
LPFNDLLCALC(SerialNumber);
I understand that i make something wrong in the C_SerialNumber.GetBuffer(0) to the TCHAR* pointer. Because in the debugger in the dll only show the first char is passed to the dll. Not the complete string.
How do i get CString to pointer that work in both ansi and unicode.
If change all my code to wchar_t or char in stead of TCHAR i get it to work. Put not with this nativ TCHAR macro.
As I see it you have two options:
Write the code entirely using TCHAR. Then compile the code into two separate DLLs, one narrow and one wide.
Have a single DLL that exports two variants of each function that operates on text. This is how the Windows API is implemented.
If you choose the second option, you don't need to implement each function twice. The primary function is the wide variant. For the narrow variant you convert the input from narrow to wide and then call the wide version. Vice versa for output text. In other words, you use the adapter pattern.
I suppose that you are imagining a third option where you have a single function that can operate on either form of text. Don't go this way. This way abandons type safety and will give you no end of pain. It will also be counter to user's expectations.
As David said, you need to export two separate functions, one for Ansi and one for Unicode, just like the Win32 API does, eg:
#ifdef __cplusplus
extern "C" {
#endif
int WINAPI calcA(LPCSTR foo);
int WINAPI calcW(LPCWSTR foo);
#ifdef __cplusplus
}
#endif
typedef int (WINAPI *LPFNDLLCALC)(LPCTSTR foo);
Then you can do the following:
int WINAPI calcA(LPCSTR foo)
{
return calcW(CStringW(foo));
}
int WINAPI calcW(LPCWSTR foo)
{
//...
}
HINSTANCE DllFoo = LoadLibrary(L"foo.dll");
LPFNDLLCALC lpfnDllcalc = (LPFNDLLCALC) GetProcAddress(DllFoo,
#ifdef UNICODE
"calcW"
#else
"calcA"
#endif
);
CString C_SerialNumber;
mvSerialNumber.GetWindowText(C_SerialNumber);
lpfnDllcalc(C_SerialNumber);

Best way to have crash dumps generated when processes crash?

In Windows environments (XP and Win 7):
What is the best way to automatically have a crash dump generated when processes crash on the system?
Can an installer (MSI) package do this?
One of the best way to have an automatic dump for any/specific process on Windows is to configure a set of entries in the registry. I tried the below on Windows 7 64 bit.
Open notepad.exe, paste the below entry and save it as "EnableDump.reg". You can give any name you wish.
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps]
"DumpFolder"=hex(2):44,00,3a,00,5c,00,64,00,75,00,6d,00,70,00,00,00
"DumpCount"=dword:00000010
"DumpType"=dword:00000002
"CustomDumpFlags"=dword:00000000
Double click the "EnableDump.reg" and select 'Yes'. I have given the dump folder as 'd:\dump'. You can change it to whatever folder you wish.
Try to execute a crashing application, Windows will display the error dialog. Choose 'Close the Program' option. After that you will see the dump in the configured folder. The name of the dump file will be .exe..dmp.
For more details, you can refer the below link.
http://msdn.microsoft.com/en-us/library/bb787181(VS.85).aspx
Below explanation is based on another answer, but the logic is mine (without attribution need, as said on my profile);
Having your own dump generation framework which automatically creates a process dump when any Unhandled exception is encountered, would avoid clients having to install WinDbg.
At the application start up use SetUnhandledExceptionFilter(...) Win32 API to register a callback (i.e. application level exception-handler).
Now the registered callback function is called whenever there is any exception which is not handled. You may then create the process dump using MiniDumpWriteDump(...) API from DbgHelp.dll.
C++ Sample (unicode-enabled)
header-file
#ifndef CRASH_REPORTER_H
#define CRASH_REPORTER_H
//Exclude rarely used content from the Windows headers.
#ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# undef WIN32_LEAN_AND_MEAN
#else
# include <windows.h>
#endif
#include <tchar.h>
#include <DbgHelp.h>
class CrashReporter {
public:
inline CrashReporter() { Register(); }
inline ~CrashReporter() { Unregister(); }
inline static void Register() {
if(m_lastExceptionFilter != NULL) {
fprintf(stdout, "CrashReporter: is already registered\n");
fflush(stdout);
}
SetErrorMode(SEM_FAILCRITICALERRORS);
//ensures UnHandledExceptionFilter is called before App dies.
m_lastExceptionFilter = SetUnhandledExceptionFilter(UnHandledExceptionFilter);
}
inline static void Unregister() {
SetUnhandledExceptionFilter(m_lastExceptionFilter);
}
private:
static LPTOP_LEVEL_EXCEPTION_FILTER m_lastExceptionFilter;
static LONG WINAPI UnHandledExceptionFilter(_EXCEPTION_POINTERS *);
};
#endif // CRASH_REPORTER_H
source-file
#include "crash-report.h"
#include <stdio.h>
LPTOP_LEVEL_EXCEPTION_FILTER CrashReporter::m_lastExceptionFilter = NULL;
typedef BOOL (WINAPI *MiniDumpWriteDumpFunc)(HANDLE hProcess, DWORD ProcessId
, HANDLE hFile
, MINIDUMP_TYPE DumpType
, const MINIDUMP_EXCEPTION_INFORMATION *ExceptionInfo
, const MINIDUMP_USER_STREAM_INFORMATION *UserStreamInfo
, const MINIDUMP_CALLBACK_INFORMATION *Callback
);
LONG WINAPI CrashReporter::UnHandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtr)
{
//we load DbgHelp.dll dynamically, to support Windows 2000
HMODULE hModule = ::LoadLibraryA("DbgHelp.dll");
if (hModule) {
MiniDumpWriteDumpFunc dumpFunc = reinterpret_cast<MiniDumpWriteDumpFunc>(
::GetProcAddress(hModule, "MiniDumpWriteDump")
);
if (dumpFunc) {
//fetch system time for dump-file name
SYSTEMTIME SystemTime;
::GetLocalTime(&SystemTime);
//choose proper path for dump-file
wchar_t dumpFilePath[MAX_PATH] = {0};
_snwprintf_s(dumpFilePath, MAX_PATH, L"crash_%04d-%d-%02d_%d-%02d-%02d.dmp"
, SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay
, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond
);
//create and open the dump-file
HANDLE hFile = ::CreateFileW( dumpFilePath, GENERIC_WRITE
, FILE_SHARE_WRITE
, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_HIDDEN
, NULL
);
if (hFile != INVALID_HANDLE_VALUE) {
_MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;
exceptionInfo.ThreadId = GetCurrentThreadId();
exceptionInfo.ExceptionPointers = exceptionPtr;
exceptionInfo.ClientPointers = NULL;
//at last write crash-dump to file
bool ok = dumpFunc(::GetCurrentProcess(), ::GetCurrentProcessId()
, hFile, MiniDumpNormal
, &exceptionInfo, NULL, NULL
);
//dump-data is written, and we can close the file
CloseHandle(hFile);
if (ok) {
//Return from UnhandledExceptionFilter and execute the associated exception handler.
// This usually results in process termination.
return EXCEPTION_EXECUTE_HANDLER;
}
}
}
}
//Proceed with normal execution of UnhandledExceptionFilter.
// That means obeying the SetErrorMode flags,
// or invoking the Application Error pop-up message box.
return EXCEPTION_CONTINUE_SEARCH;
}
usage
#include "3rdParty/crash-report.h"
int main(int argc, char *argv[])
{
CrashReporter crashReporter;
(void)crashReporter; //prevents unused warnings
// [application main loop should be here]
return 0;
}
Windows XP:
The following steps enable automatic crash dumps:
1) Open a command prompt, running as administrator
2) Run drwtsn32 -i. This will install Doctor Watson as the default debugger when something crashes
3) Click Ok
4) From the command prompt, run drwtsn32
5) Set the Crash Dump path to your favorite directory, or leave the default.
6) Set the Crash Dump Type to mini. Note that under some circumstances, we may ask you for a full crash dump.
7) Make sure the Dump All Thread Contexts and Create Crash Dump File options are selected.
8) Click Ok
9) If a user.dmp file already exists in the Crash Dump path, delete it.
Windows 7: Location is:
C:\Users[Current User when app crashed]\AppData\Local\Microsoft\Windows\WER\ReportArchive

Documentation for writting your own dll for Rundll32.exe? [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
How to use Rundll32 to execute DLL Function?
Where can I find documentation (tutorials, books, etc.) to write my own dll's that can be run with rundll32.exe?
Here is the most basic Hello World sample I could come up with that will work with rundll.exe. Please follow along these steps:
Start a fresh WIN32 DLL project in Visual Studio (I used VS2010)
In dlllmain.cpp add:
// this shoud ideally go into the .h file I believe
__declspec( dllexport ) void CALLBACK EntryPoint(
HWND hwnd,
HINSTANCE hinst,
LPSTR lpszCmdLine,
int nCmdShow);
// our hello world function
void CALLBACK EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
int msgboxID = MessageBox(
NULL,
L"Hello World from Run32dll",
L"Hello World",
MB_ICONWARNING | MB_CANCELTRYCONTINUE | MB_DEFBUTTON2
);
switch (msgboxID)
{
case IDCANCEL:
// TODO: add code
break;
case IDTRYAGAIN:
// TODO: add code
break;
case IDCONTINUE:
// TODO: add code
break;
}
}
Add a module.def file to your project and edit the following snippet in it:
LIBRARY YourDll
EXPORTS
EntryPoint
Compile and then test from the commandline with
rundll32 YourDll.dll,EntryPoint
You should be greeted with a MessageBox with three buttons
I used the following url's to overcome C++ issues and EntryPoint not found in the early stages of my effort:
Rundll from user mricicle
How messagebox works
DependencyWalker
Exporting functions
Exporting with .def file
String literals

Resources