Ländereinstellungen
Sucht man im Internet nach Code, um die Ländereinstellungen mit VB zu
ändern, so wird man recht schnell fündig. Die API Funktion SetLocaleInfo
macht so etwas. Für jede Einstellung, die geändert werden soll, wie
beispielsweise das Dezimaltrennzeichen, gibt es Konstanten. Diese und die geänderte
Einstellung werden dann an die Funktion übergeben. Nach der Änderung
muss noch eine Message an alle Fenster gesendet werden, die Anwendungen darüber
informiert, dass bestimmte Einstellungen verändert wurden. Dazu kann man
SendMessage mit der Fensternachricht WM_SETTINGCHANGE benutzen. Das klappt vorzüglich
und man kann das im Windowsdialog intl.cpl sofort nachprüfen
(Shell "RUNDLL32.EXE shell32.dll,Control_RunDLL intl.cpl,,")
Die Sache hat nur einen gravierenden Haken.
EXCEL bekommt von der Änderung nichts mit!
Man kann machen, was man will, wenn aus einer Excel-Anwendung die Einstellung
geändert wird, bekommt diese Anwendung nichts mit. Excel scheint mit der
Codeausführung so beschäftigt zu sein, dass die Fensternachrichten
schlichtweg ignoriert werden. Andere Anwendungen wie Word, oder sogar Excel,
das in einem anderen Prozessraum läuft, schnallen das sofort. Ich habe
die Nachrichten abgehört und festgestellt, dass die eigene Anwendung die
Nachricht von der Änderung zwar bekommt, aber nicht reagiert.
Was also tun? Ich habe über Automatisierung Word gestartet und dort
den Code ausgeführt, das funzt auch nicht. Ich habe den Windows Scripting
Host benutzt und die dort vorhandene Funktion zur Manipulation benutzt, auch
das klappt nicht. Ein Manipulieren der Registry mit WSH bringt auch nichts.
Der Script verändert zwar die Einstellungen, aber Excel bekommt nichts
mit. Erst ein Neustart der Excel Anwendung bringt Abhilfe, das ist aber keine
Lösung. Dagegen Word oder Excel gestartet, und den Code dort ausgeführt,
ändert die zu manipulierende Excel-Mappe sofort. Man kann sich jetzt zwei
Mappen erstellen, die den Code für die Ländereinstellung Deutsch oder
Englisch enthalten. Diese kann man mit Shell aufrufen und man hat die gewünschte
Funktionalität. Es sind aber immer Vorbereitungen nötig.
Ich habe es hier anders gemacht. Sozusagen von Hinten durchs Auge gestochen.
Ein auf dem Rechner vorhandener Windows Scripting Host ist aber Voraussetzung.
Es ist aber nicht unbedingt nötig, dass die Erweiterung .vbs mit wscript.exe
verknüpft ist. Die meisten Firmenrechner verknüpfen sowieso defaultmäßig
mit Notepad. Der hier vorliegende Code macht nun folgendes:
Es wird eine .vbs Datei erzeugt, diese wird im Temp-Verzeichnis abgelegt und
ausführt. In der .vbs Datei ist Code, der eine neue Excel Instanz erzeugt,
eine neue Mappe anlegt und ein Modul einfügt. Dann wird in dieses Modul
via WSH der Code zum Ändern der Ländereinstellungen eingefügt.
Unter XL2002 muss unter
Extras/Optionen/Sicherheit/Schaltfläche "Makrosicherheit"
das Kontrollfeld:
"Zugriff auf Visual Pasic Projekte vertrauen"
aktiviert sein.
Ist das geschehen, wird der Code in der Excel-Datei ausgeführt. Leider
gibt es beim Schließen der Mappe immer wieder Probleme. Deshalb wird die
ganze Sache noch etwas komplexer. Nachdem Excel die Ländereinstellung geändert
hat, wird die Methode OnTime benutzt, um zeitversetzt Code zum Beenden von Excel
auszuführen. In der Zwischenzeit hat der Scripting Host Zeit, den Code
in der .vbs-Datei fertig abzuarbeiten und es knallt nicht mehr.
Ein kleines selbstgeschriebenes Delphi - Programm zu benutzen wäre aber
vermutlich einfacher und eleganter. ;-)
Beispieldatei LaendercodeAendern.xls 16 kB
Private Declare Function ShellExecute Lib "shell32.dll"
_
Alias "ShellExecuteA" (ByVal Fensterzugriffsnummer
As Long, _
ByVal lpOperation_wie_Open_oder_Print As String, _
ByVal lpDateiname_incl_Pfad As String, _
ByVal lpZusätzliche_Startparameter As String, _
ByVal lpArbeitsverzeichnis As String, _
ByVal nGewünschte_Fenstergröße_der_Anwendung
As Long) _
As Long
Private Declare Function GetTempPath Lib "kernel32" Alias _
"GetTempPathA" (ByVal nBufferLength As Long,
_
ByVal lpBuffer As String) As Long
Private Const SW_NORMAL = 1
Public Sub SpracheinstellungEn()
TrennzeichenÄndern ".", ","
End Sub
Public Sub SpracheinstellungDe()
TrennzeichenÄndern ",", "."
End Sub
Private Sub TrennzeichenÄndern(Dezimaltrennzeichen
As String, _
Tausendertrennzeichen As String)
Dim ScriptText As String, Datei As String
Dim Temppfad As String, Länge As Long
On Error Resume Next
Länge = 100
Temppfad = String(Länge + 1, 0)
'Temppfad ermitteln
Länge = GetTempPath(Länge, Temppfad)
Temppfad = Left(Temppfad, Länge)
Datei = Temppfad & "MyLocaleScript.vbs"
'Scripttext erzeugen
ScriptText = ScriptText & "Dim Xl, Wb, VBEObj, mdl,Line"
ScriptText = ScriptText & vbCrLf & _
"Set Xl=CreateObject(""Excel.Application"")"
'ScriptText = ScriptText & vbCrLf & _
"xl.Visible=true"
ScriptText = ScriptText & vbCrLf & _
"Set Wb=xl.Workbooks.Add"
ScriptText = ScriptText & vbCrLf & _
"Set VBEObj = xl.VBE.ActiveVBProject"
ScriptText = ScriptText & vbCrLf & _
"Set mdl = VBEObj.VBComponents.Add(1)"
ScriptText = ScriptText & vbCrLf & _
"mdl.name=""Test"""
'Folgendes wird dann ins Excel-Modul eingefügt
ScriptText = ScriptText & vbCrLf & _
"Line=""Private Declare Function SetLocaleInfo Lib """"kernel32""""
Alias """
ScriptText = ScriptText & vbCrLf & _
"Line=Line & """"""SetLocaleInfoA""""
(ByVal Locale As Long, ByVal LCType As Long, ByVal """
ScriptText = ScriptText & vbCrLf & _
"Line=Line & ""lpLCData As string) As Long"""
ScriptText = ScriptText & vbCrLf & "mdl.CodeModule.InsertLines
2, Line"
ScriptText = ScriptText & vbCrLf & _
"Line=""Private Declare Function SendMessage Lib """"user32""""
"""
ScriptText = ScriptText & vbCrLf & _
"Line=Line & ""Alias """"SendMessageA""""
(ByVal hwnd As Long, """
ScriptText = ScriptText & vbCrLf & _
"Line=Line & ""ByVal wMsg As Long, ByVal wParam As Long,
"""
ScriptText = ScriptText & vbCrLf & _
"Line=Line & ""ByVal lParam As string) As Long"""
ScriptText = ScriptText & vbCrLf & _
"mdl.CodeModule.InsertLines 3, Line"
ScriptText = ScriptText & vbCrLf & _
"Line=""Private Declare Function GetSystemDefaultLCID Lib """"kernel32""""
() As Long"""
ScriptText = ScriptText & vbCrLf & _
"mdl.CodeModule.InsertLines 4, Line"
ScriptText = ScriptText & vbCrLf & _
"Line=""Private Const LOCALE_SDECIMAL = &HE"""
ScriptText = ScriptText & vbCrLf & _
"mdl.CodeModule.InsertLines 5, Line"
ScriptText = ScriptText & vbCrLf & _
"Line=""Private Const LOCALE_USER_DEFAULT = &H400"""
ScriptText = ScriptText & vbCrLf & _
"mdl.CodeModule.InsertLines 6, Line"
ScriptText = ScriptText & vbCrLf & _
"Line=""Private Const LOCALE_STHOUSAND = &HF"""
ScriptText = ScriptText & vbCrLf & _
"mdl.CodeModule.InsertLines 7, Line"
ScriptText = ScriptText & vbCrLf & _
"Line=""Private Const WM_SETTINGCHANGE = &H1A"""
ScriptText = ScriptText & vbCrLf & _
"mdl.CodeModule.InsertLines 8, Line"
ScriptText = ScriptText & vbCrLf & _
"Line=""Private Const HWND_BROADCAST = &HFFFF&"""
ScriptText = ScriptText & vbCrLf & _
"mdl.CodeModule.InsertLines 9, Line"
ScriptText = ScriptText & vbCrLf & _
"Line=""Public Sub Aendern()"""
ScriptText = ScriptText & vbCrLf & _
"mdl.CodeModule.InsertLines 10, Line"
ScriptText = ScriptText & vbCrLf & _
"Line=""Dim LCID As Long"""
ScriptText = ScriptText & vbCrLf & _
"mdl.CodeModule.InsertLines 11, Line"
ScriptText = ScriptText & vbCrLf & _
"Line=""On Error Resume Next"""
ScriptText = ScriptText & vbCrLf & _
"mdl.CodeModule.InsertLines 12, Line"
ScriptText = ScriptText & vbCrLf & _
"Line=""LCID = GetSystemDefaultLCID()"""
ScriptText = ScriptText & vbCrLf & _
"mdl.CodeModule.InsertLines 13, Line"
ScriptText = ScriptText & vbCrLf & _
"Line=""SetLocaleInfo LCID, LOCALE_SDECIMAL, """""
& Dezimaltrennzeichen & """"""""
ScriptText = ScriptText & vbCrLf & _
"mdl.CodeModule.InsertLines 14, Line"
ScriptText = ScriptText & vbCrLf & _
"Line=""SetLocaleInfo LCID, LOCALE_STHOUSAND, """""
& Tausendertrennzeichen & """"""""
ScriptText = ScriptText & vbCrLf & _
"mdl.CodeModule.InsertLines 15, Line"
ScriptText = ScriptText & vbCrLf & _
"Line=""SendMessage HWND_BROADCAST, WM_SETTINGCHANGE, 0&,
ByVal 0&"""
ScriptText = ScriptText & vbCrLf & _
"mdl.CodeModule.InsertLines 16, Line"
ScriptText = ScriptText & vbCrLf & _
"Line=""Workbooks(1).saved=True"""
ScriptText = ScriptText & vbCrLf & _
"mdl.CodeModule.InsertLines 17, Line"
ScriptText = ScriptText & vbCrLf & _
"Line=""Application.OnTime Now + TimeSerial(0, 0, 1), """"Aus"""""""
ScriptText = ScriptText & vbCrLf & _
"mdl.CodeModule.InsertLines 18, Line"
ScriptText = ScriptText & vbCrLf & _
"Line=""End Sub"""
ScriptText = ScriptText & vbCrLf & _
"mdl.CodeModule.InsertLines 19, Line"
ScriptText = ScriptText & vbCrLf & "Line=""Private
sub Aus()"""
ScriptText = ScriptText & vbCrLf & "mdl.CodeModule.InsertLines
20, Line"
ScriptText = ScriptText & vbCrLf & "Line=""Application.quit"""
ScriptText = ScriptText & vbCrLf & "mdl.CodeModule.InsertLines
21, Line"
ScriptText = ScriptText & vbCrLf & "Line=""End Sub"""
ScriptText = ScriptText & vbCrLf & "mdl.CodeModule.InsertLines
22, Line"
ScriptText = ScriptText & vbCrLf & "xl.Run ""Aendern"""
ScriptText = ScriptText & vbCrLf & "set wb=nothing"
ScriptText = ScriptText & vbCrLf & "set xl=nothing"
'vbs - Datei erzeugen
If Dir(Datei) <> "" Then Kill Datei
Open Datei For Binary As #1
Put #1, , ScriptText
Close
'Ausführen
If Shell("wscript.exe """ & Datei & """")
= 0 Then
ShellExecute 0&, "Open", Datei, vbNullString,
vbNullString, SW_NORMAL
End If
End Sub
Dim Xl, Wb, VBEObj, mdl,Line
Set Xl=CreateObject("Excel.Application")
Set Wb=xl.Workbooks.Add
Set VBEObj = xl.VBE.ActiveVBProject
Set mdl = VBEObj.VBComponents.Add(1)
mdl.name="Test"
Line="Private Declare Function SetLocaleInfo Lib ""kernel32""
Alias "
Line=Line & """SetLocaleInfoA"" (ByVal Locale As
Long, ByVal LCType As Long, ByVal "
Line=Line & "lpLCData As string) As Long"
mdl.CodeModule.InsertLines 2, Line
Line="Private Declare Function SendMessage Lib ""user32""
"
Line=Line & "Alias ""SendMessageA"" (ByVal hwnd
As Long, "
Line=Line & "ByVal wMsg As Long, ByVal wParam As Long, "
Line=Line & "ByVal lParam As string) As Long"
mdl.CodeModule.InsertLines 3, Line
Line="Private Declare Function GetSystemDefaultLCID Lib ""kernel32""
() As Long"
mdl.CodeModule.InsertLines 4, Line
Line="Private Const LOCALE_SDECIMAL = &HE"
mdl.CodeModule.InsertLines 5, Line
Line="Private Const LOCALE_USER_DEFAULT = &H400"
mdl.CodeModule.InsertLines 6, Line
Line="Private Const LOCALE_STHOUSAND = &HF"
mdl.CodeModule.InsertLines 7, Line
Line="Private Const WM_SETTINGCHANGE = &H1A"
mdl.CodeModule.InsertLines 8, Line
Line="Private Const HWND_BROADCAST = &HFFFF&"
mdl.CodeModule.InsertLines 9, Line
Line="Public Sub Aendern()"
mdl.CodeModule.InsertLines 10, Line
Line="Dim LCID As Long"
mdl.CodeModule.InsertLines 11, Line
Line="On Error Resume Next"
mdl.CodeModule.InsertLines 12, Line
Line="LCID = GetSystemDefaultLCID()"
mdl.CodeModule.InsertLines 13, Line
Line="SetLocaleInfo LCID, LOCALE_SDECIMAL, "","""
mdl.CodeModule.InsertLines 14, Line
Line="SetLocaleInfo LCID, LOCALE_STHOUSAND, ""."""
mdl.CodeModule.InsertLines 15, Line
Line="SendMessage HWND_BROADCAST, WM_SETTINGCHANGE, 0&, ByVal 0&"
mdl.CodeModule.InsertLines 16, Line
Line="Workbooks(1).saved=True"
mdl.CodeModule.InsertLines 17, Line
Line="Application.OnTime Now + TimeSerial(0, 0, 1), ""Aus"""
mdl.CodeModule.InsertLines 18, Line
Line="End Sub"
mdl.CodeModule.InsertLines 19, Line
Line="Private sub Aus()"
mdl.CodeModule.InsertLines 20, Line
Line="Application.quit"
mdl.CodeModule.InsertLines 21, Line
Line="End Sub"
mdl.CodeModule.InsertLines 22, Line
xl.Run "Aendern"
set wb=nothing
set xl=nothing
Option Explicit
Private Declare Function SetLocaleInfo Lib "kernel32"
_
Alias "SetLocaleInfoA" (ByVal Locale As Long,
_
ByVal LCType As Long, ByVal lpLCData As String) As Long
Private Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" (ByVal hwnd As Long,
_
ByVal wMsg As Long, ByVal wParam As Long, _
ByVal lParam As String) As Long
Private Declare Function GetSystemDefaultLCID Lib "kernel32" () As
Long
Private Const LOCALE_SDECIMAL = &HE
Private Const LOCALE_USER_DEFAULT = &H400
Private Const LOCALE_STHOUSAND = &HF
Private Const WM_SETTINGCHANGE = &H1A
Private Const HWND_BROADCAST = &HFFFF&
Public Sub Aendern()
Dim LCID As Long
On Error Resume Next
LCID = GetSystemDefaultLCID()
SetLocaleInfo LCID, LOCALE_SDECIMAL, ","
SetLocaleInfo LCID, LOCALE_STHOUSAND, "."
SendMessage HWND_BROADCAST, WM_SETTINGCHANGE, 0&, ByVal 0&
Workbooks(1).Saved = True
Application.OnTime Now + TimeSerial(0, 0, 1), "Aus"
End Sub
Private Sub Aus()
Application.Quit
End Sub