VSTO – Word Office XP/2002 – normal.dot wird immer grösser

 Entwicklung  Kommentare deaktiviert für VSTO – Word Office XP/2002 – normal.dot wird immer grösser
Okt 152009
 

Für WordPlus 4 generiere ich ein Menü im Word. Wir mussten feststellen, dass nach dem Word geschlossen wurde die normal.dot immer um ein paar KB grösser wurde. 30,40,50,60KB … bis es Kunden gab die mit mehr als 10MB zu kämpfen hatten. Das darf aber nicht sein. Nicht wegen einem Menü.

Wenn ein Menüpunkt dem Word hinzugefügt passiert das in etwa so.

Office.CommandBar toolBar = word.CommandBars.Add("Name des Menüpunkte", 
Microsoft.Office.Core.MsoBarPosition.msoBarTop, Type.Missing, true);

Der letzte Parameter würde eigentlich angeben das der Eintrag nur temporär wäre. Aber die VSTO scheint das zu ignorieren. Deshalb wird die normal.dot immer grösser.

Im Netzt gibt es einige Lösungen für das Problem.

– Die normal.dot schreibschützen. Nein, nicht gut.

– Das Menü in ein Menu.dot auslagern und das installieren. Auch nicht gut, da bei uns das Menü dynamisch aufgebaut wird.

– Den CusomizationContext auf der WordApplication ändern. Das tönt nicht schlecht.

Den letzten Punkt habe ich dann mal umgesetzt.

private Word.Template GetCustomTemplate()
{
	object templatePath = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase), "Menu.dot").Replace(@"file:\", "");            

	if (!File.Exists(templatePath as string))
	{
		return null;
	}

	object install = true;
	word.AddIns.Add(templatePath.ToString(), ref install);
	return word.Templates.get_Item(ref templatePath);
}

private void CreateMenu(string ribbonXml, string iconPath)
{
	Word.Template customTemplateTemp = (Word.Template)word.CustomizationContext;
	Word.Template newTemplate = null;

	try
	{
		//TemplateContext in Sicherheit bringen
		newTemplate = GetCustomTemplate();
		if (newTemplate != null)
		{
			word.CustomizationContext = newTemplate;
		}

		//Menü erstellen
	}
	finally
	{
		if (newTemplate != null)
		{
			((Word.Template)word.CustomizationContext).Saved = true;
			word.CustomizationContext = customTemplateTemp;
		}
	}
}

Es wird also ein Menu.dot gesucht. Wenn es diese gibt wird der CustomizationContext damit ausgetauscht und das original vorher noch in Sicherheit gebracht. Das Menü wird erstellt und danach wieder der alte Context angehängt. Ist eine Empfehlung aus dem Netzt und wurde früher in VBA auch so gelöst.

Bei mir funktionierte das einwandfrei. Egel ob ich Word aus Visual Studio heraus startete oder nicht. Das Menü wurde richtig geladen und die Klickevents funktionierten.

Ich musste jetzt aber feststellen, dass es Clients gibt bei denen einfach kein Klickevent ausgelöst wird. Wenn auf ein Menüeintrag geklickt wurde passierte einfach nichts. Aber nicht auf allen Clients. Auf dem Entwicklungsclient klappte es. Egal ob ich das AddIn aus VS heraus startete oder nicht. Menü tat immer. Man finde jetzt das Problem.

Word hat zudem die dumme Angewohnheit ein altes Menü immer noch anzuzeigen, obwohl das AddIn nicht geladen wurde. Ich ging also immer davon aus, dass das AddIn geladen wird.

Nach langem suchen wurde dann klar was los ist.

Das AddIn wird geladen, dass Menü erstellt und auch angezeigt. Aber sobald der Code in der Zeile 36 vorbei kam verschwand das Menü. Also wusste ich das es mit dem CustomizationContext zusammen hängen musste.

Die Lösung ist jetzt äusserst einfach.

//Menü erstellen
((Word.Template)word.CustomizationContext).Saved = true;

Das Menü wird nun angezeigt und funktioniert auch. Kein Context wechsel mehr.

Die normal.dot wird aber nicht mehr grösser. Wenn Änderungen an Word vorgenommen werden, z.b. Toolbar Anpassungen, werden diese aber sehr wohl in der normal.dot gespeichert. Aber das automatisch generierte Menü kommt nicht mehr in die normal.dot. Ziel erreicht.

kick it on dotnet-kicks.de

C# – Custom TabControl

 Entwicklung, Software  Kommentare deaktiviert für C# – Custom TabControl
Dez 222008
 

OK, der Titel ist Bluff. 🙂

Um was geht es. Bislang sah im WordPlus die Task Pane in etwa so aus. Je nachdem welche Snap-In’s man gewählt hatte.

Alte WordPlus TaskPane

Die Daten, die in der Task Pane angezeigt werden, werden aus den Docproperty’s des Dokumentes generiert. Wenn jetzt aber ein Makro im Hintergrund ein Docproperty ändert schlägt sich das nicht in der Task Pane nieder. Das führt dazu, dass in der Task Pane etwas anderes angezeigt wird als in den Docproperty’s ist.

Das sollte mit einem TabControl gelöst werden. Bedingung, es muss gut aussehen. Aber man sage das einem Entwickler. Ich nehme das 0815 TabControl. Aber das führt zu einem Aufschrei bei den Verantwortlichen. Das sieht ja gar nicht schick aus. Also muss man sowas selber bauen.

Aussehen sollte es in etwa so.

So sollte es in etwa aussehen

Aber nur in etwa. Einfach nicht so langweilig wie das normale TabControl.

fertiges TabControl

Der rote Pfeil markiert jetzt mein Problem. Wie soll ich diese Linien sinnvoll Zeichnen ohne das ich irgend welche OnPaint oder OnPreRender überschreiben muss. Dazu fehlt mir schlicht die Zeit und das Zeitbudget. 🙂

Aber für solche Probleme gibt es ja versierte Kollegen. Man nehme einfach ein Label, stelle BorderStyle auf FixesSingle und setze die Höhe auf 1. Dan gibt es eine Linie. Man platziere sie richtig, stelle noch den Anchor richtig ein, und schon sieht es cool aus. Vor allem schneller als mit OnPaint oder so. Dieses Zweiertab besteht aus 11 Labels. 🙂

TabControl im Designer

Jetzt kann man einfach noch das richtige Label ausschalten und schon hat man die “Lücke”.

Wer eine bessere Idee hat darf sich melden. Das ging schnell und einfach. Aber … Na ja.

Ob die Lösung ins Finale WordPlus kommt ist noch nicht klar. Wird sich noch zeigen.

VS – Unterschied zwischen F5 und CTRL+F5, oder wie finde ich den Fehler

 Allerlei, Entwicklung, Software  Kommentare deaktiviert für VS – Unterschied zwischen F5 und CTRL+F5, oder wie finde ich den Fehler
Okt 102008
 

Das hat jetzt einiges an Nerven gekostet. Eigentlich sollte ich nur ein Release-Build machen und das einchecken. Aus lauter gewohnheit habe ich dann mal die EXE-Datei gestartet und musste feststellen das die Anwendung nicht wollte. Wie so nicht? Na ja, dass galt es nun rauszufinden.

Also stellte ich die Konfiguration auf Debug und drückte F5. Die Anwendung startete ohne Fehler. Ein Doppelklick auf die EXE oder ein CTRL+F5, die Anwendung wollte nicht. 🙁

Zuerst prüfte ich dann mal alle Verzeichnisse auf einen Schreibschutz. Es war nichts schreibgeschützt.

Da ich nur eine allgemeine Fehlermeldung bekam, die leider nichts sage wo was passierte, musste ich mich mühsam durchsuchen bis ich dort war wo es bum machte. Ich konnte ja nicht debuggen. Mit der MessageBox.Show(“Hallo x”) schaute ich wo es noch tat.

Nach einiger Zeit landete ich hier.

protected override DbConnection CreateConnection(string connectionString)
{
	return new SqlConnection(connectionString);
}

Jetzt konnte ich alles in ein try{} catch() Block packen und schauen was genau der Fehler war.

System.TypeInitializationException: Der Typeninitialisierer für

"System.Data.SqlClient.SqlConnection" hat eine Ausnahme verursacht.

—> System.TypeInitializationException: Der Typeninitialisierer für

"System.Data.SqlClient.SqlConnectionFactory" hat eine Ausnahme verursacht.

—> System.TypeInitializationException: Der Typeninitialisierer für

"System.Data.SqlClient.SqlPerformanceCounters" hat eine Ausnahme

verursacht.

—> System.Configuration.ConfigurationErrorsException: Das

Konfigurationssystem konnte nicht initialisiert werden.

—> System.Configuration.ConfigurationErrorsException: Unbekannter

Konfigurationsabschnitt "lag.wordplus". (P:\ProjectX\WP.config line 8)

   bei System.Configuration.ConfigurationSchemaErrors.ThrowIfErrors(Boolean

ignoreLocal)

   bei

System.Configuration.BaseConfigurationRecord.ThrowIfParseErrors(ConfigurationSchemaErrors

schemaErrors)

   bei System.Configuration.BaseConfigurationRecord.ThrowIfInitErrors()

   bei System.Configuration.ClientConfigurationSystem.EnsureInit(String

configKey)

   — Ende der internen Ausnahmestapelüberwachung —

   bei System.Configuration.ConfigurationManager.PrepareConfigSystem()

   bei System.Configuration.ConfigurationManager.GetSection(String

sectionName)

   bei

System.Configuration.PrivilegedConfigurationManager.GetSection(String

sectionName)

   bei System.Windows.Forms.WindowsFormsSection.GetSection()

   — Ende der internen Ausnahmestapelüberwachung —

   bei System.Data.SqlClient.SqlConnectionFactory..cctor()

   — Ende der internen Ausnahmestapelüberwachung —

   bei System.Data.SqlClient.SqlConnection..cctor()

   — Ende der internen Ausnahmestapelüberwachung —

   bei System.Data.SqlClient.SqlConnection..ctor()

   bei System.Data.SqlClient.SqlConnection..ctor(String connectionString)

   bei LAG.WordPlus.Database.SqlDatabase.CreateConnection(String

connectionString) in P:\ProjectX\SqlDatabase.cs:Zeile 23.

Scheinbar wurde der Konfigurationsabschnitt “lag.wordplus” nicht gefunden. Den gibt es aber. Ganz sicher.

Der Unterschied zwischen CTRL+F5 und F5:

CTRL+F5: AppDomain.CurrentDomain.SetupInformation.ConfigurationFile == ANWENDUNGSNAME.config

F5: AppDomain.CurrentDomain.SetupInformation.ConfigurationFile == ANWENDUNGSNAME.vshost.exe.config

Das brachte mich dann auf die Idee die App.config genauer anzuschauen.

Ich fand dort folgendes.

<!– <configSections>

    <section name="lag.wordplus"

type="LAG.WordPlus.Configuration.WordPlusSection, LAG.WordPlus" />

  </configSections> –>

Na ja, was soll ich sagen. <!– –> weg und es tut.

Und wieder um eine Erfahrung reicher. 🙂

Jun 242008
 

Ich muss mit WordPlus einem Word-Dokument einige Textbausteine einfügen.
Geliefert werden sie mir von/aus einer Datenbank. So können
Word-Dokumente sehr einfach komponiert werden.

Wie macht man das nun.

Word.Application word = new Word.Application();

Word.Document doc =
					word.Documents.Add(ref templatepath,
					ref missing,
					ref missing,
					ref objFalse);

object to = Word.WdUnits.wdStory;
doc.Select();
word.Selection.EndKey(ref to, ref missing);

word.Selection.InsertFile(file, 
							ref missing, 
							ref missing, 
							ref missing, 
							ref missing);

Zuerst besorgt man sich ein neues Word. Zeile 1.

Danach fügt man dem Word ein neues Dokument ein. Bei uns
ist das dann meistens das mit den Kopf- und Fusszeilen. Zeile 3 bis 7.

In Zeile 9 bis 10 setze ich den Cursor ans ende des Dokumentes.
Die Textbausteine sollen immer ganz am ende eingefügt werden.

In Zeile 13 bis 17 wird dann der Textbaustein eingefügt. Das macht
man dann natürlich in einer Schlaufe. Pro Textbaustein einmal
Zeile 13 bis 17.

PS: Das hier ist auch noch wichtig. Nicht das man danach sucht.

object missing = Type.Missing;
object objFalse = (object)false;

Einfach vor der ersten Zeile einfügen. 🙂