Dienstag, 18. Dezember 2007

ADO.NET Timeout

Aufwändige Abfrage


Wird aus einer .Net Applikation per ADO.NET eine aufwändige Abfrage an einen SQL-Server abgesetzt, kann es zu folgender Fehlermeldung kommen, wenn das Ergebnis nicht rechtzeitig geliefert wird:

"The timeout period elapsed prior to completion of the operation or the server is not responding."

Connect Timeout im ConnectionString


Im ConnectionString kann ein längerer Zeitraum festgelegt werden (z.B.: server=myServer;uid=myUser;pwd=myPassword;database=myDatabase;Connect Timeout=60)

Hinweis


Unter http://www.dotnet247.com/247reference/msgs/57/289664.aspx bin ich auf den interessanten Hinweis gestossen, dass die Zeitangabe mindestens bedeutet, nicht höchstens.

CommandTimeout


Das Connection-Timeout anzupassen ist nicht genug.
Beim SqlCommand-Objekt ist noch das Property CommandTimeout auf die gewünschte Anzahl Sekunden zu setzen (z.B.: cmd.CommandTimeout=100;).

Diese Lösung stammt von http://www.eggheadcafe.com/PrintSearchContent.asp?LINKID=357.

Sonntag, 16. Dezember 2007

Visual Studio 2008 Solution in VS 2005 öffnen

Wenn man eine Visual Studio Solution, die mit VS 2005 erstellt wurde, in VS 2008 öffnet, wird automatisch ein Assistent zum konvertieren der Solution gestartet.

Will man diese Solution dann wieder in VS 2005 öffnen, weigert sich dieses.

Da VS 2008 wahlweise auch für .Net 2.0 verwendet werden kann, sollte nichts dagegen sprechen daran mit VS 2005 weiterzuarbeiten.

Ich war in der Situation, dass eine Applikation die ich mit VS 2008 begonnen habe, von jemandem, dem nur VS 2005 zur Verfügung stand, weiter entwickelt werden sollte.

Der Vergleich einer VS 2005- und einer VS 2008-Solution-Datei hat keine wesentlichen Unterschiede feststellen lassen.

So sehen die ersten beide Zeilen einer Solution-Datei aus VS 2008 aus:

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008


Nach dem ändern von
... Format Version 10.00
auf
... Format Version 9.00
und
# Visual Studio 2008
auf
#Visual Studio 2005
lässt sich die Solution in VS 2005 wieder öffnen.

Montag, 10. Dezember 2007

Entity Framework Beta 3 unter Vista x64 installieren

ADO.NET Entity Framework wird für x86 und x64 zum Download angeboten, die Tools nur für x86.

Es lassen sich auch die Tools unter Windows Vista x64 installieren und scheinen soweit problemlos zu funktionieren.

Für die Tools wird vorausgesetzt, dass der XML Editor QFE istalliert ist.

Nachfolgend die Links zum Download in der Reihenfolge wie sie installiert werden müssen:

  1. ADO.NET Entity Framework Beta 3 (x86 und x64)
  2. XML Editor QFE (x86)
  3. ADO.Net Entity Framework Tools Dec 07 Community Technology Preview (x86)
Weitere interessante Links zum Entity Framework:

Attach einer Datenbank funktioniert unter Windows Vista nicht.

Wieder hat Vista's UAC hier seine Finger im Spiel.

Umgehen lässt sich das Problem indem man dem Benutzer, unter dem das Management Studio gestartet wurde, Vollzugriff auf das Verzeichnis mit den Datenbankdateien gewährt.

Unter Windows Vista schlägt die Installation von MS SQL Server Management Studio Express fehl: Error 29506

Fehlermeldung
Wenn unter Windows Vista die Installation des Management Studio Express mit obiger Fehlermeldung abbricht, liegt es an Vista's UAC

Das Problem kann umgangen werden, indem die Installation über einen Command Prompt mit Administratorenrechten startet.

Command  Prompt mit Administratorrechten
Im Command Prompt einfach die Installationsdatei (z.B.: c:\Download\SQLServer2005_SSMSEE_x64.msi) ausführen. Damit sollte es funktionieren.

Freitag, 7. Dezember 2007

In Firefox gespeicherte Passwörter übertragen

Mein Notebook hat eine neue Harddisk verpasst bekommen :-)

Nach einem halben Jahr ist es sowieso höchste Zeit Windows neu aufzusetzen, daher habe ich nicht die bestehende Installation auf die neue HD übertragen, sondern Windows Vista (x64) frisch aufgesetzt.

Die im Firefox gespeicherten Passwörter wollte ich nicht neu erfassen sondern direkt übernehmen.

Die alte HD wurde in ein externes Gehäuse gesteckt und als Laufwerk I: gemounted.

Um die Passwörter zu übertragen sind zwei Dateien zu kopieren (Firefox vorher beenden):

I:\Dokumente und Einstellungen\MeinWindowsUserName\Anwendungsdaten\Mozilla\Firefox\Profiles\9x399sre.default\key3.db
sowie
I:\Dokumente und Einstellungen\MeinWindowsUserName\Anwendungsdaten\Mozilla\Firefox\Profiles\9x399sre.default\signons2.txt

in das Verzeichnis
C:\Users\MeinWindowsUserName\AppData\Roaming\Mozilla\Firefox\Profiles\sb459zt1.default

Wer schlau genug ist und vor dem Ausbauen der alten HD daran denkt, dass er die Firefox-Konfiguation übernehmen will, kann sich die Arbeit erleichtern indem er z.B. das Firefox-Add-In Firefox Environment Backup Extension installiert und damit die gesamte Firefox-Konfiguration sichert.

Sonntag, 25. November 2007

Tastaturereignisse in Silverlight Alpha 1.1

Mich interessiert viel mehr ob und wie man LOB-Applikationen mit Silverlight realisieren kann, als toll designte Multimediale Seiten oder Spiele.
Dabei fällt zuallererst auf, dass dafür keine Eingabe-Controls zur Verfügung stehen (die aber mit der Beta-Version von Silverlight 1.1 geliefert werden sollen).

Für einen Softwareentwickler sollte das kein Problem darstellen.
Ich versuche mich also an einer TextBox für Silverlight.

Bereits mehrfach bin ich auf den Hinweis gestossen, dass Spiele die mit Silverlight realisiert wurden, nicht die Cursurtasten für die Steuerung verwenden da diese kein KeyDown-Event liefern. Nachdem auch eine TextBox intensiv von Tastaturereignissen gebrauch macht ;-) habe ich diesen Aspekt zuerst untersucht.

Es stimmt, Silverlight liefert einige Tastaturereignisse nicht.
Aber es gibt Abhilfe - die fehlenden Ereignisse kann man sich einfach vom Browser liefern lassen.

In CreateSilverlight.js werden die Tastaturereignisse registriert und beim Auftreten an das Silverlight-Plugin weitergereicht:

   1 var sl_Sender;
2 var sl_Plugin;
3 var sl_PluginHost;
4 var sl_Context;
5
6 //contains calls to silverlight.js, example below loads Page.xaml
7 function createSilverlight()
8 {
9 Silverlight.createObjectEx({
10 source: "Page.xaml",
11 parentElement: document.getElementById("SilverlightControlHost"),
12 id: "SilverlightControl",
13 properties: {
14 width: "100%",
15 height: "100%",
16 version: "1.1",
17 enableHtmlAccess: "true"
18 },
19 events: {
20 onError:null,
21 onLoad:sl_OnLoad
22 }
23 });
24
25
26 // Give the keyboard focus to the Silverlight control by default
27 document.body.onload = function() {
28 var silverlightControl = document.getElementById('SilverlightControl');
29
30 if (silverlightControl)
31 silverlightControl.focus();
32 }
33
34
35 //onkeypress doesn't work in IE (7?) if Silverlight has focus
36 document.onkeypress = function(evt) {
37 var charCode = 0;
38
39 evt = (evt) ? evt : ((event) ? event : null);
40
41 if (evt)
42 charCode = evt.charCode; // || evt.keyCode;
43
44 return sl_Plugin.Content.smRootCanvas.DoHostKeyPress(charCode);
45 }
46
47 document.onkeydown = function(evt) {
48 var keyCode = 0;
49
50 evt = (evt) ? evt : ((event) ? event : null);
51
52 if (evt)
53 keyCode = evt.keyCode;
54
55 // returning bool from [Scriptable] doesnt work properly so int is used instead
56 return (sl_Plugin.Content.smRootCanvas.DoHostKeyDown(keyCode) != 0);
57 }
58
59 document.onkeyup = function(evt) {
60 var keyCode = 0;
61
62 evt = (evt) ? evt : ((event) ? event : null);
63
64 if (evt)
65 keyCode = evt.keyCode;
66
67 // returning bool from [Scriptable] doesnt work properly so int is used instead
68 return (sl_Plugin.Content.smRootCanvas.DoHostKeyUp(keyCode) != 0);
69 }
70 }
71
72 function sl_OnLoad(plugin, userContext, sender)
73 {
74 //alert(plugin.id + " : " + userContext + " : " + sender.toString());
75 sl_Sender = sender;
76 sl_Plugin = sender.getHost();
77 sl_PluginHost = plugin;
78 sl_Context = userContext;
79
80 if (plugin)
81 plugin.focus();
82 }

Ein Custom Control in Silverlight kann die Tastaturereignisse empfangen und verarbeiten:

   1 namespace SaveMethod.Silverlight.Controls
2 {
3 [Scriptable]
4 public class SmCanvas : System.Windows.Controls.Canvas
5 {
6 [Scriptable]
7 public int DoHostKeyPress(int keyCode)
8 {
9 System.Diagnostics.Debug.WriteLine(String.Format("HostKeyPress - keyCode: {0}", keyCode));
10
11 // process keyboard events here ...
12
13
14 return Convert.ToInt32(!AbsorbKey(e.HostKey));
15 // AbsorbKey is a custom method (not presented here)
16 // to decide if the event should be handled back to the browser for further processing outside Silverlight
17 // returning 0 disables and 1 enables further event processing
18 }
19
20 [Scriptable]
21 public int DoHostKeyDown(int keyCode)
22 {
23 // process keyboard events here ...
24 }
25
26 [Scriptable]
27 public int DoHostKeyUp(int keyCode)
28 {
29 // process keyboard events here ...
30 }
31 }
32 }

Das Scriptable Attribut für die Klasse und die Methode macht die Methode für JavaScript aufrufbar.

Das "Schlucken" des Ereignisses durch einen Returnwert 0 ist besonders für die Tab-Taste interessant, denn wenn auch der Browser das Ereignis verarbeitet, wird der Cursor in die Adressleiste (IE7) gesetzt. Das ist bei Dateneingabeformularen kaum gewünscht.

In diesem custom Control kann man die empfangenen Tastaturereignisse per C# Events weiteren Controls zum Abonnement anbieten.

  • Ist dieser Beitrag hilfreich?

  • Fehlen Informationen?

  • Kann man das besser, einfacher, kürzer, ... lösen?


Schreibe einen Kommentar um diesen Beitrag noch nützlicher zu machen.

Sonntag, 18. November 2007

Silverlight 1.1 Alpha mit ASP.NET

Um in einem Silverlight-Projekt JavaScript debuggen zu können habe ich folgende Lösung zusammengebaut:

Ausgangspunkt ist eine neue Solution (VS2008 Beta2), in die ein Silverlight-Projekt "SilverlightApp" und ein ASP.NET Projekt "SilverlightWeb" eingefügt wurden.

In SilverlightWeb habe ich einen neuen Ordner "js" hinzugefügt in das ich die Dateien Silverlight.js sowie TestPage.html.js (als CreateSilverlight.js) aus SilverlightApp kopiert habe.

Den Inhalt aus TestPage.html (SilverlightApp) habe ich in in Default.aspx kopiert, wobei die erste Zeile

"<%@ Page Language="C#" ..."
in Default.aspx bestehen bleibt und der Rest durch den Inhalt aus TestPage.html ersetzt wird.

In Default.aspx sind zwei Zeilen entsprechend anzupassen

   1 <script type="text/javascript" src="js/Silverlight.js"></script>
2 <script type="text/javascript" src="js/CreateSilverlight.js"></script>

Damit die benötigten Dateien des SilverlightApp-Projektes in das SilverlightWeb-Projekt kopiert werden ist noch eine Verbindung herzustellen.
Über das Kontextmenü des SilverlightWeb-Projektes "Add Silverlight Link ..." aufrufen und SilverlightApp auswählen.

In den Properties des SilverlightWeb-Projektes Register "Web" kann der Debugger für Silverlight ein- und ausgeschaltet werden, da nur Script- *oder* Silverlight-debugging unterstützt wird.

JavaScript debugging mit Silverlight 1.1 Alpha

Möglicherweise habe ich etwas übersehen, aber ich schaffe es nicht in einem Silverlight Projekt JavaScript zu debuggen.

Breakpoints im Codebehind C#-Code funktionieren, aber Breakpoints im JavaScript-Code werden ignoriert.

Debuggen von JavaScript in ASP.NET-Seiten funktioniert problemlos.

Meine Schlussfolgerung: Es liegt daran, dass im Silverlight-Projekt eine .html-Seite verwendet wird und Debuggen damit nicht unterstützt wird.

Wie ich das Projekt umgebaut habe, damit alles über ASP.NET läuft erläutere ich in einem eigenen Blogpost: Silverlight 1.1 Alpha mit ASP.NET

Silverlight 1.1 Alpha scriptable Methode liefert true anstatt false

Bei meinen ersten Versuchen mit Silverlight (1.1 Alpha) bin ich auf folgenden Bug (?) gestoßen.

Die Methode

   1 [Scriptable]
2 public bool GiveMeFalse()
3 {
4 return false;
5 }

liefert beim ersten Aufruf mit

   1 alert(sl_Plugin.Content.smRootCanvas.GiveMeFalse());

true, bei allen weiteren Aufrufen dann aber den erwarteten Wert false.

Ich verwende als Workaround eine Methode die 0 bzw 1 als int zurückliefert, das funktioniert soweit.

JavaScript Syntax-Highlighting und Intellisense funktioniert in Visual Studio 2008 Beta 2 nicht

Ich verwende den Visual Studio 2008 Beta 2 und Team Foundation Server in der VirtualPC-Variante wie sie von Microsoft zum Download angeboten wird..

Das vielgepriesene Intellisense für JavaScript zeigt sich nicht und nicht mal mehr Syntaxhighlighting funktioniert - das kann nicht sein.

Hier gibts die Lösung Angus Logan's Blog

Dienstag, 30. Oktober 2007

Visual Studio Macro zum finden des aktuellen Dokuments im Solution-Explorer (Projektmappe)

Die Option "Track Active Item in Solution Explorer" (unter Tools/Options/Projekts and Solutions/) habe ich generell deaktiviert, da es mich nervös macht wenn beim wechseln zwischen geöffneten Dateien die Solution-Explorer Ansicht auf und ab springt.

Bei umfangreichen Solutions mit vielen Projekten und Ordnern kann es so gelegentlich schwierig werden herauszufinden in welchem Ordner die gerade bearbeitete Datei abgelegt ist.

Folgendes Visual Studio Macro (getestet unter VS 2005 und VS 2008 Beta2) öffnet im Solution Explorer den Ordner unter dem die angezeigte Datei abgelegt ist.

   1 Imports System
2 Imports EnvDTE
3 Imports EnvDTE80
4 Imports System.Diagnostics
5
6 Public Module FindFileInSolutionExplorer
7 Sub FindFileInSolutionExplorer()
8
9 Dim myDTE As EnvDTE80.DTE2 = DTE
10 'myDTE = DTE
11
12 myDTE.Solution.FindProjectItem(myDTE.ActiveDocument.FullName).ExpandView()
13
14 End Sub
15
16 End Module

Einfügen kann man das Macro mit der Macros IDE (Tools/Macros/Macros IDE oder Alt-F11). Im Project Explorer "Add Class" wählen und den Code hineinkopieren.

Noch schnell ein Symbol in der Taskleiste dafür erstellt und schon sollte es funktionieren.

Leider wird nur der Ordner geöffnet in dem die Datei liegt, die Datei aber nicht ausgewählt.
Nachdem man den richtigen Ordner gefunden hat sollte es aber nicht mehr schwierig sein die Datei zu finden.
Vielleicht komme ich noch dahinter wie sich dieses Manko ausmerzen lässt ...

Samstag, 20. Oktober 2007

Zweidimensionales Array in einer C++ COM-Komponente erzeugen und an VB/VBA zurückgeben

Ich habe den Code aus einer konkreten Anwendung herausgelöst und die Bezeichner verallgemeintert, das Ergebnis aber nicht getestet.
Womöglich habe ich den einen oder anderen Tippfehler oder ähnliches hinzugefügt ...

Ein Beispiel für SafeArrayGetElement() fehlt noch.
Bei Gelegenheit werde ich das nachzuholen.

   1 // MyCOM.idl
2 interface ICo4COM : IUnknown {
3 HRESULT GetArray([out,retval] SAFEARRAY(short)* arr);
4 }
5
6 // MyCOM.h
7 interface IMyCOM : public IUnknown {
8 virtual HRESULT __stdcall GetArray(SAFEARRAY(short)** arr) = 0;
9 }
10
11 // MyCom.cpp
12 class MyCOMImpl : public ICo4COM {
13 private;
14 SAFEARRAY* arr;
15 SAFEARRAYBOUND rgsabound[2];
16
17 ~Co4COMImpl() {
18 gObjCnt--;
19
20 if(arr != NULL)
21 {
22 SafeArrayDestroy(arr);
23 arr = NULL;
24 }
25 }
26
27 HRESULT __stdcall GetArray(SAFEARRAY** arr) {
28 *arr = this->arr;
29 return S_OK;
30 }
31
32 void AddElement(long x, long y, short val) {
33 long index[2];
34 index[0] = x;
35 index[1] = y;
36
37 short data = val;
38 SafeArrayPutElement(arr, index, &data);
39 }
40
41 long ArrayXCount() {
42 return long(rgsabound[0].cElements);
43 }
44
45 long ArrayYCount() {
46 return long(rgsabound[1].cElements);
47 }
48
49 bool InitArray(long sizeX, long sizeY) {
50 short data = 0;
51 long index[2];
52
53 rgsabound[0].lLbound = 0;
54 rgsabound[0].cElements = sizeX;
55 rgsabound[1].lLbound = 0;
56 rgsabound[1].cElements = sizeY;
57
58 if(arr != NULL)
59 SafeArrayDestroy(arr);
60
61 arr = SafeArrayCreate(VT_I2, 2, rgsabound); // array of short
62
63 if(arr == NULL) { //SafeArray create failed
64 return false;
65 }
66
67 // init with 0
68 for(long i = 0; i <>cols; i++) {
69 for(long j = 0; j <>rows; j++) {
70 index[0] = i;
71 index[1] = j;
72 data = 0;
73
74 SafeArrayPutElement(arr, index, &data);
75 }
76 }
77
78 return true;
79 }
80 }

Verstrichene Zeit in C++ unter Windows messen ...

hat mich einige Zeit gekostet eine Lösung zu finden.
Fündig wurde ich unter Get time in milliseconds in Windows

Nachfolgend ein Beispiel wie ich es konkret eingesetzt habe.

   1 ULONGLONG endCalculationAt;
2
3 ULONGLONG GetSystemTimeInMS() {
4 SYSTEMTIME systemTime;
5 GetSystemTime(&systemTime);
6
7 FILETIME fileTime;
8 SystemTimeToFileTime(&systemTime, &fileTime);
9
10 ULARGE_INTEGER uli;
11 uli.LowPart = fileTime.dwLowDateTime; // could use memcpy here!
12 uli.HighPart = fileTime.dwHighDateTime;
13
14 ULONGLONG systemTimeIn_ms(uli.QuadPart/10000);
15 return systemTimeIn_ms;
16 }
17
18 void InitCalculationTime() {
19 endCalculationAt = GetSystemTimeInMS() + (ULONGLONG)(10 * 1000); // ab jetzt 10 Sekunden Zeit
20 }
21
22
23 bool CheckCalculationTimeElapsed() {
24 if(GetSystemTimeInMS() >= endCalculationAt)
25 return true;
26 else
27 return false;
28 }

Buttons dynamisch zur Laufzeit hinzufügen ist in Excel leicht realisiert, aber ...

wie bringt man diese Buttons dazu dass ein Klick darauf etwas sinnvolles macht?

Eine Variante, die ich im Netz gefunden habe, ist entsprechende Ereignisprozeduren dynamisch zu erzeugen.
Eine weitere gefundene Variante die mir besser gefällt habe ich nachfolgend zusammengefasst.

[hinzugefügt am 2008-11-18 12:15]
Ein vollständiges lauffähiges Beispiel steht unter diesem Link zum Download bereit.
Die Codeteile sind im VBA-Editor unter "Diese Arbeitsmappe", "DynamicButtonSheet (Tabelle1)" und im Klassenmodul "ButtonObject" zu finden.

Nachfolgend die wichtigsten Codeteile mit einigen Anmerkungen:
[hinzugefügt bis hier]

Folgendes Klassen-Modul wird benötigt.

   1 Option Explicit
2
3 Public WithEvents ButtonObject As MSForms.CommandButton
4
5 Public btnName As String
6 Public btnId As Integer
7
8 Private Sub ButtonObject_Click()
9 Module1.MoveButton_Click btnId
10 End Sub

Der globalen Variable ButtonObject wird später der neu erstellt Button zugewiesen.
btnName und btnId sind Beispiele für zusätzliche Properties zur Identifikation welcher konkrete Butten gedrückt wurde.

ButtonObject_Click() ist die Ereignis-Prozedur die im Fall eines Button-Click aufgerufen wird.
Module1.MoveButton_Click btnId ist eine zentrale Prozedur in der die Button-Click-Ereignisse verarbeitet werden, an die der Aufruf weitergeleitet wird.

Es folgt ein Beispielcode wie die Buttons erstellt werden.

   1 Private Buttons As New Collection
2
3 Dim btnWidth as Integer
4 Dim btnHeight as Integer
5
6 btnWidth = 50
7 btnHeight = 25
8
9 For i = 0 To 10
10 Set btn = ws.OLEObjects.Add(ClassType:="Forms.CommandButton.1", Link:=False, DisplayAsIcon:=False, _
11 Left:= i * btnWidth, _
12 Top:= 200, Width:=btnWidth, Height:=btnHeight)
13 btn.Name = RT_PREFIX & "MoveButton" & i
14 btn.Object.Caption = "Button " & i
15 btn.Object.TakeFocusOnClick = False
16 Next i

Nach dem Erstellen der Buttons kommt ein kleiner Trick der Excel eine kurze Verschnaufpause verschafft damit es nicht außer Tritt kommt.

   1 Application.OnTime Time + TimeSerial(0, 0, 1), "Module1.prcAssign"

Damit wird die Prozedur prcAssign aus dem Module1 zeitversetzt aufgerufen.
prcAssign sieht folgendermaßen aus:

   1 Public Sub prcAssign()
2 Dim ws As Worksheet
3 Dim btn As OLEObject
4 Dim button As ButtonObject
5 Dim i As Integer
6
7 Set ws = ActiveWorkbook.Worksheets("Tabelle1")
8 i = 0
9
10 For Each btn In ws.OLEObjects
11 If Left(btn.Name, Len(RT_PREFIX)) = RT_PREFIX Then
12 Set button = New CButton
13 Set button.ButtonObject = btn.Object
14 button.Id = i
15 button.Name = RT_PREFIX & "Button" & i
16 Buttons.Add button
17
18 i = i + 1
19 End If
20 Next
21
22 End Sub

Beim Zuordnen eines Buttons in der beschriebenen Art an die ButtonObject Variable einer CButton Instanz wird automatisch die Ereignisprozedur ButtonObject_Click zugeordnet.

Freitag, 19. Oktober 2007

Globale Variablen in Excel verlieren ihren Wert

Ein bekanntes Problem scheint zu sein, dass Excel (ich hatte das Problem mit Excel 2003) während der Laufzeit aus verschiedenen Anlässen die Werte globaler Variablen "vergisst".

Lt. Informationen aus dem Web passiert das wenn

  • der Code neu compiliert wird
  • ein Laufzeitfehler auftritt
Wenn Änderungen am Code durchgeführt werden ist es nachvollziehbar, dass neu compiliert werden muss.
Die Werte gehen aber auch verloren wenn keine Änderungen gemacht wurden und keine Laufzeitfehler aufgetreten sind (ist mit "Unterbrechen bei Fehlern" auf "Bei jedem Fehler" gesetzt leicht überprüfbar).

In meinem Fall dürfte die Ursache daran gelegen sein, dass ich zur Laufzeit per Programmcode Buttons hinzugefügt und entfernt habe (siehe Beitrag Buttons dynamisch zur Laufzeit hinzufügen ist in Excel leicht realisiert, aber ...).
Dadurch entsteht die Notwendigkeit den Programmcode neu zu kompilieren und das führt zum hier beschriebenen Phänomen.

Nach langer erfolgloser Suche im Web bin ich auf folgende Lösung gekommen, die in meiner Situation das Problem gelöst hat

Ich habe eine neue leere Arbeitsmappe erstellt und in ein Codemodul folgenden Code eingefügt

   1 Option Explicit
2
3 Public Co4COMObj As SWK5_P1.Co4COM
4
5 Public Function Co4COM() As SWK5_P1.Co4COM
6 If Co4COMObj Is Nothing Then
7 Set Co4COMObj = New SWK5_P1.Co4COM
8 End If
9
10 Set Co4COM = Co4COMObj
11 End Function

und die Arbeitsmappe als "Microsoft Office Excel-Add-In (*.xla)" gespeichert.

Bei diesem Beispiel geht es darum, dass eine Instanz einer COM-Komponente (SWK5_P1.Co4COM) erstellt wird und diese über einen längeren Zeitraum verfügbar bleiben soll.

Nach dem Prinzip des Singleton-Patterns wird geprüft ob die Variable Co4COMObj schon zugwiesen wurde.
Wenn ja wird sofort eine Referenz zurückgeliefert andernfalls wird zuvor mit New eine neue Instanz zugewiesen.

In der Arbeitsmappe, in der die globale Variable verwendet wird, wird diese *.xla (in diesem Fall Co4COM.xla) über das "Menü Extras/Add-Ins..." eingebunden.

Eine Prozedur kapselt den Zugriff darauf:

   1 Public Function Co4COM() As SWK5_P1.Co4COM
2 ' to trick the damned Excel loosing the value of global variables occassionally,
3 ' the public variable holding the COM component was moved to an AddIn
4 Set Co4COM = Application.Run("Co4COM.xla!Co4COM")
5 End Function

Hieraus wird ersichtlich, dass der Zugriff auf die Prozedur im Add-In, die eine Referenz auf die gewünschte Variable zurückliefert, etwas umständlicher ist als gewohnt.

Es können meines Wissens auch keine Variablen im Add-In direkt angesprochen werden sondern es müssen entsprechende Getter- und Setter-Prozeduren bzw Functions bereitgestellt werden.