Autor Beitrag
reeny
Hält's aus hier
Beiträge: 2



BeitragVerfasst: Fr 30.11.07 09:49 
Hallo Helfende!

Ich habe für das kostenlose UML-Programm "StarUML" ein Addin in C# programmiert. Auf deren Homepage befindet sich eine mehr oder weniger gute Anleitung zur Programmierung eines solchen Addins. Da ich aber noch nicht so viel Erfahrung mit CSharp, COM-Objekte, DLLs oder .Net habe, bin ich auf Schwierigkeiten gestoßen.

Der Plan:
Das Addin soll aus einer Datei mit XML-Formatierung (muss nicht lokal auf dem Rechner liegen) einen Wert auslesen, diesen mit dem Wert aus einer lokal liegenden Datei vergleichen und dann ggf. die lokale Datei ersetzen.
Dieses Addin habe ich als DLL exportiert und dann einfach in den dafür verwendeten Ordner des StarUML Programms kopiert.

Der aktuelle Stand:
Bei meinem Rechner funktioniert das Einbinden der DLL in das StarUML Programm. Wenn ich die DLL allerdings auf andere Rechner kopiere, schlägt das Einbinden fehl.

Ich versteh nicht ganz, warum und wie ich an die Problemlösung heran gehen soll.

Die Beschreibung des Addin-Programmierens findet man auf staruml.sourceforge....-guide(en)/ch09.html.
Dort steht unter anderem
Zitat:
The most important point about implementing StarUML Add-In COM Objects is that the IStarUMLAddIn interface defined by StarUML must be used.

und
Zitat:
... defines the three additional interface methods: InitializeAddIn(), FinalizeAddIn(), and DoMenuAction()


Meine Lösung sieht dabei so aus:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Text;
using System.Xml;
using System.IO;
using StarUML;

namespace ProfileUpdate
{

    [ClassInterface(ClassInterfaceType.AutoDual)]
    [Guid("000214FB-0000-0000-C000-000000000046")]
    public class ProfileUpdate : IStarUMLAddIn
    {

        private static IStarUMLApplication _starumlapp;

        public void DoMenuAction(int ActionID)
        {
            _starumlapp.Log("MENU-ACTION=" + ActionID);

            if (ActionID == 1) {
                try
                {
                    updateProfile();
                }
                catch (Exception e)
                {
                    _starumlapp.Log("Fehler: "+e.Message);
                }
            }
        }

        public void FinalizeAddIn()
        {
            _starumlapp.Log("### stop profile update ...");
            Marshal.ReleaseComObject(_starumlapp);
        }

        public void InitializeAddIn()
        {
            _starumlapp = new StarUMLApplicationClass();
        }

        public void updateProfile()
        {
            String startup_path = AppDomain.CurrentDomain.BaseDirectory;

            String localxmlfilepath = Path.Combine(startup_path,"modules\\atacama-profile\\profiles\\atacamaprofile\\atacamaprofile.prf");
            String remotexmlfilepath = _starumlapp.GetOptionValue("oaw-addin-settings""update_from_filepath").ToString()+"\\atacamaprofile.prf";

            try
            {
                _starumlapp.Log("read local prf-file: " + localxmlfilepath);

                if (!File.Exists(localxmlfilepath))
                {
                    _starumlapp.AddMessageItem(InformationMessageKind.mkGeneral, "file does not exist ...", _starumlapp.GetProject());
                    _starumlapp.Log("local file does not exist ...");
                    return;
                }
                _starumlapp.Log("read local version ...");
                String local_version = read_profile_version(localxmlfilepath);
                if (local_version == null)
                {
                    _starumlapp.Log("local version unknown - update stopped");
                    return;
                }

                _starumlapp.Log("read remote prf-file: " + remotexmlfilepath);
                if (!File.Exists(remotexmlfilepath))
                {
                    _starumlapp.AddMessageItem(InformationMessageKind.mkGeneral, "file does not exist ...", _starumlapp.GetProject());
                    _starumlapp.Log("remote file does not exist ...");
                    return;
                }
                _starumlapp.Log("read remote version ...");
                String remote_version = read_profile_version(remotexmlfilepath);
                if (remote_version == null)
                {
                    _starumlapp.Log("remote version unknown - update stopped");
                    return;
                }


                if (remote_version.CompareTo(local_version) > 0)
                {
                    _starumlapp.Log("found a newer profile version");
                    DialogResult do_continue = MessageBox.Show("Es wurde eine Version des atacama-Profils gefunden, die aktueller als die lokal installierte Version ist.\nWollen Sie die neue Version herunterladen (alte Daten werden überschrieben)?""Aktuellere Version gefunden", MessageBoxButtons.YesNo);
                    
                    if (do_continue == DialogResult.Yes)
                    {
                        FileInfo local_prf_info = new FileInfo(localxmlfilepath);
                        FileInfo remote_prf_info = new FileInfo(remotexmlfilepath);

                        DirectoryInfo local_profile_root = local_prf_info.Directory.Parent.Parent;
                        DirectoryInfo remote_profile_root = remote_prf_info.Directory.Parent.Parent;

                        // neuere Profile-Dateien ins lokales Verzeichnis kopieren
                        copyDirectory(remote_profile_root, local_profile_root, true);


                        MessageBox.Show("Das aktuelle Profil wurde heruntergeladen.\nErst durch ein Neustart von StarUML werden die Änderungen übernommen.""Kopiervorgang erfolgreich");
                    }
                    else
                    {
                        return;
                    }
                }
                else
                {
                    MessageBox.Show("Es wurde keine Version des atacama-Profils gefunden, die aktueller als die lokal installierte Version ist.""Keine aktuellere Version gefunden");
                    return;
                }

            }
            catch (Exception exc)
            {
                _starumlapp.Log("error while updating: " + exc);
            }

        }

        private String read_profile_version(String path)
        {
            XmlDocument xmldoc = new XmlDocument();
            xmldoc.Load(path);
           
            XmlNodeList nodes = xmldoc.GetElementsByTagName("PROFILE");
            
            if (nodes.Count == 0)
            {
                _starumlapp.Log("xml node 'PROFILE' not found");
                return null;
            }

            XmlNode prfnode = nodes[0];
            XmlAttributeCollection atts = prfnode.Attributes;
            XmlAttribute curattr;
            for (int i = 0; i < atts.Count; i++)
            {
                curattr = atts[i];
               
                if (curattr.Name.Equals("version"))
                {
                    _starumlapp.Log("found version: " + curattr.Value);
                    return curattr.Value.Trim();
                }
            }
            
            _starumlapp.Log("xml attribute 'version' for node 'PROFILE' not found");
            return null;
        }

        private static void copyDirectory(DirectoryInfo srcpath, DirectoryInfo destpath, bool recursive)
        {
            _starumlapp.Log("copy " + srcpath.FullName + " to " + destpath);
            if (!destpath.Exists)
                return;

            // erst alle Dateien im Verzeichnis kopieren
            foreach (FileInfo fi in srcpath.GetFiles())
            {
                _starumlapp.Log("  -> copy " + fi.FullName + " to " + Path.Combine(destpath.FullName, fi.Name));
                fi.CopyTo(Path.Combine(destpath.FullName, fi.Name), true); 
            }

            // dann ggf. alle Unterverzeichnisse kopieren
            if (recursive)
            {
                foreach (DirectoryInfo di in srcpath.GetDirectories())
                {
                    copyDirectory(di, new DirectoryInfo(Path.Combine(destpath.FullName, di.Name)), true);
                }
            }
        }
    }
}



Ich weiß nicht:
- ob das "[ClassInterface(ClassInterfaceType.AutoDual)]" richtig ist (oder was es überhaupt tut ... :? )
- welche Einstellungen ich für das Assembly machen soll (Microsoft Visual Studio 8 )
- ob ich was in der Registry registrieren muss und wenn ja, was

Beim Erstellen des Builds kommen drei Dateien raus (in \Workspace\profile-update\profile-update\bin\Release\), die ich in das entsprechende Programmverzeichnis kopiere:
- Interop.StarUML.dll
- ProfileUpdate.dll
- ProfileUpdate.tlb

Wenn das Addin richtig geladen wird, wird im StarUML die Meldung "Add-In 'oaw' is loaded successfully." ausgegeben und ein zusätzliches Menü ist sichtbar. Bei anderen Rechnern kommt die Fehlermeldung "Failed to load Addin 'oaw'".

Bitte um Hilfe:
Habt ihr vielleicht einen Ansatz, woran das liegen könnte? Hat das was mit der Registry zu tun? Habe ich überhaupt ein richtiges COM-Objekt programmiert? Funktioniert es bei mir nur, weil ich das Microsoft Visual Studio 8 drauf habe?

Ihr könnt das gerne bei euch ausprobieren! StarUML ist kostenlos unter staruml.sourceforge.net/en/download.php zu bekommen. Bitte bitte helft mir, das Teil auch bei anderen Rechnern zum Laufen zu bringen.


-= Reeny =-


PS: Bevor ihr den Vorschlag macht, gebe ich gleich mal die Antwort vorweg: Ich kann die Frage nicht wirklich im StarUML-Forum stellen, da das Projekt tot zu sein scheint. In deren Forum wird auch nicht gerne geantwortet ...
reeny Threadstarter
Hält's aus hier
Beiträge: 2



BeitragVerfasst: Mi 05.12.07 09:28 
Ich hab es selbst rausgefunden:

Als ich meine Registry-Einträge mit den der anderen Rechner verglichen hatte, habe ich festgestellt, dass den anderen der Eintrag "CodeBase" zum COM-Objekt fehlte. Dieser verweist auf die DLL, in der der Code zum COM-Objekt zu finden ist. Irgendwie lässt sich dieser Eintrag nicht automatisch mit RegAsm erzeugen. Aber das ist trotzdem kein großes Problem.


-= reeny =-