Laden...

Forenbeiträge von Andreas.May Ingesamt 915 Beiträge

15.02.2008 - 15:10 Uhr

Ups.. hatte das etwas anders aufgefasst mit dem Tool.exe /visible, hatte nicht gedacht das damit Übergabeparameter meinst.

norman_timo hat den Nagel auf den Kopf getroffen, in Main(string[] args) bekommst du deine übergabeparameter angezeigt und kannst entsprechend darauf reagieren. Über die Windowsnachrichten (WM_QUERYENDSESSION = &H11) kannst dann auf WindowsShutdown reagieren und dein Programm anständig beenden lassen. Denk auch über Mutex dann nach, damit dein Programm nicht mehrfach gestartet wird.

15.02.2008 - 14:36 Uhr

Hrm, da List<T> IList<T> implementiert einfach

  public class MyListClass : List<MyClass> { }

Und das wars 🙂

15.02.2008 - 14:32 Uhr

Das klingt ganz nach einer NotifyIcon oder besser gesagt SysTray Anwendung.
Auf der rechten Seite neben der Windowsuhr hast dann ein Symbol das z.B. durch anklicken mit der Maus ein ContextMenü öffnet und du diese Schalter dort umlegen kannst. Also Form.Hide und Form.Show.

Hier gibt es einen guten Beitrag dazu.

Mehr dazu findets du dann auch auf der MSDN Seite 🙂

15.02.2008 - 14:19 Uhr

Kommt drauf an was du machen möchtest.

Einen WindowsDienst der auch aktiv ist wenn der Benutzer z.B. nicht am Rechner angemeldet ist. Oder eine NotifyIcon Anwendung die z.B. auf der Windows Taskbar (SysTray) angezeigt wird. Du kannst auch nur eine Anwendung schreiben die ähnlich einer NotifyIcon / Windowsforms Anwendung basiert indem du in der Main nen Thread mit einer DoNothing Schleife einbaust oder über WaitHandles, Thread.Join, ManualResetEvent, AutoResetEvent, SubClassing usw.. usw. 😉

Also, was willst du genau machen?

15.02.2008 - 13:50 Uhr

Hrm, man kann zwar die verschiedenen Programme erlernen wie z.B. mit Büchern wie "Photoshop für Dummies". Allerdings die Grundkenntnisse wie man sie evtl. mit Büchern wie "Der typografische Raster" erlernen kann, werden einem besser durch eine Ausbildung oder jemanden mit Berufserfahrung, vermittelt.

Allerdings, durch die Firmen/Arbeit meiner Mutti 😉 weis ich zumindest das Schulungen zumeist nichts bringen - da diese zum Großteil eben von Leuten abgehalten werden die meistens genauso viel Ahnung haben wie man selbst. Und wirklich gute Schulungen kosten ein vermögen. Meine Mutter arbeitet bereits ca. 30 Jahre im Druckmedien Gewerbe und eine Schulung bei ihr kostet meistens zwischen 5.000 bis zu 35.000 Euro...

Grafik ist einfach ***, es gibt tausende Dinge zu beachten - Programmierung unterliegt meistens logisch nachvollziehbaren Regeln, lass dich also nicht assimilieren von den "Pinslern und Maler" und bleib lieber bei uns "Blinzlern" :evil:

Scherz beiseite, die beiden Bücher helfen einen wirklich weiter:
Link
Link

15.02.2008 - 12:07 Uhr

Hrm, die Lösung dazu würde mich auch interessieren. Hatte mal ein ähnliches Problem und sogar dabei die NonClientAreBereich überschrieben dennoch kam das Icon. Hatte dann einfach ein Maximize nicht mehr erlaubt, aber eine tolle Lösung wars natürlich nicht.

15.02.2008 - 11:58 Uhr

Ups, vergessen reinzuschreiben, der ist nicht einfach zu finden 🙂

Der Fehler entsteht bei der FuelleListView Methode:

Wenn nen Breakpoint mal vor der zweiten Schleife reinmachst und dir mal folgendes ansiehst : "this.listView1.Items[0].SubItems.Count". Fällt dir auf das der Count = 2 statt wie erwartet = 1 ist. Somit exestiert schon 1 Subitem mehr mit den Inhalt von Subitem 0 als erwartet. Somit wird beim hinzufügen einer neuen Column die dann den Index 1 bei 2 Columns der Wert von Subitem 1 von 2 Subitems angezeigt.

Fehler wird wie folgt behoben :

listviewitem.SubItems[0]


  // Füllt Items in die ListView in der Anzahl der Teilnehmer pro Gruppe
                for(int j=1; j<=AnzahlTpGruppe; j++)
                {
                    // Index des Items ist fortlaufend, während Index der teilnehmer der 
                    // entsprechenden Gruppe wieder bei 0 anfängt
                    int n = (Gruppenindex - 1) * AnzahlTpGruppe + j;
                    string ItemName = Convert.ToString(n);
                    ListViewItem listviewitem = new ListViewItem(ItemName);
                    listviewitem.Name = ItemName;
                    listviewitem.SubItems[0].Text = ItemName;
                    this.listView1.Items.Add(listviewitem); 
                }

Warum ist das so ? - Verdammt gute Frage:
Wenn einfach mal nur:


                ListViewItem bla = new ListViewItem("Hätte auch gerne das Zeug was man bei MS morgens in den Kaffee bekommt..");

Instanzierst wirst du merken das in "Bla" immer ein Subitem.Count = 1 vorhanden ist. Also ich erkläre mir das mal so, es wird immer davon ausgegangen das bei new ListViewItem ein Subitem vorhanden sein muss um etwas darzustellen. Zumindest fällt mir sonst keine andere Erklärung dazu ein. Würde mich nur interessieren was in der MSDN dazu steht.

15.02.2008 - 10:45 Uhr

Hrm, habe einige Workflows schon geschrieben für PPS / CRM und ERP Programme.
herbivore und Khalid haben beide nicht unrecht ein Workflow funktioniert am besten wenn er klein gehalten wird aber muss ab und an auch Komplexe aufgaben erfüllen. Bei ERP Systemen kam das häufig vor in Form von Aufträge Prioisieren durch ein Rechtesystemdurchjagen auf Rechte warten udn Auftrag anschließend durch einen Projektplan jagen ob z.B. Gewinn dann noch einen Prozentsatz besitzt der z.B. erst wieder genehmigt werden muss.

Früher habe ich dabei dne Fehler gemacht das viel zu grobmotorig abzuarbeiten. Nach dem Muster, es kommt ein Event wenn Fall A führe Methode X aus. Dieser Ansatz ist allerdings unübersichtlich und wird je mehr Abfragen und vorallem Fallsituationen zusammen kommen unübersichtlich.

Mittlerweile mache ich es mir einfacher, ich nutze das Command Action Prinzip und kann somit Aktionen immer je nahc Fall weiter verschachteln. Und somit Quasi unendlich viele Fälle abgreifen und da ich für jeden eine eigene Komposition schreibe. Allerdings habe ich von JuyJuka ebenso einen dafür Anwendbaren Ansatz gesehen der genauso gut Funktionieren würde.

Wie gesagt mach blos nicht den Fehler alles statisch herunter zu Programmieren, nur auf Events zu triggern oder sogar reine Macro Funktionen zu verwenden.

Evtl. kennt ja der ein oder andere noch bessere Ansätze.

14.02.2008 - 19:30 Uhr

Verlesen, ist aber genau das selbe Spiel 🙂

[Edit]
Um genau zu sein, ein paar Threads unter deinen gings es ebenso ums Drag&Drop nur bei TreeView zu DataGridView. Versuche die Postings zu beantworten und gleichzeitig meiner Arbeit nachzugehen - Irgendwann kommt man halt durcheinander 😉

14.02.2008 - 17:33 Uhr

Khalid's Ansatz + TreeViewHitTestInfo Info = TreeView.HitTest(e.Location);
Und Info = TreeViewHitTestLocations.PlusMinus.

[Edit] War wer schneller 😉

14.02.2008 - 15:12 Uhr

Ich denke dir fehlen noch ein paar Grundlagen, das wichtigste aber mach dich erstmal mit der Entwicklungsumgebung vertraut.

Im "Solution Explorer" ("Projekt übersicht") findest du ganz oben in dieser Liste den Punkt "References" ("Verweise"). Dort klickst du mit der rechten Maustaste drauf und sagst "Add Reference" ("Verweis hinzufügen"). Dann öffnet sich ein Fenster mit verschiedenen Reitern. Du klickst auf den Reiter .NET wenn er nicht sogar schon angeklickt ist. Dort selektierst du jeweils die Einträge System.Drawing und System.Windows.Forms mit gedrückter "STRG-TASTE" da sonst nur eines auswählen würdest und drückst dann auf den Button "OK".

Jetzt hast du unter den Punkt References ("Verweise") wenn das "+" Symbol anklickst die beiden References ("Verweise") stehen.

Denk dran, wenn du Namespaces nutzt diese auch innerhalb deiner Klassen einzubinden mit "using System.Windows.Forms". Du musst allerdings nicht unbedingt die References ("Verweise") derartig einbinden aber dazu sieh dir die Grundlagen an.

* Die deutschen Übersetzungen kenne ich nicht, habe nur das englische Virsual Studio hoffe das die Begriffe ca. passen 😉

14.02.2008 - 14:51 Uhr

Denke da wirst irgendwie globale Systemnachrichten abfangen müssen.

Über die Windowsnachricht WM_QUERYENDSESSION = 0x001 oder eben System.Environment.HasShutdownStarted kommt man dran ran. Jetzt frag mich blos nicht nach ner WindowsNachricht bei nen Dienst, wirst dich wenn irgendwo mit einklinken müssen oder nen Register z.B. auf die Devices machen müssen. Und irgendwie klingt es nicht verlockend nen Thread zu öffnen mit ner DoNothing Schleife für HasShutdownStarted. Würde aber drauf wetten wenn in der MSDN nach override ServiceBase.OnShutDown suchst findest was.

Nur Shutdown würde nichts nützen, glaube das wird auch ausgelöst wenn nen benutzer den Dienst manuell beendet.

Evtl. helfen dir aber die genannten Stichwörter etwas weiter unter google.

14.02.2008 - 14:31 Uhr

Hrm, okay habe lange kein VB mehr gemacht daher vermute ich den Fehler mal. Bzw. ist er eigentlich logisch 🙂

Genau in diesen Codeabschnitt wird dein Fehler verursacht.


      void Event_DragDrop(object sender, DragEventArgs e)
        {
            this.<DataGridView oder ListView>.DoDragDrop(e.Data, e.Effect);
        }

Weil hier wieder base.OnDragDrop aufgerufen.

Erinnere dich an:


// Diese Methode wird durch <DataGridView oder ListView>.DoDragDrop vom EventHandler ausgelöst
protected override void OnDragDrop(DragEventArgs drgevent)
        {

            string sTest = drgevent.Data.GetData(typeof(string)) as string;
            base.OnDragDrop(drgevent); // hier wird der EventHandler wieder ausgelöst 
         }    

Das base.OnDragDrop(drgevent); löst ja das Event_DragDrop aus. Somit, hast du eine Endlosschleife. Ausklammern is nicht - jetzt geht es darum entweder die Daten so aufzubereiten das Anhand der übertragenen Daten weist was damit passieren muss und dann via if else das base.OnDragDrop aufrufst oder nicht. Oder du identifizierst ob Ziel und Sender gleich sind und somit das base.OnDragDrop nicht aufgerufen werden darf.

Gibt sicher auch noch mehr möglichkeiten, dass dan zu lösen 🙂

14.02.2008 - 13:59 Uhr

Okay, das erste was auffällt ... viiiel Code.

Denke brauchst nicht mal die Hälfte davon.

Du hast viele Abfragen mit ListIDP drinnen und einer switch case Anweisung was mit welchen Item tun. Und du hast viele listView_DragDropX Methoden drinen.

Also wäre das erste hier zu vereinfachen .-)

Der erste Schritt, erstelle eine neue Klasse Namens TreeViewEx, überschreibe dort die Methode OnMouseDown innerhalb davon holst dir mit this.GetNodeAt die Node von der Position an der die Maustaste gedrückt wurde -> Vorzugsweise Linke Maustaste und holst dir den Knoten via GetNodeAt() übergibst die Daten anhand des Methodenaufrufes base.DoDragDrop(MyNode, DragDropEffects.Move). Danach überschreibst du die OnDragOver Methode und stellst den Effekt = DragDropEffects.Move.

Soo nun zum etwas spannenderen Teil. Du erstellst die neue Methode.
DoDragDrop(object sender, object data, DragDropEffects allowedEffects). Innerhalb der Methode rufst du dann nicht mehr die base.DoDragDrop auf, also einfach auskommentieren. Stattdessen feuerst du selbst das DragDrop Event ab, indem erstmal ein neues dafür definierst das eben zwei sender übergabeparameter hat. Einmal das base und zum zweiten den sender und zum dritten eben das DragEventArgs.

Soo, alles was nun noch tun musst ist für alle instanzierten TreeViews von deiner TreeView Klasse jeweils das neue Event aufrufen und hast nun die möglichkeit eben ziel und transfer TreeView über die sender zu identifizieren und dort dann auch jeweils beim rüberzeihen der Elemente diese zu lsöchen. Das minimiert deinen Quellcode ungemein und reduziert die Fehler. Ebenso kannst dann innerhalb der gebundenen Methode deines eigenen Events die Daten auf das Label anzeigen lassen.

Ich habe wahrscheinlich länge gebraucht um das runter zu tippen als es wirklich zu tun gibt 🙂

Du kannst auch alternativ gleich die sender TreeView mit deinen Nodes über eine Hilfs-Struktur oder Hilfs-Klasse als DragEventArgs merken indem eben von diesen Ableitest und füllst was noch sauberer wäre.

14.02.2008 - 12:14 Uhr

Hrm, nutze tapiex finde die nen Tick einfacher.

14.02.2008 - 11:14 Uhr

Okay, das geht nicht so einfach. Das Problem, ich kenne das comppact Framework ebensowenig.

Gelöst habe ich ein solches Problem damals mit Win32 API Befehlen, dazu habe ich einfach mit SetWindowPos die Windows Taskbar mit dem Style SWP_HIDEWINDOW in den Hintergrund gesetzt. Wenn man nun Fenster Maximiert hat man einen FullScreen, das habe ich über this.WindowState gelöst kann auch sein das ich damals ne Win32 API benutzt habe. Mit SetForegroundWindow und Form.TopMost = true, habe ich das Fenster in den Vordergrund gebracht. Damit das Fenster zusätzlich keinen ContextMenü hatte, nutzt ich etwas sehr spezielles. Denke aber ein FormBorderStyle = None tuts auch.

14.02.2008 - 11:01 Uhr

Das erste was mir auffiel "ermittleGruppenNr":
Wenn du da nach der Gruppe suchst zu der der Teilnehmer gehört, machst du folgendes:

Wenn die Teilnnehmernummer kleiner oder gleich die der der Teilnehmer einer Gruppestärke ist, so gibst du den Index Wert zurück - so weit so gut. Bei einer Teilnehmernummer die größer als die Gruppenstärke ist nimmst du den Wert und Teilst diesen durch die Gruppengröße. Klingt eigentlich logisch verursacht aber folgenden Fehler.

5 Teilnehmer 3 Gruppen 15 Leute

Soo Gruppe 1 BSP

5 Teilnehmer ≤ 5 = true daher greift deine temp =1 da 1-1 = Index 0
9 Teilnehmer ≤ 5 = false daher 9 / 5 =2 = 2 -1 = Index 1
10 Teilnehmer ≤ 5 = false daher 10 / 5 =2 = 2 -1 = Index 2 <-- FEHLER
11 Teilnehmer ≤ 5 = false daher 11 / 5 =2 = 2 -1 = Index 2
15 Teilnehmer ≤ 5 = false daher 15 / 5 = 3 = 3-1 = Index 2

Warum Fehler?
1 -5 = Gruppe 1 == Index 0
6-10 = Gruppe 2 == Index 1 <-- Man sieht nummer 10 gehört zu Gruppe 2 (Index1)
10 - 15 Gruppe 3 == Index 2

Soo nun der nächste Fehler in der Methode "ermittleTeilnNrZurGruppe" 🙂
Da rechnest Teilnehmernummer Modulo-Operator (%) Anzahl Teilnehmender zur Gruppenstärke.

5 Teilnehmer 1 Gruppen 5 Leute

Gruppe 1
1 % 5 = 1 -> 1 Index = Teilnehmer 2 -> Fehler?
2 % 5 = 2 -> 2 Index= Teilnehmer 3-> Fehler?
3 % 5= 3 -> 3 Index= Teilnehmer 4-> Fehler?
4 % 5 = 4 -> 4 Index= Teilnehmer 5-> Fehler?
5 % 5 = 5 -> 0 Index= Teilnehmer 1 -> Fehler?
Usw.. bei mehreren Gruppen wiederholt sich das dann alles.

Und das nächste, du füllst jedesmal this.listView1.Items.Add so dass evtl. Wenn Teilnehmer 1 zuerst in Runde 1 ist und kurz dannach Teilnehmer 2 in Runde 1 einläuft eine weitere Runde hinzu. So das x Runden Pro Teilnehmer entstehen. Für mich ist die Rundenanzahl etwas fixes also ein Wert den ich eingeben muss. 1 Läufergruppe a 5 Läufer die 2 Runden a 200 m laufen sollen.

Aber ehrlich, finde das zu komplex aufgebaut, schreib dir einfach mehr Hilfsklassen und leite in deinen Hilfsklassen von die List<> ab um dort die Sortierungs und Suchfunktionen nutzen zu können. Hatte wirklich Probleme zu verstehen was wie funktionieren soll, kann daher sein das ich dass ein oder andere falsch interpretiere habe 🙂

13.02.2008 - 17:47 Uhr

Hrm, kann es mal über die Win32 API Funktion SetWindowPos versuchen die Location zu ändern. Glaube da konnte man die Rect bzw. position des Wnd's verschieben während es minimiert und hidden war.


[DllImport("user32.dll", SetLastError=true)]
private static extern bool SetWindowPos(IntPtr hwnd, int hwnd2, int x, int y, int cx, int cy, int uFlags);

Ähm, hab sowas ja grade selbst geschrieben für nen PopUp Fenster... hust geht definitiv 😉

13.02.2008 - 17:45 Uhr

Hrm, stimmt auch wieder bei CodeProject Suchen und rumkopieren geht schneller 😉

In der LineNumber.cpp in der CLineNumberStatic:👍nPaint() Methode kann man quasi alles fast 1 zu 1 rauskopieren und minimal anpassen. Bzw. über www.pinvoke.net die entsprechenden DllImports reinkopieren.

13.02.2008 - 16:44 Uhr

Hrm, du könntest anhand des Textes durchgehen und nach "\n" suchen.
Bei jedem "\n" weist du dann das eine neue Zeile kommt.

Anschließend würde ich mir ein UserControl basteln: Mit einen TableLayoutPanel die TextBox einfügen und nebendran nen normales Panel mit einer einer dynamischen Breite. Im Panel würde ich dann die OnPaint überschreiben und dort mit der Scroulbar bewegung von der TextBox die jeweilige zeile die ich gesucht habe an die entsprechende visuelle Stelle hinmalen.

Die TextBox selbst an einer bestimmten Stelle zu übermalen würde glaube ich mehr Zeit in Anspruch nehmen, da man hierfür den ClibBound Bereich vom ClientRectangle versetzen müsste und ich denke das geht insgesammt länger.

13.02.2008 - 16:30 Uhr

Hrm, muss dann etwas mit Vista zu tun haben.

Das Beispiel bei CodeProjectklappt geht bei mir reibungslos. Wäre also interessant was bei deinem Code unter WinXP nun passiert. Kannst das ja mal auf einen anderen Rechner mal testen. 🙂

/PS
Bei meinen kleinen codebeispiel ging es unter Vista wie XP, habe allerdings die Windows Border Styles über SetWindowPos anderst gesetzt.

13.02.2008 - 14:25 Uhr

Hrm, sehe da kein this.Size = new Size(abd.rc.right - abd.rc.left,abd.rc.bottom - abd.rc.top).

Kann auch an etwas anderen liegen, aber hier ein Link der dir weiterhelfen sollte 🙂

[Edit]
Grml.. 2 mal den falschen Link gepostet..

13.02.2008 - 14:02 Uhr

Hrm, kannst du den Abschnitt reinposten an denen du die OnRowPostPaint / OnRowPrePaint Methoden überschreibst um die Zeilen selbst zu zeichnen? Denn, normalerweise wenn diese überschreibst sollte die Scroulbar nicht beeinflusst werden. Oder überschreibst du die OnPaint Methode?

13.02.2008 - 11:50 Uhr

Also, TreeNode ist implementiert ja deine deine Klasse AbstractTreeNode Klasse nicht.

Aber ich denke eher du hast eine Klasse die von AbstractTreeNode ableitet und AbstractTreeNode leite von TreeNode ab. Wenn jetzt new TreeNode("Test") übrergibst kann es ja nur zu Fehlern kommen 🙂 Wenn deine Klasse die von AbstractTreeNode abgeleitet wurde mit Nodes.Add(new KlasseDieVonAbstractTreeNodeAbgeleitetIst) hinzufügst. Wird es dennoch nicht klappen.

Da TreeNode von MarshalByRefObject abgeleitet ist und die Schnittstellen ICloneable, ISerializable beinhaltet kommt es ebenso zu fehlern.

Also, du hast gar keine andere wahl als die Klasse TreeNode zu verwenden. Ansonsten müsstest du eine Hilfsklasse nutzen in der die Daten von TreeNode übergibst. Sowas könntest entweder über Reflection lösen oder machst es via parameter übergabe.

13.02.2008 - 11:41 Uhr

Hrhr, na ja wenn man es recht überlegt ist die Lösung ja ziemlich einfach. Nur wenn man Tagelang irgendwelche T-SQL normierungen angeht sieht man den Wald vor lauter Bäumen nicht mehr 🙂

13.02.2008 - 10:48 Uhr

Super vielen Dank euch allen!
Die Nummern von vorne durchzugehen ist wirklich besser, habs mir mal Anhand der Liste vom ONB angesehen und ausprobiert.

Bei Tante Louise wäre bei 004977716570 mit 4 Stellen das Suchkriterium 00497771*.
Somit bekäme ich viel weniger falsche Treffer bei denen z.B. die Länder oder gar Ortsvorwahl schonmal falsch ist.

Danach kann ich ja wie gehabt durchgehen 🙂

12.02.2008 - 19:42 Uhr

Hallo,

habe einen kleinen Algorithmus geschrieben um telefonnumemrn zu identifizieren.
Leider bin ich mir nicht sicher ob der Weg den ich eingeschlagen wirklich der Richtige ist. Leider muss ich dafür etwas ausholen...

Bisher habe ich eine normalisierung der Telefonnummern vorgenommen und diese daher in einheitlichen Formaten vorliegen:

+(41) 07731 / 6470 - 2 wird zu 0041773164702
6470 wird zu 004977716470
usw.

Die Normierung sieht also immer so aus:
00<Ländervorwahl><Ortsvorwahl ohne 0><Rufnummer><Nebenstelle>

Bekomme ich also einen Anruf von Tante Louise so erhallte ich eine normierte nummer. Z.B. 004977716570.

Für das Suchen der Telefonnummer habe ich die Vorgabe das man anhand von variablen Anzahl von Stellen ungefähre Nummern suchen kann. Diese liegen zwischen 0 für einen Volltreffer bis 1-7 Stellen. Momentan habe ich das so gelöst das ich eine SQL Abfrage starte die mir alle Telefonnummern zurückliefert deren letzten Stellen mit der des Suchkriteriums übereinstimmen.

Sprich, bei Tante Louise 004977716570 mit 4 Stellen als Suchekriterium. Erhallte ich alle Telefonnummern die mit *6570 Enden.

Jetzt zum Problem ich soll die "Trefferqualität" darstellen mit 3 bunten Bildern 😉

Grün = 100%ige Treffer
Gelb = 99-50%ige Treffer
Rot = 49-20%ige Treffer
Alles unter 20% fällt raus...

Also habe ich mir gedacht, ich überprüfe jede Stelle von beginn an ob diese mit dem Suchkriterium überinstimmt.

Bei Tante Louise mit Suchkriterium "004977716570" mit 4 Stellen als Suche, erhallte ich also ersteinmal 3 Treffer die mit *6570 Enden.

(Die Leerzeichen sind nur der Übersichtlichkeit drinnen)

1.) 0041 7561 6570
2.) 0049 7772 6570
3.) 0049 7771 6570

1.)
0041 7561 6570 (1. Datensatz)
0049 7771 6570 (Tante Louise)
TTTT T = 5 Treffer

2.)
0049 7772 6570 (2. Datensatz)
0049 7771 6570 (Tante Louise)
TTTT TTT = 7 Treffer

3.)
0049 7771 6570 (3. Datensatz)
0049 7771 6570 (Tante Louise)
TTTT TTTT TTTT = 12 Treffer

Soo nun rechne ich das Prozentual um, dafür nehme ich den Treffer und teile diese durch die Länge der gesuchten Telefonnummer.

Bei Tante Louise wäre das bei der Nummer 004977716570 die Zeichenlänge 12;

1.) 5 / 12 = 0,41~ = 41% = Rot
2.) 7 / 12 = 0,58~ = 58% = Gelb
3.) 12 / 12 = 1 = 100% = Grün

Soo bis jtzt sieht es so aus als wäre das ganze absoluter Unsinn, da man Tante Louise ja eigentlich viel einfacher finden könnte und ich gleich weis habe ich Tante Louise in der Datenbank ja oder nein.

Nur geht es dabei um etwas anderes, ich lege eine Telefonnummer von einer Zentrale an, werde aber von einen Mitarbeiter der Zentrale "mit Nebenstellennummer" angerufen. So soll ich ermitteln können, zu welcher wahrscheinlichkeit der Anrufer, zu welcher Firma gehören könnte - wenn ich diesen noch nicht als Kontak gespeichert habe. Oder ich möchte nach Telefonnummern suchen können bei denen ich nur Teilweise die Telefonnummer kenne - so komisch das auch klingt 😉

Soweit habe ich bereits alles schon realisiert aber ich fürchte das dieser Weg nicht der Richtige zur berechnung einer Trefferwahrscheinlichkeit ist. Aber irgendwie stehe ich zurzeit auf dem Schlauch... Vielleicht weis ja jemand einen bessere Weg.

12.02.2008 - 17:36 Uhr

Hrm, hatte es auch grade etwas verpeilt...

Da TreeNode ja nicht von deiner abstrakten Basisklasse abgeleitet ist und somit nicht gecastet werden kann geht das ganze auch so nicht. Bei deinen zweiten Beispiel genau das selbe in GetData. Wenn da statt AbstractTreeNode eben TreeNode nimmst sollte es funktionieren.

Allgemein ist es aber möglich eine normale Klasse, die von einer abstrakten Klasse abzuleiten und sofern beide serialisierbar sind auch in eine abstrakte Klasse zurück zu casten und diese zu serialisieren.
Aber darum ging es dir ja nicht, bzw. wüsste grade nicht wofür man ein so komisches gebilde bräuchte 🙂

Ich habs einfach nur wie folgt getestet, hab ne Klasse erstellt von TreeView abgeleitet und die OnMouseDown Methode überschrieben, mir das gefundene object in die Zwischenablage gelegt und bei nen Button-Click wieder ausgegeben. Hatte ohne Probleme funktioniert. Bzw. das ganze kann man ja auch beliebig anders lösen, der Weg ist immer nur der selbe - Die meisten Control spezifischen objekte sind wegen der DragAndDrop Geschichte ja eh schon serialisierbar, also muss man da in den seltesten Fällen etwas machen. Also, Datenholen, in dem Fall den Knoten diesen ins Clipboard schmeissen und wieder rausholen.

Zusammengefasst sieht das so aus, was ebenso geht.


        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            if (e.Button == MouseButtons.Left)
            {
                TreeNode node = base.GetNodeAt(e.Location);

                if (node != null)
                {

                    // copie node into the clipboard.
                    Clipboard.SetData(DataFormats.Serializable, node);

                    // get node from clipboard.
                    TreeNode mynode = (TreeNode)Clipboard.GetData(DataFormats.Serializable);
                }
            }
        }

12.02.2008 - 16:50 Uhr

Hrhr, tu mir mal einen gefallen - geh in die Klasse AbstractTreeNode und schreib statt


public abstract class AbstractTreeNode 

mal folgendes hin:


public class AbstractTreeNode 

Probiers jetzt noch mal 😉

12.02.2008 - 16:45 Uhr

Hrm, wenn die MessageBox nicht mal erscheint vermute ich mal das herbivore den richtigen Richer hatte und der EventHandler nicht aufgerufen wird.


       public Form1()
        {
            InitializeComponent();
            this.FormClosing += new FormClosingEventHandler(Form1_FormClosing);
        }

        void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = MessageBox.Show("Bla", "Blubb", MessageBoxButtons.YesNo) == DialogResult.No;
        }

Bei
Application.ExitThread();
System.Threading.Thread.CurrentThread.Abort();
System.Diagnostics.Process.GetCurrentProcess().Close();
usw..

Wird beendet ohne die OnClose aufzurufen.. Aber wüsste grad keine Beispiele bei denen man auf diese Art sein Programm beendet - Vielleicht bei alten Anwendungen mit Excel oder Word wenn man Marshal.ReleaseComObject vergessen hatte?

12.02.2008 - 16:09 Uhr

Hrm, wenn wie im Link vorgegangen bei dem Beispiel für C#.
Sollte es zu keinen Problemen kommen.

Hast du das [Serializable] Attribut über deiner AbstractTreeNode wirklich gesetzt und bedenke AbstractTreeNode klingt komisch.
Würde vermuten das dass Ding ne Abstrakte Klassen ist und diese kann man nicht instanziieren und somit serialisieren. Ansonsten vergewissere dich das die Klasse auch einen Konstruktor ohne Parameter hat.

12.02.2008 - 15:24 Uhr

Hallo punkdevil,
bei Clipboard.SetData solltest du die DataFormats beachten.

Du hast zwar einen Wert in die Zwischenablage gespeichert aber das ist der Text von AbstractTreeNode.ToString().
Um die Klasse in die Zwischenablage zu kopieren musst sie Serialisierbar machen. Hier der Link zur MSDN Seite.

12.02.2008 - 11:22 Uhr

[DllImport("user32.dll")]
private static extern bool SetCursorPos(int X, int Y);


[DllImport("user32.dll")]private 
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

//SendMessage(hWnd, WM_LBUTTONDOWN, IntPtr.Zero, new IntPtr( YPoint * 0xFFFF + XPoint));
//SendMessage(hWnd, WM_LBUTTONUP, IntPtr.Zero, new IntPtr( YPoint * 0xFFFF + XPoint));

maus, cursor bewegen
Mausklick im fremden Fenster simulieren
SendClick / API?

/ps
Mir war langweilig 🙁

12.02.2008 - 11:13 Uhr

Hrm, eigentlich das was herbivore Schrieb, z.B. wenn DOM Code verwendest für den Aufbau einer Tabelle "table.appendChild(newRow);" oder "setAttribute" versucht IE diesen nachzuladen kennt aber den Befehl nicht. Also erscheint entweder nen Fehler oder eben gar nichts.

Ich kann mir daher nur vorstellen das es evtl. daher kein Quellcode angezeigt werden kann. Genau weis ich das nicht, bin sehr lange nicht mehr in der Web Programmierung tätig gewesen. Hatte damals nur mal versucht mit Ajax und PHP was zu machen. Schau(t)e daher für sowas meistens ins SELFHTML Forum rein.

Die Frage ist ob diese Seiten dann wirklich beachten musst.

12.02.2008 - 10:44 Uhr

Hrm, ich kann mir vorstellen das es im IE im Zusammenhang mit DOM-Code zu Problemen kommen kann. Einige Befehle kennt der IE nicht. Fürchte da wirst etwas nachgooglen müssen.

12.02.2008 - 10:13 Uhr

Hallo nibbler,

Erstell eine neue Klasse, leite von TreeView ab. Stell im Konstruktor den base.DrawMode auf OwnerDrawAll um auch das Selektieren selbst zu zeichnen. Dann überschreibst du die base.OnDrawNode(e) Methode und erstellst deine eigene Zeichenroutine. Bedenke dabei das die Node Eigenschaften die über dem Parameter DrawTreeNodeEventArgs e hereinbekommst benutzt.

Hier nen kleines Beispiel dafür:


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

namespace CursomLevelReport
{
    public class TreeViewEx :TreeView
    {

        public TreeViewEx()
        {
            base.DrawMode = TreeViewDrawMode.OwnerDrawAll;
        }

        private ToolTip myToolTip = new ToolTip();

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            TreeNode myNode = base.GetNodeAt(e.Location);

            if (myNode != null)
            {
                if (myNode.Text != this.myToolTip.GetToolTip(this))
                    this.myToolTip.SetToolTip(this, myNode.Text);
            }
            else
                this.myToolTip.SetToolTip(this, null);
        }

        protected override void OnDrawNode(DrawTreeNodeEventArgs e)
        {
            if (e.Node.IsVisible)
            {
                Font drFont = e.Node.NodeFont;

                if (drFont == null)
                    drFont = base.Font;


                e.Graphics.FillRectangle(new SolidBrush(e.Node.BackColor), e.Bounds);
                e.Graphics.DrawString(e.Node.Text, drFont, new SolidBrush(Color.DarkGray), e.Bounds.Location);

                if (e.Node.IsSelected)
                    e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(50, 0, 0, 128)), e.Bounds);
            }

            //base.OnDrawNode(e);
        }
    }
}

/ps
Den Tool-Tip kannst rausmachen wenn ihn nicht brauchst, hatte diesen noch von einem anderen Posting bezüglich Tool-Tip in TreeView drinnen. Denk dran, in diesen Beispiel habe ich nicht alles beachtet es soll nur den Weg aufzeigen - wirst merken das die Texte und die Select Positionen z.b. nicht stimmen. Also das X bei e.Bounds.Location noch etwas höher als 0 sein muss wegen des normalen "+" Expanding zeichens das ich nicht gemalt habe usw.

[Edit]
herbivore war schneller als ich gebraucht habe, um das runter zu Tippen, siehe einfach Doku da steht noch mehr.

12.02.2008 - 09:49 Uhr

Hrm, also wenn ich das nicht falsch sehe dann ist da nen Fehler drinnen.

Du bindest die Daten an this.table1BindingSource an die Spalte table2_id - müsste das nicht table1_id sein?

Also


this.comboBox1.DataBindings.Add(new System.Windows.Forms.Binding("SelectedValue", this.table1BindingSource, "table1_id", true));
this.comboBox1.DataSource = this.table2BindingSource;
this.comboBox1.DisplayMember = "table2_column5";
this.comboBox1.ValueMember = "table2_id";

11.02.2008 - 16:31 Uhr

Denke mal du musst unformatierte Daten an den Drucker senden...

Kannst es über DllImport von winspool mal versuchen. Über www.pinvoke.net findest alles was dazu brauchst und in der MSDN bzw. Microsoft Windows Platform SDK findest meistens C++ Code und eben die Beschreibungen dazu.


    [DllImport("winspool.Drv", EntryPoint="WritePrinter", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
    public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten );

Hier nen Link.

Wenn es in Word zu drucken geht, dann machs einfach darüber und spaar dir die Arbeit.
Evtl. weis ja jemand sonst noch eine Lösung.

11.02.2008 - 16:09 Uhr

Hrm, versuch mal das ganze einfach auf ne WindowsForm zu malen indem die Paint Methode überschreibst ob da auch der Text nicht als Barcode erscheint.

Weil, sollte der text der Schrieftart nicht stimmen "SATO-Code128MP" dann malt er automatisch in der Standardforn "Microsoft Sans Serif". Reicht eigentlich schon aus wenn beim Print nen Breakpoint reinsetzt nach gr.DrawString um nachzusehen ob die Font auch wirklich "SATO-Code128MP" heisst.

/ps

Mit dem Codebeispiel kannst ja wenn feststellst das SATO-Code128MP evtl doch nicht der richtige Name sein sollte, dne richtigen heraussuchen, kann ja sein das z.B. nur nen leerzeichen fehlt oder etwas anderes.


foreach (FontFamily _ff in FontFamily.Families)
                Console.WriteLine(_ff.Name);

11.02.2008 - 15:50 Uhr

Ich weis du hast nun ein paar mal hingeschrieben das es nicht funktioniert hat.

Aber, du hast wirklich beim PrintPageEventHandler die Graphics überschrieben und die passende Font die du auch in Word verwendets benutzt und es hat nicht geklappt (Siehe Beispiel) ? Hatte das damals so eigentlich hinbekommen, man muss nur die Font beim Kundenrechner dann im Setup mit installieren falls nicht vorhanden.


        public void Print()
        {
            PrintDocument tmp = new PrintDocument();

            tmp.PrintPage += new PrintPageEventHandler(tmp_PrintPage);
        }

        private string m_sBarcode = "77782221";

        void tmp_PrintPage(object sender, PrintPageEventArgs e)
        {
            using (Graphics gfx = e.Graphics)
            {
                gfx.DrawString(m_sBarcode, new Font("<FontvomBarcode>", 10.0f), new SolidBrush(Color.Black), 0, 0);
            }
        }

Mir fällt es nur schwer sich vorzustellen dass das nicht geht...
Wie kann man sich den Drucker dann vorstellen A5 Formate oder so nen Bondruckerding den ein normaler Label-Drucker sollte das locker hinbekommen?

11.02.2008 - 14:53 Uhr

Hallo Andreas.May,
Grund für InvokeRequired. Der Grund warum du hier InvokeRequired brauchst, ist das die Aktualisierungsmethode sowohl aus dem extra Thread als auch aus dem GUI-Thread aufgerufen wird.

Hrm, das stimmt...

Bei Klassen mit operationen von langer Laufzeit die nicht von System.Windows.Forms.Control abgeleitet wurden. Kann man den Arbeitsthread mithilfe eines asynchronen Delegates erzeugen und dort dann mit der Invoke-Methode über ein weiteres delegate zurückschreiben (also bei nen Array dann halt nur ne Kopie..).

11.02.2008 - 14:22 Uhr

Na sowas musst dann mit reinschreiben, das geht etwas anders aber ist ebenso einfach 🙂

Erstelle eine neue Klasse, leite von TreeView ab.


 public class TreeViewEx :TreeView
    {
        private ToolTip myToolTip = new ToolTip();
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            TreeNode myNode = base.GetNodeAt(e.Location);

            if (myNode != null)
            {
                if (myNode.Text != this.myToolTip.GetToolTip(this))
                    this.myToolTip.SetToolTip(this, myNode.Text);
            }
            else
                this.myToolTip.SetToolTip(this, null);
            }

    }

/PS
Denk dran, myNode.Text != this.myToolTip.GetToolTip(this) muss sein, du kannst das auch etwas anders schreiben - aber die Abfrage muss drinnen bleiben. Sonst blinkt dich das Ding zu tode 😉

11.02.2008 - 14:12 Uhr

Hrm, die eine Datenbank gibt dir den Inhalt der ComboBox Auswahl wieder. Das ist dann <ComboBox>.DataSource.

Für die andere Datenbank benötigst du <ComboBox>.DataBindings.

Über <ComboBox>.DataBindings.Add(new System.Windows.Forms.Binding("Text", <BindingSource>, "<ColumnName1>", true)); kannst du dann die Daten binden. Jeweils an ein Property von ComboBox und bei der Datenbank an in bezug auf dessen Spaltenname.

11.02.2008 - 13:50 Uhr

Einfach über System.Windows.Forms.ToolTip einen ToolTip erzeugen und über SetToolTip dann das ToolTip auf das Control setzen auf dem es angezeigt werden soll.


  private ToolTip toolTip1;
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.checkBox1 = new System.Windows.Forms.CheckBox();
            this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
            this.SuspendLayout();
            // 
            // checkBox1
            // 
            this.checkBox1.AutoSize = true;
            this.checkBox1.Location = new System.Drawing.Point(38, 121);
            this.checkBox1.Name = "checkBox1";
            this.checkBox1.Size = new System.Drawing.Size(80, 17);
            this.checkBox1.TabIndex = 0;
            this.checkBox1.Text = "checkBox1";
            this.toolTip1..SetToolTip(this.checkBox1, "TEST\r\n");
            this.checkBox1.UseVisualStyleBackColor = true;
            // 
            // Form1
            // 
            this.ClientSize = new System.Drawing.Size(292, 266);
            this.Controls.Add(this.checkBox1);
            this.Name = "Form1";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

Kannst das auch direkt über den Designer machen, einfach ToolTip aufs Form ziehen, das Control angeben auf dem es angezeigt werden soll. Dann auf das entsprechende Control draufklicken unter MISC siehst dann den ToolTipText und kannst diesen dann dort eingeben.

11.02.2008 - 13:40 Uhr

Hier mal nen billiges Beispiel:


  public class Form1 : Form
    {
        private System.Windows.Forms.TextBox textBox1;
        public Form1()
        {
            this.textBox1 = new System.Windows.Forms.TextBox();

            this.SuspendLayout();
            this.textBox1.Location = new System.Drawing.Point(92, 56);
            this.textBox1.Size = new System.Drawing.Size(100, 20);
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(292, 266);
            this.Controls.Add(this.textBox1);
            this.ResumeLayout(false);
            this.PerformLayout();

            new System.Threading.Thread(new System.Threading.ThreadStart(this.DoSomeWork)).Start();
        }

        private delegate void RefreshTextBoxEventHandler(string _sText);

        private void DoSomeWork()
        {
            for (int i = 0; i < 1000; i++)
            {
                if (i % 10 == 0)
                {
                    this.RefreshTextBox(string.Format("Wert{0}", i));
                    System.Threading.Thread.Sleep(500);
                }
            }
        }

        private void RefreshTextBox(string _sText)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new RefreshTextBoxEventHandler(this.RefreshTextBox), _sText);
            }
            else
            {
                this.textBox1.Text = _sText;
            }
        }
    }

Wichtig ist das this.InvokeRequired um abzufragen, den der Aufruf der Aktualisierungsmethode erfolgt in einem anderen Thread als der zur darstellung erzeugte Thread für das Control auf dem der Handle erstellt wurde (der Form1 Anwendung Application.Run(new Form1())😉.

08.02.2008 - 15:17 Uhr

Hrhr, also ich glaub du brauchst "dringend" nen Kaffee :p

Bitte nicht hauen ^^.. weil ich doch nur das eine Verzeichnis das ausgewählt ist zähle oder nicht?

Nein, Directory.GetFiles gibt immer die Dateien zurück die sich im angegebenen Ordner befinden. Mit GetDirectories bekommst du die Ordner zurück die sich im angegebenen Ordner befinden 🙂

Beispiel dazu:


 private void button1_Click(object sender, EventArgs e)
        {
            using (FolderBrowserDialog dlg = new FolderBrowserDialog())
            {
                dlg.ShowNewFolderButton = true;

                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    string[] asFiles = Directory.GetFiles(dlg.SelectedPath);
                    string[] asDirectories = Directory.GetDirectories(dlg.SelectedPath);

                    Console.WriteLine("In Path {0} where {1} Files and {2} Subdirectories",
                        dlg.SelectedPath, asFiles.Length, asDirectories.Length);
                }
            }
        }


            int FileCount = 0;
            for (int i = 1; i <= FileCount; i++)
            {

Wenn i also hier 1 kleiner gleich 0 ist , so ist die Bedingung immer false :p

Du meintest sicher das hier :


    string[] asFiles = Directory.GetFiles(@"C:\");

            for (int i = 0; i < asFiles.Length; i++)
            {
                Console.WriteLine(asFiles[i]);

            }

[Edit]
Hrhr, glaube brauch auch nen Kaffee, bekam das Quote nicht hin 😉

08.02.2008 - 14:57 Uhr

Du hast folgende Problematik: Woher weist du welches Notepadfenster das von dir mit Process.Start erstellte ist?

Es gibt jetzt viele Ansätze ich nenne erstmal nur einen:

Wenn man über Start->CMD notepad lala eingibt startet Notepad mit dem Fenstertitel "lala - Editor". So jetzt läge es ja nahe zu sagen okay ich nehme einen eindeutigen Fenstertitel auf den kein Benutzer der Wellt kommen würde und weis daher über FindWindow(null, "lala - Editor"); das es nur mein Editorfenster sein kann. Dazu kommt nun folgendes Problem: Weshalb es auch bei dir nicht geklappt hat (wenn du es schnell durchlaufen hast). Die geschwindigkeit bis zum Start der Anwendung Notepad. Um dieses Problem zu umgehen startest einen Thread nachdem Process.Start("notepad lala") ausgelöst hast. In diesem Thread wird eine DoNothing Schleife (also while(true)) abgearbeitet und es wird versucht über FindWindow(null, "lala - Editor") != IntPtr.Zero abgefragt, wenn der Fall true wird, so kannst nen Break machen da dein Fensterhandle gefunden wird. Natürlich solltest das ganze auch mit nen Abbruchkreterium versehen z.B nach 10 Sekunden kein Fensterhandle gefunden -> Fehler ist aufgetreten.

/PS
Über FindWindow solltest das ganze nicht unbedingt machen, habe es aber mal im beispiel so belassen. FindWindowEx wäre da noch etwas besser da hier den Class Name "Notepad" zusätzlich mit angeben kannst (also noch ein kriterium mehr damit du weist das es auch wirklich das richtige Fenster ist)

08.02.2008 - 13:50 Uhr

Du meinst sowas ?


  public class MyList
    {
        private List<string> myList = new List<string>();
        public enum MyStrings : int
        {
            NONE = 0,
            BTN_OK,
            BTN_CANCLE,
            LB_INFO,
            LB_BLA

        }

        public MyList()
        {
            this.myList.Add(string.Empty); // None
            this.myList.Add("OK"); // BTN_OK
            this.myList.Add("Cancel"); // BTN_CANCLE
            this.myList.Add("Info"); // LB_INFO
            this.myList.Add("Blablabla..."); // LB_BLA
        }

        public string GetString(MyStrings _eMyStrings)
        {
            return this.myList[(int)_eMyStrings];
        }
    }

Oder eine andere Variante?

/PS
Die Frage ist nur für was das brauchst, um strings ab zu speichern kannst die Resourcen nutzen.

08.02.2008 - 13:37 Uhr

Du wirst imemr Process.Start dafür verwenden müssen wo das dann aufrufst ist egal. Dann müsstest via FindWindow / FindWindowEx oder GetActiveWindow das Handle dazu suchen müssen. Ob es dann auf einen TabControl oder einer Form darstellst ist egal du kannst mit SetParent das Handle vom Notepad auf ein X beliebiges Control setzen.

Das dumme an der Sache ist nur die Komunikation, denn die Notepad Anwendung läuft in einen anderen Prozess und anderen Thread. Du müsstest einen Hook schreiben um die WindowsNachrichten vom Notepad zu empfangen und via SendMessage an Notepad Nachrichten versenden um eine Komunikation hinzubekommen. Und müsstest beim beenden deines Programms vorher darauf achten das auch Notepad sich beendet - wüsste nicht was passiert wenn das nicht tust - glaube deine Anwendung würde dennoch weiterlaufen.

Achja, und man muss natürlich beachten das wenn dir wie gesagt das Handle von Notepad holst es zu dem Zeitpunkt ausgeschlossen ist, dass genau zeitgleich jemand manuell Notepad startet.

07.02.2008 - 17:31 Uhr

Hrm, kenne das Win CE Framework leider nicht genau geht da den PostMessage? Wenn ja kannst auch alternativ das nutzen vorallem geht dir dann nicht der aktive Focus verloren. Ansonsten SendMessage mit WM_CLICK versenden um den Activen Control den Focus zu geben über GUITHREADINFO könntest zB das Aktuelle Fenster bzw. das Handle suchen.


[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam,
   IntPtr lParam);


[DllImport("user32.dll")]
static extern bool GetGUIThreadInfo(uint idThread, out GUITHREADINFO lpgui);

// code
GetGUIThreadInfo(0, out guiThreadInfo);


[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern IntPtr SendMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

/PS
Wie gesagt keine Ahnung was unter CE geht und was nicht.