expertenaustausch > comp.os.* > comp.os.ms-windows.programmer

Matthias Hanft (04.03.2020, 22:22)
Hallo,

es gibt in den unergründlichen Tiefen von Windows (10) eine
Einstellung namens "Aktuelles Gebietsschema" (unter "Sprache
für nicht Unicode-kompatible Programme"). Ich meine die
Einstellung bei "7." im Screenshot auf


Ich würde diese Einstellung gerne programmgesteuert auslesen
bzw. setzen. Weiß zufällig jemand, wie die entsprechende
Windows-Funktion dafür heißt (und ggf. in welcher DLL sie
steht)?

Im MSDN danach zu googeln ist schwierig, wenn man nicht
weiß, wie "Gebietsschema" in Microsoft-Englisch heißt.

Stimmt es, dass man nach dem Ändern dieser Einstellung
den Rechner neu starten (oder zumindest den User reloggen)
muss?

Danke & Gruß Matthias.
Christoph Schneegans (05.03.2020, 03:46)
Matthias Hanft schrieb:

> es gibt in den unergründlichen Tiefen von Windows (10) eine
> Einstellung namens "Aktuelles Gebietsschema" (unter "Sprache
> für nicht Unicode-kompatible Programme"). (?) Ich würde diese
> Einstellung gerne programmgesteuert auslesen bzw. setzen.


In PowerShell gibt es dafür die Cmdlets Get-WinSystemLocale und
Set-WinSystemLocale.
Matthias Hanft (05.03.2020, 10:50)
Christoph Schneegans schrieb:
> In PowerShell gibt es dafür die Cmdlets Get-WinSystemLocale und
> Set-WinSystemLocale.


Danke. Ich hab zwar eher sowas hier gesucht:

aber mit dem Zauberwort "system locale" (und dann weiter "thread
locale" und "user localw") habe ich gefunden, was ich gesucht habe.

Gruß Matthias.
Matthias Hanft (05.03.2020, 19:19)
Ich schrieb:
> Danke. Ich hab zwar eher sowas hier gesucht:
>
> aber mit dem Zauberwort "system locale" (und dann weiter "thread
> locale" und "user localw") habe ich gefunden, was ich gesucht habe.


Also mit dem obigen Get{System|User}DefaultLocale kriege ich ordnungs-
gemäß "de-DE" zurück - das ist wohl tatsächlich der Inhalt des Kästchens
"Aktuelles Gebietsschema" bei Punkt Nr. 7 in der Abbildung auf
(auch wenn ich noch
keine Tabelle gefunden habe, die mir "de" in "Deutsch" und "DE"
in "Deutschland" übersetzt - gibts aber bestimmt irgendwo. Ist
aber auch erst mal egal).

Aber:

Da drunter gibts noch eine Checkbox "Beta: Unicode UTF-8 für die
Unterstützung weltweiter Sprachen verwenden". Dafür finde ich
in dieser "Funktions-Gegend" (winnls.h) nichts passendes. Kann
man das auch via Kernel-Funktion abfragen (und gar setzen)?

Danke & Gruß Matthias.
Stefan Reuther (06.03.2020, 19:33)
Am 05.03.2020 um 18:19 schrieb Matthias Hanft:
> Da drunter gibts noch eine Checkbox "Beta: Unicode UTF-8 für die
> Unterstützung weltweiter Sprachen verwenden". Dafür finde ich
> in dieser "Funktions-Gegend" (winnls.h) nichts passendes. Kann
> man das auch via Kernel-Funktion abfragen (und gar setzen)?


Wozu willst du das denn abfragen?

Soweit ich das verstanden hab, sorgt diese Checkbox dafür, dass die
"A"-Funktionen UTF-8 statt Windows-1252 nehmen. Wenn du also Text hast,
steckst du den WideCharToMultiByte rein und bekommst was-auch-immer-
für-ein-Encoding-der-User-will raus.

Stefan
Matthias Hanft (06.03.2020, 22:55)
Stefan Reuther schrieb:
> Wozu willst du das denn abfragen?


Wenn das angekreuzt ist, funktioniert mein Programm nicht richtig:

Das ist mit Delphi 7 compiliert. Der Text in den Dialogboxen wird
dann mit verstümmelten Umlauten (Karo statt "ä") angezeigt, und
Delphi-Funktionen, die "XMLDocument" und seine Spielarten verwenden,
liefern Exceptions, wenn Umlaute in den XML-Feldern enthalten sind
(auch wenn sie im XML-Dokument korrekt mit "ISO-8859-1" oder "UTF-8"
deklariert sind).

> Soweit ich das verstanden hab, sorgt diese Checkbox dafür, dass die
> "A"-Funktionen UTF-8 statt Windows-1252 nehmen.


Ja, das könnte hinkommen, dass dieser Effekt auftritt - das passt
dann nämlich nicht zusammen.

Wenn ich aus meinem Programm heraus via Windows-Aufruf irgendwie
feststellen könnte, ob das angekreuzt ist, könnte ich dem Benutzer
anzeigen "Machen Sie das weg" (oder via Set-Funktion möglicherweise
sogar selbst gleich wegmachen).

Ich kenne niemanden, der das angekreuzt braucht (aber offenbar ist
das - z.B. auf Dell-Rechnern - manchmal von der "Werksinstallation"
her vorab angekreuzt).

Gruß Matthias.
Stefan Reuther (07.03.2020, 11:40)
Am 06.03.2020 um 21:55 schrieb Matthias Hanft:
> Stefan Reuther schrieb:
> Wenn das angekreuzt ist, funktioniert mein Programm nicht richtig:
> Das ist mit Delphi 7 compiliert. Der Text in den Dialogboxen wird
> dann mit verstümmelten Umlauten (Karo statt "ä") angezeigt, und
> Delphi-Funktionen, die "XMLDocument" und seine Spielarten verwenden,
> liefern Exceptions, wenn Umlaute in den XML-Feldern enthalten sind
> (auch wenn sie im XML-Dokument korrekt mit "ISO-8859-1" oder "UTF-8"
> deklariert sind).


OK, da müsste man wissen, was für APIs da intern verwendet werden, da
kenne ich mich dann nicht aus.

> Ja, das könnte hinkommen, dass dieser Effekt auftritt - das passt
> dann nämlich nicht zusammen.
> Wenn ich aus meinem Programm heraus via Windows-Aufruf irgendwie
> feststellen könnte, ob das angekreuzt ist, könnte ich dem Benutzer
> anzeigen "Machen Sie das weg" (oder via Set-Funktion möglicherweise
> sogar selbst gleich wegmachen).


Naja, du könntest ein Unicode-"ä" ($00E4) und MultiByteToWideChar
reinstecken und schauen, ob das Erwartete ($E4) rauskommt. Wenn nicht
hat der Nutzer ein Locale eingestellt, das nicht zu deinem Programm
passt (kann ja auch was japanisches oder russisches sein).

> Ich kenne niemanden, der das angekreuzt braucht (aber offenbar ist
> das - z.B. auf Dell-Rechnern - manchmal von der "Werksinstallation"
> her vorab angekreuzt).


Die Idee eines UTF-8-Locale ist so dumm nicht, weil man damit in
Programmen, die 'A' Funktionen verwenden, auch Unicode darstellen kann,
und eben nicht alles auf 'W' Funktionen umarbeiten muss. Insbesondere
die Funktionen der C/C++-Standardbibliotheken sind ja mit 'A' Funktionen
definiert (fopen usw.). Deswegen ist das in Unix/Linux ja mit UTF-8
gelöst worden, und die Nerds haben das halt für Windows auch haben wollen.

Für Anwender dürfte es keinen Grund geben, diesen Haken zu setzen, die
nerven einfach den Entwickler, dass der sein Programm anpasst :)

Stefan
Matthias Hanft (07.03.2020, 16:10)
Stefan Reuther schrieb:
> OK, da müsste man wissen, was für APIs da intern verwendet werden, da
> kenne ich mich dann nicht aus.


Also was die GUI bzw. Formulare und Controls angeht, gibt es noch
diesen seltsamen Effekt:

Wenn ich dort Texte im Entwicklungsmodus (also im Form-Designer)
reinschreibe (Fenstertitel, Labels, Dialogboxen etc.) und die zur
Laufzeit nie anfasse, werden die bei gesetztem Haken falsch ange-
zeigt. Die Locale selbst spielt dabei offenbar gar keine Rolle -
ich habe mal in einer VM ein rein US-englisches Windows aufgesetzt,
dort werden trotzdem alle deutschen Umlaute richtig angezeigt
(wenn dieser Haken nicht gesetzt ist).

Wenn ich dagegen Texte der Controls erst zur Laufzeit setze, z.B.
einen Label mit Label1.Caption:='Grüß Gott ohne Ärger'; dann sieht
das auch bei "falscher" Locale richtig aus.

Das scheint also unterschiedlich behandelt zu werden (was auch immer
die Laufzeitbibliothek da macht, siehe unten).

> Naja, du könntest ein Unicode-"ä" ($00E4) und MultiByteToWideChar
> reinstecken und schauen, ob das Erwartete ($E4) rauskommt. Wenn nicht
> hat der Nutzer ein Locale eingestellt, das nicht zu deinem Programm
> passt (kann ja auch was japanisches oder russisches sein).


Klingt interessant - damit werde ich mal herumexperimentieren. Wobei
eine falsche Locale ja gar nicht mal zu stören scheint - wenn da z.B.
"English (United States)" eingestellt ist, klappt ja trotzdem alles.
Es geht offenbar wirklich *nur* um diesen ominösen Haken bei "Beta:
Use Unicode UTF-8 for worldwide language support".

Das wäre schon schick, wenn's für dessen Abfrage (oder gar Setzen)
eine Windows-Funktion gäbe.

Hab grad mal gegoogelt: Es scheint sich um den Registry-Eintrag
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Contro l\Nls\CodePage\ACP
zu handeln. Ist der Haken gesetzt, steht dort der String "65001" drin.
Wenn nicht, "1252". Das kriegt man wohl auch mit GetACP, siehe

bzw. die Code Page Identifiers auf


Manche Websites raten auch zu einem Test ähnlich wie
WideCharToMultiByte((GetACP() == 65001) ? CP_UTF8 : CP_ACP,...

Hier schreibt auch jemand, dass Dell das tatsächlich standardmäßig ankreuzt:


Und Microsoft hat das Problem auch selbst erkannt:


Also an der Stelle könnte man wohl irgendwie ansetzen... das bringt
mich schon mal weiter.

> Die Idee eines UTF-8-Locale ist so dumm nicht, weil man damit in
> Programmen, die 'A' Funktionen verwenden, auch Unicode darstellen kann,
> und eben nicht alles auf 'W' Funktionen umarbeiten muss. Insbesondere
> die Funktionen der C/C++-Standardbibliotheken sind ja mit 'A' Funktionen
> definiert (fopen usw.). Deswegen ist das in Unix/Linux ja mit UTF-8
> gelöst worden, und die Nerds haben das halt für Windows auch haben wollen.


Ah, *das* ist also der Grund :-)

> Für Anwender dürfte es keinen Grund geben, diesen Haken zu setzen, die
> nerven einfach den Entwickler, dass der sein Programm anpasst :)


Wenn ich nur wüsste, wie :-) Wobei ich sagen muss, dass dieses Problem
jetzt nicht gerade Top-Priorität bei mir hat - von über 10.000 Anwendern
hatte ich bisher nur zwei, die damit steckengeblieben sind (und jetzt
weiß ich ja, wie man's beheben kann). An der Delphi-Laufzeitbibliothek
kann ich natürlich nicht herumschrauben (und Delphi 7 ist ja inzwischen
auch schon fast 20 Jahre alt - das spielt u.U. auch eine Rolle); daher
wollte ich über die Windows-eigenen Funktionen gehen, um (für mein
Programm) falsche Einstellungen herauszufinden und ggf. sogar gleich
korrigieren zu können.

Gruß Matthias.
Matthias Hanft (07.03.2020, 20:42)
Ich schrieb:
> HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Contro l\Nls\CodePage\ACP


Weitere Forschungen haben ergeben:

Es gibt dort die drei (REG_SZ-)Schlüssel "ACP", "MACCP" und "OEMCP".
Wenn man dieses "Beta-UTF8" ankreuzt, steht in allen drei Schlüsseln
"65001" drin. Wenn man das *nicht* ankreuzt, hängt der Inhalt von der
Einstellung unmittelbar darüber ab:

ACP MACCP OEMCP
deutsch 1252 10000 850
englisch 1252 10000 437
russisch 1251 10007 866
usw., und eben
UTF-8 65001 65001 65001

Neben dem Auslesen dieser Registry-Werte gibt es die Windows-Funktion
"GetACP", mit der man den ACP-Wert als simplen Integer auslesen kann.
Das kann ich in meinem Programm verwenden à la

if GetACP=65001 then print "Machen Sie den Haken bei UTF-8 weg!"
else if GetACP=1252 then print "Alles paletti!"
else print "Hmmm... ausländische Einstellung? Geht vielleicht."

Dummerweise gibt es keine Windows-Funktion "SetACP". Google findet
auch nur einige Foren-Threads, die sich über diese Tatsache aufregen,
dann aber irgendwann mehr oder weniger im Sande verlaufen.

Einfach nur diese Registry-Werte ändern (und dann neu starten)
genügt jedenfalls *nicht*.

Es *könnte* evtl. mit
setlocale( LC_ALL, "<language>_<country>.<code_page>" );
z.B. also
setlocale( LC_ALL, "German_Germany.1252" );
funktionieren, allerdings würde mir das Setzen der Codepage ja
genügen (die Sprache und/oder das Land muss ich nicht unbedingt
einstellen, nur eben "weg von 65001"). Ob es eine Kurzform à la
setlocale( LC_ALL, ".1252" );
gibt, muss ich noch herausfinden.
setlocale( LC_ALL, ".ACP" );
soll laut Microsoft-Doku funktionieren, aber das nimmt dann halt
die Standard-Codepage des Systems, und das will ich ja gerade
nicht. Auf der Seite

wo die gültigen Bezeichner aufgeführt sind, ist allerdings

locale :: "locale-name"
| "language[ _ country-region[ . code-page]]"
| " . code-page"
| "C"
| ""
| NULL

".code-page" als zulässig aufgeführt. Vielleicht kann man so
die 65001 durch die 1252 ersetzen. Aber zum Neu-Starten wird
man den Benutzer dann vermutlich trotzdem noch auffordern
müssen?!

Es bleibt also noch ein wenig Experimentalphysik zu betreiben...

Gruß Matthias.
Stefan Reuther (08.03.2020, 11:35)
Am 07.03.2020 um 15:10 schrieb Matthias Hanft:
> Stefan Reuther schrieb:
> Also was die GUI bzw. Formulare und Controls angeht, gibt es noch
> diesen seltsamen Effekt:
> Wenn ich dort Texte im Entwicklungsmodus (also im Form-Designer)
> reinschreibe (Fenstertitel, Labels, Dialogboxen etc.) und die zur
> Laufzeit nie anfasse, werden die bei gesetztem Haken falsch ange-
> zeigt.

Das wäre dann eine Frage für einen Delphi-Programmierer. Da gibt's doch
auch 'ne Newsgroup für? Ich hätte jetzt erwartet, dass gerade Dinge, die
irgendwie aus Ressource-Dateien kommen, grundsätzlich in Unicode sind.

> Klingt interessant - damit werde ich mal herumexperimentieren. Wobei
> eine falsche Locale ja gar nicht mal zu stören scheint - wenn da z.B.
> "English (United States)" eingestellt ist, klappt ja trotzdem alles.
> Es geht offenbar wirklich *nur* um diesen ominösen Haken bei "Beta:
> Use Unicode UTF-8 for worldwide language support".


Es kommt auf den Zeichensatz (Codepage) an, und der ist für Englisch und
Deutsch der gleiche (1252). Relevant wäre Russisch (1251) und sowas wie
Polnisch (1250), oder natürlich Fernost.

Stefan
Stefan Kanthak (08.03.2020, 16:30)
"Stefan Reuther" <stefan.news> schrieb:

[...]

> Das wäre dann eine Frage für einen Delphi-Programmierer. Da gibt's doch
> auch 'ne Newsgroup für? Ich hätte jetzt erwartet, dass gerade Dinge, die
> irgendwie aus Ressource-Dateien kommen, grundsätzlich in Unicode sind.


AUTSCH!
1. die Entwicklungsumgebung des unter der Namen "Delphi" beruechtigten
SCHROTTS speichert die o.g. Objekte NICHT als Ressourcen.
2. zumindest Ressourcen vom Typ STRINGTABLE und MESSAGETABLE koennen
in Ressource-Dateien in ANSI oder in UNICODE gespeichert werden.
3. beim Zugriff auf Ressourcen konvertieren die A-Funktionen des Win32-API
in UNICODE gespeicherte Ressourcen nach ANSI, und die W-Funktionen
andersrum.

Stefan
Matthias Hanft (08.03.2020, 16:54)
Stefan Reuther schrieb:
> Das wäre dann eine Frage für einen Delphi-Programmierer. Da gibt's doch
> auch 'ne Newsgroup für? Ich hätte jetzt erwartet, dass gerade Dinge, die
> irgendwie aus Ressource-Dateien kommen, grundsätzlich in Unicode sind.


In der Delphi-Newsgroup hatte ich dieses Phänomen letztes Jahr
schon mal angesprochen, aber keinerlei Antwort erhalten.

Delphi ist wohl irgendwann im Laufe der Jahre mal auf UTF-8
umgestellt worden (z.B. als Standard für den eingebauten Datentyp
"string"). Inwieweit das auch Windows-Aufrufe betrifft, weiß
ich allerdings nicht.

> Es kommt auf den Zeichensatz (Codepage) an, und der ist für Englisch und
> Deutsch der gleiche (1252). Relevant wäre Russisch (1251) und sowas wie
> Polnisch (1250), oder natürlich Fernost.


Ja, dass es um die "Codepage" (und nicht etwa um die "Locale")
geht, habe ich inzwischen herausgefunden. Locale (z.B. 0x0407
für Deutsch, 0x0409 für US-Englisch etc.) kann man in weiten
Grenzen abfragen und auch setzen; Code Pages (1252 für "Ansi-
Windows", 65001 für UTF-8 etc.) kann man mit "GetACP" zwar
abfragen (für die "Ansi Codepage"), aber nur für die "DOS-
Shell" (ala "OEM Codepage") setzen ("OEMCP", mit dem "DOS-
Befehl" CHCP).

Eine Windows-Aufrufmöglichkeit à la "SetACP" gibt es offenbar
nicht. Wie macht das denn die Systemsteuerung selbst? Die
muss das Windows ja auch irgendwie mitteilen. Einfach den
zugehörigen Registry-Eintrag unter HKEY_LOCAL_MACHINE\SYSTEM\
CurrentControlSet\Control\Nls\CodePage\ACP ändern genügt
offenbar jedenfalls nicht.

Meine Anwender sind halt "Mega-DAUs". Wenn ich rausfinden
würde, wie ich den "UTF-8-Haken" programmgesteuert entfernen
könnte (d.h. die ACP von 65001 in 1252 ändern), könnte ich
eine Dialogbox machen à la "Ihr Windows ist falsch konfiguriert,
wollen Sie, dass ich es korrigiere?". So wie jetzt muss ich
eine Infobox machen "Rufen Sie Einstellungen auf, dort Region,
dort erweitert, dann gehen Sie auf den Tab 'Verwaltung',
klicken dort 'Gebietsschema' an und entfernen den Haken
bei 'Beta: UTF-8' usw. usf. blablabla". Das rafft doch
kein normalsterblicher User - die erwarten, dass man
irgendwo auf "Ok" klicken kann und alles ist gut.

Gruß Matthias.
Matthias Hanft (08.03.2020, 20:38)
Ich schrieb:
> Eine Windows-Aufrufmöglichkeit à la "SetACP" gibt es offenbar
> nicht. Wie macht das denn die Systemsteuerung selbst? Die
> muss das Windows ja auch irgendwie mitteilen. Einfach den
> zugehörigen Registry-Eintrag unter HKEY_LOCAL_MACHINE\SYSTEM\
> CurrentControlSet\Control\Nls\CodePage\ACP ändern genügt
> offenbar jedenfalls nicht.


Offenbar schon, aber nur...
a) wenn man ACP *und* MACCP *und* OEMCP auf was anderes als
"65001" setzt
und
b) das System neu startet (Abmelden genügt nicht).

Problem ist nur, dass man für a) Admin-Rechte braucht (weil
das ja ein HKEY_LOCAL_MACHINE ist). Also werde ich ein kleines
Programm schreiben, das per Manifest Admin-Rechte anfordert
und das nix anderes tut als die drei Werte zu setzen und
dann ggf. auch den Reboot zu übernehmen, wenn der Anwender
das wünscht (ich hab zwar in der WinAPI einen Restart Manager
gefunden, aber "C:\Windows\System32\shutdown.exe /r" aufzurufen
dürfte einfacher sein). (*)

Dann wäre der Ablauf so:

1. Mein Hauptprogramm schaut mit GetACP nach, ob UTF-8 angekreuzt
ist (dann liefert GetACP = 65001 als Ergebnis zurück).

2. Wenn nein -> alles paletti (evtl. bei Nicht-1252 einen Hinweis
ausgaben, dass möglicherweise keine deutschen Umlaute verwendet
werden können oder so ähnlich).

3. Wenn ja, fragen, ob das richtiggestellt werden soll.

4. Wenn Anwender "Ja" klickt, mit ShellExecute mein Zusatzprogramm
"DisableUtf8" oder so mit Admin-Rechten aufrufen, das die drei
o.a. Werte auf Nicht-65001 ändert (entweder gleich 1252/10000/
850 für Westeuropa, oder evtl. abhängig von der User-Locale).

5. Dieses Zusatzprogramm fragt dann auch gleich "das funktioniert
erst, wenn Sie neu booten. Wollen Sie?"

6. Wenn der Anwender "Ja" klickt, "shutdown /r" aufrufen.

Damit sollte eigentlich auch der allerDAU zurechtkommen...

Gruß Matthias.

(*) Um Stefan zu beruhigen: Ja, ich hole den Pfad natürlich
mit GetSpecialFolderLocation(CSIDL_SYSTEM).
Ähnliche Themen