Übersetzen von C++/MFC- und C#-Anwendungen

Die Übersetzung von Anwendungs-Ressourcen (Texte, Dialogfenster, usw.) in verschiedene Sprachen kann meist nicht mit Bordmitteln gemacht werden, da diese zu restriktiv sind.

Visual Studio .NET 2005 bietet da zwar einige nette Dinge, aber die Praxistauglichkeit finde ich als nicht gegeben.

Deswegen verwende ich separate Anwendungen:

C++/MFC-Anwendungen

Zum Übersetzen von C++/MFC-Anwendungen verwende ich seit ein paar Monaten/Jahren das Werkzeug „appTranslator“ und bin sehr zufrieden.

Details dazu findet Ihr in meinem entsprechenden Weblog-Eintrag zu appTranslator.

C#/.NET-Anwendungen

Der in Visual Studio .NET eingebaute Windows Forms-Designer bietet zwar die Übersetzung von Dialogfenster-Ressourcen grafisch an, und ist soweit auch brauchbar, hat aber die Nachteile, dass die übersetzende Person das Visual Studio benötigt und dass Zeichenketten-Ressourcen, die im Quelltext verwendet werden (z.B. beim Werfen von Ausnahmen) nicht übersetzt werden können.

Durch Zufall bin ich auf das Werkzeug „Multi-Language Add-In for Visual Studio .NET“ gestossen.


Bildschirmfoto, Klick für Großbild

Dieses Werkzeug sieht sehr vielversprechend aus, kommt mit .NET 2.0 zurecht und kann über den Import/Export von Excel-Dokumenten auch von Übersetzern ohne Visual Studio-Installation verwendet werden.

Ich hab’s bisher noch nicht produktiv eingesetzt, werde das aber ziemlich sicher machen (es sei denn ich finde noch was Besseres). Die Preise sind mit 100 Euro sehr moderat.

Probiert’s mal aus und gebt mir Feedback, bitte!

System.TypeLoadException in C++/CLI-MFC-Anwendung

Beschreibung

Beim Umstellen einer MFC-Anwendung auf C++/CLI kam nach erfolgreicher Kompilierung beim Start eine .NET-Fehlermeldung System.TypeLoadException, mit Fehlercode 0x80131522.

Ursache

Genau kenne ich die Ursache nicht, verschiedene Berichte/Postings deuten darauf hin, dass es ein Fehler mit dem Assembly Loader ist, der die Anwendung initial startet.

Scheinbar gibt es eine Begrenzung diverser Ressourcen in der Sektion globaler Symbole. Dass dies tatsächlich ein Grund sein könnte zeigte die riesige Dateigröße von 66 MB für die eigentliche Anwendung (früher, ohne C++/CLI war diese 30 MB groß).

Lösung

Die eigentliche, für mich passende, Lösung wurde hier beschrieben:

Ich habe das sogenannte „String Pooling“ in meinen Visual C++-Projekteinstellungen aktiviert. Danach war die kompilierte Anwendung noch 8 MB (statt 66 MB) groß und der Fehler trat beim Laden nicht mehr auf.

Weitere ggf. nützliche Ressourcen:

Fehlermeldung beim Aktualisieren einer SQL Server 2000-Tabelle äber einen Verbindungsserver

Beschreibung

In einem Szenario hatten wir 2 Microsoft SQL Server 2000 (Server A und B). der eine hat den anderen als Verbindungsserver („Linked server“) eingebunden.

Wenn nun von einer Datenbank auf Server B eine SELECT-SQL-Abfrage auf eine Tabelle in einer Datenbank auf Server A ausgeführt wurde, so hat dies korrekt funktioniert.

Wurde jedoch eine UPDATE-SQL-Abfrage ausgeführt, so kam eine Fehlermeldung.

Die auszuführende Abfrage war in etwa:

UPDATE [MyTable]
SET [Credit Limit Block]=2
WHERE [No.]=’000102628521′

(also eine Abfrage auf Spaltennamen mit Leerzeichen).

Als Fehlermeldung erschien dann:

Server: Nachr.-Nr. 8180, Schweregrad 16, Status 1, Zeile 1
Statement(s) could not be prepared.

Server: Nachr.-Nr. 170, Schweregrad 15, Status 1, Zeile 1
Line 1: Incorrect syntax near ‚Limit‘.

Ursache

Scheinbar hat der SQL Server 2000 bei bestimmten Konfigurationsparametern Probleme bei UPDATE-Abfragen über einen Verbindungsserver, wenn Feldern mit Leerzeichen beteiligt sind.

Dies waren die ursprünglichen Einstellungen des Verbindungsservers:

Verbindungsserver-Einstellungen die in meinem Fall die UPDATE-Anweisung fehlschlagen ließen
Fehlgeschlagen

Damit kam die Fehlermeldung.

Bei Google habe ich unter anderem folgende Zitate gefunden:

…If I was to remove the space from (my colum name) [f 1] and use [f1] it would work fine…

Und

I’ve seen this before, and I’m quite sure that I have reported it to
Microsoft. However, it does not seem have been fixed in SQL 2000. The
error is that when the query is submitted to the remote server, the
brackets are missing.

Lösung

Da ich ein anderes, fast gleichwertiges, System hatte, auf dem die UPDATE-Abfrage korrekt funktionierte, habe ich die Einstellungen des Verbindungsservers verglichen und die Option gefunden, die in meinem Fall die Lösung war:

Verbindungsserver-Einstellungen die in meinem Fall die UPDATE-Anweisung erfolgreich ausführen ließen
Erfolgreich

Ich habe also schlicht die Option „Remotesortierung verwenden“ deaktiviert. Danach funktionierte meine Abfrage.

Ob das in jedem Fall eine praktikable Lösung ist, weiß ich leider nicht, jedoch in meinem Fall war dies ausreichend.

Die <%@ Page %>-Direktive in ASP.NET 2.0 um benutzerdefinierte Attribute erweitern

Im Artikel „Obscure but cool feature in ASP.NET 2.0“ schreibt Scott Guthrie darüber, wie die Page-Direktive um eigene Attribute erweitert wird.

Z. B.

<%@ Page 
	Language="C#" 
	Message="My Test Message String"
	Inherits="BasePage"%>

Dabei ist das „Language“-Attribut und das „Inherits“-Attribut ein eingebautes Attribut, das „Message“-Attribut ist ein benutzerdefiniertes.

Ich habe das mit der RTM-Version (also der endgültig freigegebenen Version) von ASP.NET 2.0 probiert, so wie von Scott beschrieben, bin aber erst mal auf den Fehler gelaufen:

Build (web): Fehler beim Analysieren des Attributs message: Der Typ System.Web.UI.Page hat keine öffentliche Eigenschaft mit dem Namen message.

Da Scott den Artikel mit der Version Beta 1 von ASP.NET 2.0 geschrieben hat, hat sich da wohl was geändert intern. Er schreibt das auch in einem entsprechenden Kommentar zu seinem Artikel, verschweigt aber wie genau das gemacht wird.

Nun, die Lösung ist ganz einfach (wie immer, wenn man weiß wie:

Das „CodeFileBaseClass„-Attribut muß auch in der Page-Direktive angegeben werden, und zwar mit dem Namen der Basisklasse, und nicht mit dem Namen der CodeBehind-Klasse.

Z. B.

<%@ Page 
	Language="C#" 
	CodeFileBaseClass="BasePage" 
	Message="My Test Message String"  
	Inherits="BasePage"%>

Dann sollte es korrekt funktionieren. In einem konkreten Fall habe ich folgendes erfolgreich geschrieben:

<%@ Page 
	Language="C#" 
	MasterPageFile="~/StandardMaster.master" 
	Inherits="Pages_ConfigurationAssetList" 
	CodeFile="ConfigurationAssetList.aspx.cs" 
	CodeFileBaseClass="PageBase" 
	Title='Anlagenliste' 
	TitleImageFileName="CheckBook.png" %>

Wobei „PageBase“ die Basisklasse war und „TitleImageFileName“ mein neu hinzugefügtes Attribut.

Microsoft Indexing Service findet (scheinbar) nicht vorhandene Suchbegriffe

Beschreibung

Beim Suchen nach Suchbegriffen mit dem Indexing Service von Microsoft (auch „Index Server“ genannt) tritt das Phänomen auf, daß auch Dokumente gefunden werden die den Suchbegriff scheinbar gar nicht enthalten.

Beispielsweise wurde nach „preisliste“ oder „kombinationsbeispiel“ gesucht und eben solche scheinbar falschen Dokumente gefunden. Hingegen haben Suchanfragen nach Wörtern wie „haus“ oder „auto“ nur korrekte Dokumente geliefert.

Ursache

Ich vermute sehr, dass der Indexing Service bei zusammengesetzten Wörtern die Wörter aufteilt und sucht als wäre es eine Suche nach den einzelnen Wörtern (gibt es da in der Grammatik Regeln um dies automatisch durchzuführen?).

Also beispielsweise bei der Suche nach „preisliste“ führt der Indexing Service eine Suchanfrage aus nach Dokumenten die „preis“ oder „liste“ oder „preisliste“ als Suchbegriffe enthalten.

Deswegen werden scheinbar auch „falsche“ Dokumente gefunden.

Lösung

Als einzigen Workaround habe ich die sogenannten „Content Queries“ gefunden.

Wenn mit einem Suchbegriff nun statt beispielsweise nach „preisliste“ über die erweitere Syntax nach „{phrase} preisliste {/phrase}“ gesucht wird, so werden tatsächlich auch nur Dokumente gefunden die direkt den Begriff „preisliste“ enthalten.

Ich bin mir unsicher ob das ein sauberes Vorgehen ist oder eher ein „geht so, ist aber eigentlich für was anderes gedacht gewesen“. Aber es funktioniert in allen bisherigen Tests :-).

Ergänzung 2006-03-03: Im Artikel „Creating Search Pages with Index Server and .NET“ auf CodeProject schreibt Heath Stewart über die „CONTAINS“- und „FREETEXT“-Prädikate. Ggf. auch eine Alternative.

Zeichenketten in C# formatieren

Dieser Artikel hier soll im Laufe der Zeit für mich (und ggf. andere) eine schnell zu findende Kurzreferenz für Zeichenkettenformatierung in C# werden.

In C/C++ gibt es printf() und verwandte Funktionen um verschiedene Datentypen formatiert in Zeichenfolgen umzuwandeln. In .NET/C# sind es string.Format(), object.ToString() und verwandte Funktionen, die verwendet werden um dies zu erreichen.

Tipps

1.) Nachkommastellen festlegen

Um die Nachkommastellen beim Umwandeln von Fließkommazahlen (decimal, double, float) zu beeinflussen, einfach das Präfix „:F“ gefolgt von der Anzahl der Nachkommastellen angeben.

Beispiel:

decimal x = 0.00m;
double y = 1.38;

// Variablen x und y auf jeweils
// 2 Nachkommastellen formatieren.
string s1 = string.Format( "{0:F2}", x );
string s2 = string.Format( "{0:F2}", y );

2.) Vorkommastellen festlegen und mit Nullen auffüllen

Um die Vorkommastellen beim Umwandeln von Ganzzahlen (z.B. int, long) zu beeinflussen und auf eine feste Anzahl stellen zu bringen, einfach das Präfix „:“ gefolgt von der gewünschten Anzahl als Nullen („0“) verwenden.

Beispiel:

int i = 19;

// Variable i auf 5 Stellen formatieren,
// fehlende Stellen mit "0" auffüllen.
string s1 = string.Format( "{0:00000}", i );

3.) Integerzahlen hexadezimal mit führenden Nullen darstellen

Um ganze Zahlen hexadezimal mit einer festen Anzahl Stellen zu formatieren einfach ein „X“ gefolgt von der gewünschten Anzahl der Nullen (z.B. „4“) schreiben.

Beispiel:

int i = 234;

// Schreibt "00EA" in s1.
string s1 = i.ToString( "X4" );

Beispiel (alternativ zum vorherigen Beispiel, gleiches Ergebnis):

int i = 234;

// Schreibt "00EA" in s1.
string s1 = string.Format( "{0:X4}", i );

Internet-Ressourcen

Folgende Artikel/Seiten sind hilfreich: