Dienstag, 24. Juli 2018

WinCC MessageBox durch Windows MessageBoxExW ersetzen

Im WinCC ODK gibt es eine Funktion zum Aufruf der Windows MessageBox. Diese WinCC Funktion ruft die Windows API Funktion MessageBoxA (der letzte Buchstabe ist wichtig) auf. Solange die Texte in der aktuellen System Codepage ausgegeben werden sollen, funktioniert alles korrekt. Wenn aber die Texte mit der aktuelle System Codepage nicht dargestellt werden können, ist die Anzeige falsch.


Chinesische Mehrbytekodierung auf einem deutschen Windows System


Was tun?


WinCC ist ab Version 7.2 weitgehend auf Unicode umgestellt, nur die C Scripte können kein Unicode. Idee: Wenn die Windows API Funktion MessageBox für Unicode aufgerufen wird und vorher die Texte nach Unicode konvertiert wurden, sollte die Anzeige gelingen.

Gesagt, getan!


Alle Texte, die in den C Scripten ankommen, werden von WinCC in die Mehrbytekodierung der eingestellten Codepage konvertiert, also müssen diese wieder nach Unicode konvertiert werden. Die Windows API Funktion MultiByteToWideChar erledigt dies, wenn die richtigen Parameter verwendet werden. Die Codepage für das C Script sollte auf "Dynamisch" stehen. Es muss weiterhin daran gedacht werden, beide Texte, also Caption und Text zu konvertieren. Anschließend zeigt die MessageBoxExW den Text korrekt an.

Chinesischer Text in Messagebox, nur auf den Buttons stehen noch deutsche Beschriftungen

Die Texte der Kopfzeile und der Anzeigetext sind jetzt Chinesisch, aber die Buttons zeigen noch die deutsche Beschriftung. Die Texte der Buttons stammen vom Windows Betriebssystem. Wenn in Windows auch die Chinesische Sprache als Anzeigesprache (Display language) installiert ist, werden auch die korrekten Beschriftungen der Buttons angezeigt. Dies wird gesteuert über den letzten Parameter der API Funktion MessageBoxExW.  Diese lässt als letzten Parameter die LocalID als Sprache für die Buttons zu. Chinesisch muss nicht als Display language ausgewählt sein.

Chinesischer Text in Messagebox mit chinesischen Buttons

Chinesisch als Display language installiert


Deutscher Text in Messagebox

Code Beispiel


Der folgende Code kann als Global C Script in WinCC hinzugefügt werden. Dann kann an allen Stellen, an denen MessageBox auf gerufen wird, der Aufruf durch MessageBoxLocale ersetzt werden. Wichtig ist, dass die Codepage der C Scripte auf "Dynamisch" gestellt ist.

int MessageBoxLocale(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{

#pragma code ("kernel32.dll")
#define CP_ACP 0
int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR
lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int
cchWideChar);
#pragma code()


#pragma code ("User32.dll")
int MessageBoxExW(
  HWND    hWnd,
  LPCWSTR lpText,
  LPCWSTR lpCaption,
  UINT    uType,
  WORD    wLanguageId
);
#pragma code()


static short int lpWideCharStrHeader[300];
static short int lpWideCharStrText[300];
int sizeInChars;
int ret;
int result = 0;

UINT LocalID = GetLanguage();
// Western Europe
UINT uCodepage = 1252;

// Japanese
if (LocalID == 0x411) {
      uCodepage = 932; 
      }
// Chinese
if (LocalID == 0x0804) {
      uCodepage = 936;
      }

ret = MultiByteToWideChar(uCodepage,(DWORD)0, lpCaption,-1, (LPWSTR)lpWideCharStrHeader,300);

ret = MultiByteToWideChar(uCodepage,(DWORD)0, lpText,-1, (LPWSTR)lpWideCharStrText,300);

result = MessageBoxExW(hWnd,(LPWSTR)lpWideCharStrText,(LPWSTR)lpWideCharStrHeader, uType, (WORD)LocalID);

return result;
}