Mehr Infos zu nichts sagenden Fehlermeldungen

 Entwicklung  Kommentare deaktiviert für Mehr Infos zu nichts sagenden Fehlermeldungen
Okt 162009
 

Wer wusste das?

Ich bekomme zur Zeit immer eine Fehlermeldung im Word die mir eigenartig vorkommt.

Fehlermeldung

Das ist ein eingebettetes Excel im Word. Alles unter Office 2007. Excel ist aber sicher installiert.
Diese Meldung kommt nur wenn man a) ein Add-in im Excel hat das einige Events registriert hat und b) wenn Excel vor dem Word mit dem eingebetteten Excel startet. Aber sie kann durchaus auch in anderen Situationen auftreten. Ich habe ihm Internet einige gefunden.

Aber was interessant ist. Drückt mal “Ctrl + Shift + i”.

Fehlernummer unten rechts im Dialog

Es erscheint unten rechts eine Fehlernummer. Habe dazu zwar noch nichts gefunden aber das wird schon noch kommen.

Ich bin gespannt wo ich noch mehr von diesen Meldungen finde.

kick it on dotnet-kicks.de

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

Office XP – deploy Add-in – Wie registriert man die Extensibility.dll

 Entwicklung, Software  Kommentare deaktiviert für Office XP – deploy Add-in – Wie registriert man die Extensibility.dll
Nov 282008
 

Wer suched der findet. Bei mir hat es jetzt sehr, sehr lange gedauert.

Ich habe ein Office XP Add-in das auf diversen Systemen mit verschiedenen Konfigurationen installiert werden muss. Ein Add-in für Office XP/2002 muss die Schnittstelle Extensibility.IDTExtensibility2 implementieren. Diese ist in der Extensibilty.dll definiert.

Auf einem XP mit SP2 und Office XP/2002 ohne SP ist die DLL aber nicht registriert, dass heisst nicht im GAC.

Auf dem Entwicklungsclient habe ich die DLL natürlich. Also, ich nehme die dll, kopiere sie auf das Zielsystem und versuche das Teil mit RegAsm.exe zu registrieren. Das führt zu einer Fehlermeldung in dieser form.

RegAsm : error RA0000 : Could not load file or assembly ‚Extensibility, Version= 7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a‘ or one of

Das Teil will einfach nicht in den GAC.

Wie bin ich nun vorgegangen um das Add-in auf einem frisch aufgesetzten System an den Start zu bringen.

  1. Man mache ein Setup. Das Setup mache ich NUR weil ich nicht weiss was alles in die Registry muss.
    Die Primäre Ausgabe wird bei Register auf vsdrpCOM gestellt.
    image
  2. Bei den Abhängigkeiten genau das selbe. Wenn ich die Office XP/2002 PIA Abhängigkeiten aus dem Setup ausschliesse, und sie deshalb nicht registriert werden, läuft das Add-in nicht mehr. Aber eigentlich müssten die Office XP/2002 PIA’s ja schon bei der Installation der Office XP/2002 PIA’s registriert worden sein.
    image
  3. Wenn man schon dabei ist, dann kann man auch gleich noch drei Registry Key importieren. Für jedes Office Programm das ein Add-in hat ein Schlüssel.

    Windows Registry Editor Version 5.00

    [HKEY_CURRENT_USER\Software\Microsoft\Office\Word\Addins\namespace.namespace]
    "Description"="Bschreibung"
    "FriendlyName"="Angezeigter Name des AddIns im Office"
    "LoadBehavior"=dword:00000003

    Die rot markierten Textteile müssen dann noch passend ersetzt werden.

  4. Das Add-in hat einen sehr einfachen Code.
  5. using System;
    using System.Text;
    using System.Reflection;
    using Extensibility;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    namespace LAG.WordPlus.OfficeAddIns.Word2002
    {
    	public class Word2002 : Object, Extensibility.IDTExtensibility2
    	{
    		#region IDTExtensibility2 Member
    
    		public void OnAddInsUpdate(ref Array custom)
    		{
    		}
    
    		public void OnBeginShutdown(ref Array custom)
    		{
    
    		}
    
    		public void OnConnection(object Application, ext_ConnectMode ConnectMode, object AddInInst, ref Array custom)
    		{
    			MessageBox.Show("OnConnection -- Hallo :-)");
    		}
    
    		public void OnDisconnection(ext_DisconnectMode RemoveMode, ref Array custom)
    		{
    			MessageBox.Show("OnDisconnection -- ByBy :-)");
    		}
    
    		public void OnStartupComplete(ref Array custom)
    		{
    			MessageBox.Show("OnStartupComplete -- TippTopp :-)");
    		}
    		#endregion
    	}
    }
  6. Dann besorgt man sich folgenden VS2005-KB908002-ENU-x86.EXE fix. Die Thematik des KB interessiert nicht wirklich. Dort drin gibt es eine ganz bestimmtes MSI Packet.
  7. Man führt die EXE aus. Im Ordner C:\Programme\Microsoft Visual Studio 8\SDK\v2.0\BootStrapper\Packages\KB908002 findet man nun die Datei extensibilityMSM.msi. Und die ist für dieses Problem Gold wert. Ich habe leider keinen anderen Weg gefunden wie man an das MSI kommt.
  8. Auf dem Zielsystem führt man nun das extensibilityMSM.msi aus und anschliessend noch das eigene Setup. 

Danach müsste ein Dialog erscheinen der etwa so aussieht.

image

Es kann aber noch 1000 andere Gründe geben.

– Sind die nötigen .NET Versionen installiert?

– Sind die Office CP/2002 PIA’s installiert?

Jedenfalls habe ich jetzt endlich einen Weg gefunden wie ich das Add-in lauffähig bringe.

VSTO – Probleme mit Zeilenumbrüchen

 Entwicklung  Kommentare deaktiviert für VSTO – Probleme mit Zeilenumbrüchen
Nov 182008
 

Es kann durchaus sein, dass in einer Anwendung (WordPlus) ein solcher Dialog auftaucht.

image

Dargestellt werden die eingegebenen Daten so:

image

Hier wird also ein Zeilenumbruch eingefügt. Das macht man in der Regel mit Environment.NewLine;.

Diese Adresse wird jetzt dem Word oder Excel übergeben. Das kann dann so aussehen.

image

Was mich jetzt aber am meisten erstaunt ist die Tatsache, dass es bei einem DOCPROPERTY richtig aussieht und bei einer DOCVARIABLE nicht. Dort gibt es für den Zeilenumbruch ganz spezielle Sonderzeichen.

image

Das selbe kenne ich noch von gewissen Feldern im Excel. Wenn das auftritt, dann macht man einfach ein Replace("\r\n", "\r"); auf den String den man nutzen will. Und schon sieht es wieder normal aus.

image

Was Microsoft hier wohl überlegt hat?

Die Assembly Irgendwas, Version=4 … kann nicht gefunden werden.

 Entwicklung, Software  Kommentare deaktiviert für Die Assembly Irgendwas, Version=4 … kann nicht gefunden werden.
Okt 082008
 

Wie oft habe ich nun diese Fehlermeldung schon bekommen. Es ist unglaublich.

Ich portiere zur Zeit ein Office 2003/2007 Add-In, dass mit VSTO entwickelt wurde, nach Office 2002/XP. Dort ist nicht mehr die VSTO aktuell sondern die PIA’s (Primary Interop Assemblies) für Office XP. Im grossen und ganzen wird das Add-In einfach anders geladen. Vor allem darf man mit dem Extensibility.IDTExtensibility2 Interface arbeiten. Den restlichen Code kann man 1 zu 1 übernehmen.

Das Add-In wird im Office als ganz normales COM Add-In registriert und auch als solches behandelt. Genau das verursacht nun diverse Probleme die umschifft werden müssen.

Die .NET Laufzeit sucht in dieser Konstellation die diversen beteiligten Verweise im Ausführungsverzeichnis von der startenden Office-Anwendung. Das ist dann meist im Ordner “C:\Programme\Microsoft Office\Office10”. Dort sind die Assemblies aber nicht vorhanden. Was kann man dagegen tun?

Zum Beispiel hilft diese Datei, die man genau in den besagten Order tut, bei Word schon einiges. Die Datei heisst WINWORD.EXE.config und hat folgenden Inhalt.

<?xml version="1.0"?>
<configuration>
    <startup>
        <supportedRuntime version="v2.0.50727"/>
    </startup>
</configuration>

Das erleichtert einem schon einiges. Die Standard-Assemblies werden so gefunden.

Aber beim BinaryFormatter greift auch das nicht. Hier muss man es anders Lösen.

licenses = (LicenseCollection)formatter.Deserialize(licensestream);

Hier kommt die Meldung, dass die Assembly für den Typ LicenseCollection nicht gefunden werden kann. Das ist dann natürlich sehr ärgerlich.

Hier habe ich dann die Lösung gefunden.

private static void InitializeLicenses()
{
	ResolveEventHandler loadComponentAssembly = new ResolveEventHandler(LoadComponentAssembly);
	AppDomain.CurrentDomain.AssemblyResolve += loadComponentAssembly;

    licenses = new LicenseCollection();

	string licensefilename = 
		Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.
		GetExecutingAssembly().CodeBase), 
		"license.dat").Replace(@"file:\", "");

    if(File.Exists(licensefilename))
    {
		try
		{
			FileStream licensestream = 
				new FileStream(licensefilename, FileMode.Open, FileAccess.Read);
			BinaryFormatter formatter = 
				new BinaryFormatter();

			formatter.AssemblyFormat = 
				System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;

			licenses = (LicenseCollection)formatter.Deserialize(licensestream);
			licensestream.Close();
		}
		catch (Exception ex)
		{}
		finally
		{
			AppDomain.CurrentDomain.AssemblyResolve -= loadComponentAssembly;
		}
    }
    else
    {
        ErrorHandler.LogInfo(1000, "License not found!");
    }
}

static Assembly LoadComponentAssembly(Object sender, ResolveEventArgs args)
{
	string simpleName = args.Name.Substring(0, args.Name.IndexOf(','));
	string assemblyPath = simpleName + ".dll";
	return Assembly.LoadFrom(Path.Combine
				(Path.GetDirectoryName
				(System.Reflection.Assembly.GetExecutingAssembly().CodeBase), 
				assemblyPath).Replace(@"file:\", ""));
}

So wird die Assembly gefunden.

Und wieder ein Problem weniger. Ab zum nächsten. 🙂

VSTO – Seit SP1 für VS2008 – Schwanzbeisser Fehler

 Entwicklung, Software  Kommentare deaktiviert für VSTO – Seit SP1 für VS2008 – Schwanzbeisser Fehler
Aug 142008
 

Seit ich das SP1 für Visual Studio 2008 installiert habe zeigt mir die Entwicklungsumgebung einen eigenartigen Fehler an.

image

image

Den zweiten Parameter kann man nicht als ref übergeben. War früher sicher nicht so.

Nimmt man das ref raus sieht es so aus.

image

image

Ja was nun? Mit ref oder nicht?

Aber die erste Version, die mit ref, kann man wenigstens erstellen.

Tags: , ,

VSTO – Transparente Icon’s in den Menüs

 Entwicklung, Software  Kommentare deaktiviert für VSTO – Transparente Icon’s in den Menüs
Aug 142008
 

Ich glaube jeder ist mit mir einig, wenn ich sage, dass hier sieht hässlich aus.

Icons im Menü ohne Transparenz.

Mit VSTO ist es jetzt aber gar nicht mal so einfach transparente Icon’s zu bekommen.

Ein Icon wird einem CommandBarButton (cbc) wie folgt hinzugefügt.

if (item.Icon.Length > 0)
{
	stdole.IPictureDisp pic = GetImage(item.Icon);

	if (pic != null)
	{
		cbc.Picture = pic;
	}
}

GetImage sieht so aus.

private stdole.IPictureDisp GetImage(string imageName)
{
	stdole.IPictureDisp pic = null;
	string file = Path.Combine(iconPath, imageName);
	if (File.Exists(file))
	{
		try
		{
			pic = PictureConverter.
				ImageToPictureDisp(Image.FromFile(file));
		}
		catch (Exception ex)
		{
			//Hier Fehler
		}
	}
	return pic;
}

Und der PictureConverter ist eine eigene Klasse. Findet man überall im Inet.

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

namespace LAG.WordPlus.OfficeAddIns.Word2003
{
	public class PictureConverter : AxHost
	{
		public PictureConverter() : base(string.Empty)
		{
		}
		public static stdole.IPictureDisp ImageToPictureDisp(Image image)
		{
			return (stdole.IPictureDisp)GetIPictureDispFromPicture(image);
		}
		public static stdole.IPictureDisp IconToPictureDisp(Icon icon)
		{
			return ImageToPictureDisp(icon.ToBitmap());
		}
		public static Image PictureDispToImage(stdole.IPictureDisp picture)
		{
			return GetPictureFromIPicture(picture);
		}
	}
}

Wie macht man nun die Icon’s transparent?

Man erweitere das erste Codesnippet um die Zeile 7.

if (item.Icon.Length > 0)
{
	stdole.IPictureDisp pic = GetImage(item.Icon);
	if (pic != null)
	{
		cbc.Picture = pic;
		SetImage(cbc, item.Icon);
	}
}

Der Code für SetImage sieht so aus.

private void SetImage(CommandBarButton button, string icon)
{
	try
	{
		Bitmap bmp = new Bitmap(Path.Combine(iconPath, icon));
		IntPtr Hicon = bmp.GetHicon();
		Icon newIcon = Icon.FromHandle(Hicon);

		ImageList newImageList = new ImageList();
		newImageList.ColorDepth = ColorDepth.Depth8Bit;
		newImageList.ImageSize = new Size(16, 16);
		newImageList.Images.Add(newIcon);

		button.Picture = PictureConverter.
				ImageToPictureDisp(newImageList.Images[0]);
		Bitmap mask = (Bitmap)newImageList.Images[0].Clone();

		for (int x = 0; x < 16; x++)
		{
			for (int y = 0; y < 16; y++)
			{
				mask.SetPixel(x, y, (mask.GetPixel(x, y) 
					== Color.Transparent
					|| mask.GetPixel(x, y).Name == "0") 
					? Color.White : Color.Black);
			}
		}
		button.Mask = PictureConverter.ImageToPictureDisp(mask);
	}
	catch (Exception ex)
	{
		//Fehlerbehandlung
	}
}

Das Ergebnis sieht dann so aus.

Icons im Menü mit Transparenz.

Viel besser. Oder?

VSTO – Formatting Codes im Header und Footer

 Entwicklung  Kommentare deaktiviert für VSTO – Formatting Codes im Header und Footer
Jul 302008
 

Bei unserem Tool WordPlus muss ich im Excel die Definitionen
vom Header und Footer wegspeichern damit man sie wieder
rekonstruieren kann.

In den Feldern vom Header oder Footer kann man Platzhalter definieren
die danach mit den entsprechenden Werten ersetzt werden.
Damit man die Felder auch updaten kann muss ich wissen wie die Definition ursprünglich
ausgesehen hat.

Im deutschen Excel wird ein Bild mit dem Platzhalter &[Grafik] im
Header angezeigt.

Wenn ich jetzt den Header z.B. mit workSheet.PageSetup.CenterHeader
auslese ist es nicht mehr &[Grafik] sondern &I.

Bei der Rekonstruktion des Header’s schreibe ich jetzt &I zurück.

Im deutschen Excel ist das aber der Code um Text italic anzuzeigen.
Ich müsste ja aber das Bild anzeigen.

Das war ein kleineres Problem.

Aber Dank Frank Dzaebel war die Lösung dann doch einfach.

CultureInfo oldCulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");

//Arbeiten am Header oder Footer

Thread.CurrentThread.CurrentCulture = oldCulture;

Alle arbeiten am Header oder Footer werden zwischen den Zeilen 2 und 6
gemacht. Somit kommen immer die selben Codes in die Felder und alles klappt
wie gewünscht.

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. 🙂

VSTO – Word – Cursor am Ende oder Start des Dokumentes platzieren

 Entwicklung  Kommentare deaktiviert für VSTO – Word – Cursor am Ende oder Start des Dokumentes platzieren
Jun 232008
 

Etwas, was ich auch immer wieder gebraucht habe.

Ich musste den Cursor an den Anfang des Dokumentes platzieren.

Geht so.

Object unit = Word.WdUnits.wdStory;
Object extend = Word.WdMovementType.wdMove;
ThisApplication.Selection.HomeKey(ref unit, ref extend);

Ans ende des Dokumentes:

unit = Word.WdUnits.wdStory;
extend = Word.WdMovementType.wdExtend;
ThisApplication.Selection.EndKey(ref unit, ref extend);

Genaueres findet man hier.

Tags: ,