Windows Azure Cloud Storage ermöglicht es Ihnen bereits ab 0,10€ pro GB/Monat die Vorteile der Cloud zu nutzen.
Willkommen bei dotnet-snippets.de! Snippet hinzufügen Login Registrieren
Snippets in der Datenbank: 1551 | Anzahl registrierter User: 1841 | Besucher online: 273
Hauptmenü
Home
Top Ten
Zufälliger Snippet
FAQs
.NET Community
dotnet-forum.de
dotnet-kicks.de
Social

RSS Feeds
Rss Alle Snippets
Rss C#
Rss VB.NET
Rss C++
Rss ASP.NET
Partner
Member of Microsoft Community Leader/Insider Program (CLIP)

Windows Forms Anwendungs-Sessions verwalten


Autor: Timo Pijnappel
Sprache: C#
Bewertung: 7,4
(1 Bewertung)
Anzahl der Aufrufe: 5359
  
Kick it on dotnet-kicks.de  

Beschreibung:

Diese Klasse hilft bei der Verwaltung von Anwendungssitzungen.

Es ist möglich zu prüfen, welche Sitzungen im System bereits laufen und diese zu benachrichtigen. Bei der Benachrichtigung kann ein Objekt an den Prozess gesendet werden (z.B. Kommandozeilenparameter)


Funktionen
- Starten eines Prozesses mit einer benannten Session
- Herunterfahren der laufenden Session
- Herausfinden, ob eine Session mit dem gewünschten Namen bereits existiert
- Benachrichtigung der "alten" Session
- Übermittlung von Startup-Parametern an die "alte" Session (z.B. CommandLine)
- Auflisten aller laufenden Sessions


Funktionen der Klasse (alle static)

void SessionStart(string sessionName)
void SessionShutdown()
bool SessionIsActive(string sessionName)
bool NotifyActiveSession(string sessionName, object attachment)
List GetAllActiveSessionNames()

event SessionNotifiedEventHandler Notified


Beispielszenario - SingleInstance:
Die Anwendung soll nur einmal gestartet werden können.

Wird sie nochmal gestartet, benachrichtigt der neue Prozess die "alte" Sitzung, übermittelt dabei seine Kommandozeilenparameter und wird dann beendet.

Die neue Sitzung empfängt die Daten und kann darauf reagieren (z.B. ein neues Fenster im eigenen Prozess öffnen).


Abgelegt unter: C#, Process, Assembly, Session.



C#
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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Windows.Forms;
using System.Reflection;

namespace Sessions
{
    public delegate void SessionNotifiedEventHandler(object objectReceivedFromCallingProcess);
    public class SessionManager : IDisposable
    {
        #region Private fields
        /// <summary>
        /// Name of the active session
        /// </summary>
        private string _sessionName;

        /// <summary>
        /// String to identify the current assembly
        /// This string will be attached to the session window name
        /// to make it unique. This id could also be used to identify
        /// groups of sessions.
        /// </summary>
        private readonly string _appendToSessionNametoEnsureItsUnique;

        /// <summary>
        /// The native Window to communicate across processes using 
        /// WM_COPYDATA
        /// </summary>
        private CommunicationWindow _communicator;
        #endregion

        #region Singleton implementation - This object exists only once per process
        /// <summary>
        /// Holds SessionManager instance
        /// </summary>
        private static SessionManager _instance;

        /// <summary>
        /// Private Constructor to allow initialization only from within this class
        /// </summary>
        private SessionManager()
        {
            _sessionName = "";

            // This could be any string, I use the Assembly GUID here.
            // It will be trimmed from the window title later to read the session name
            _appendToSessionNametoEnsureItsUnique = GetAssemblyGUID();
        }

        /// <summary>
        /// Creates the SessionManager Instance if required
        /// and returns it (or the existing one)
        /// </summary>
        private static SessionManager Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new SessionManager();

                return _instance;
            }
        }
        #endregion

        #region Methods - These methods will be used by the static Interface methods
        /// <summary>
        /// Starts a new Session with the given name 
        /// by creating a (hidden) session window
        /// </summary>
        /// <param name="sessionName">Name of the session</param>
        private void StartNew(string sessionName)
        {
            _sessionName = sessionName;

            // Initialize the Native Window
            // The window will be invisibly running in background, only to be found by the findwindow method
            _communicator = new CommunicationWindow(_sessionName + _appendToSessionNametoEnsureItsUnique);
        }

        /// <summary>
        /// Shuts the session down by closing and destroying the native window
        /// </summary>
        private void Shutdown()
        {
            if (_communicator != null)
                _communicator.DestroyHandle();
        }

        /// <summary>
        /// Searches for the Session Window
        /// </summary>
        /// <param name="sessionName"></param>
        /// <returns></returns>
        private bool IsActive(string sessionName)
        {
            IntPtr handle = FindWindow(IntPtr.Zero, sessionName + _appendToSessionNametoEnsureItsUnique);
            if (handle != IntPtr.Zero)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// Notifies another session about the launch of a new process.
        /// The target session should now act as it was called. 
        /// The calling Session will exit immediately after calling.
        /// </summary>
        /// <param name="sessionName">Name of the session to send the notification to</param>
        /// <param name="attachment">Attachment to be contained within the message. Usually command line string</param>
        /// <returns>true if the message was sent, false if the target session was not found</returns>
        private bool NotifySession(string sessionName, object attachment)
        {
            // Search for the window of the session to notify
            IntPtr hWnd = FindWindow(IntPtr.Zero, sessionName + _appendToSessionNametoEnsureItsUnique);
            if (hWnd != IntPtr.Zero)
            {
                // This is the Trick! Use a pinned handle to have a global pointer to the byte array.
                // The pinned pointer allows us to access the memory location from another process
                GCHandle bufferHandle = new GCHandle();
                try
                {
                    byte[] buffer;
                    COPYDATASTRUCT dataStructForMessage = new COPYDATASTRUCT();
                    if (attachment != null)
                    {
                        buffer = MakeBytes(attachment);
                        bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); // here we pin the buffer

                        dataStructForMessage.dwData = 0;
                        dataStructForMessage.cbData = buffer.Length;
                        //get the address of the pinned buffer
                        dataStructForMessage.lpData = bufferHandle.AddrOfPinnedObject();
                    }

                    GCHandle dataStructHandle = GCHandle.Alloc(dataStructForMessage, GCHandleType.Pinned); // the COPYDATASTRUCT must also be pinned!!
                    try
                    {
                        // Send the message to the target process and attach the structure
                        SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, dataStructHandle.AddrOfPinnedObject());
                        return true;
                    }
                    finally
                    {
                        dataStructHandle.Free();  // Free the handle to let the memory cleanup do its magic!
                    }
                }
                finally
                {
                    if (bufferHandle.IsAllocated)
                        bufferHandle.Free(); // Free second handle too!
                }
            }
            return false;
        }

        /// <summary>
        /// Enumerates all Windows of the system and returns a list of those
        /// ending with the string defined in _appendToSessionNametoEnsureItsUnique
        /// (without _appendToSessionNametoEnsureItsUnique)
        /// </summary>
        /// <returns>List of Session Names</returns>
        private List<string> GetListOfSessionWidows()
        {
            List<string> windowNames = new List<string>();

            // Enumeration with nested delegate function for API callback
            EnumWindows(delegate(IntPtr hWnd, IntPtr lParam)
            {
                string windowText = GetWindowText(hWnd);
                if (windowText.EndsWith(_appendToSessionNametoEnsureItsUnique))
                    windowNames.Add(windowText.Replace(_appendToSessionNametoEnsureItsUnique, ""));
                return 1;
            }, new IntPtr(0));

            return windowNames;
        }
        #endregion

        #region Static Interface Methods - Use these to call from the outside

        /// <summary>
        /// Occurs when another process was launched targetting the same session name.
        /// The other process will exit after this event was handled.
        /// </summary>
        public static event SessionNotifiedEventHandler Notified;


        /// <summary>
        /// Starts the Session.
        /// </summary>
        /// <param name="sessionName">Name of the session.</param>
        public static void SessionStart(string sessionName)
        {
            Instance.StartNew(sessionName);
        }

        /// <summary>
        /// Shuts the Session down.
        /// </summary>
        public static void SessionShutdown()
        {
            Instance.Shutdown();
        }

        /// <summary>
        /// Determinse if a session with the given name is already active.
        /// </summary>
        /// <param name="sessionName">Name of the session.</param>
        /// <returns>true if a session name is already used by another session</returns>
        public static bool SessionIsActice(string sessionName)
        {
            return Instance.IsActive(sessionName);
        }


        /// <summary>
        /// Notifies the active session and attaches an object to be sent.
        /// </summary>
        /// <param name="sessionName">Name of the session.</param>
        /// <param name="attachment">The attachment.</param>
        /// <returns>true if the message was sent, false if the target session was not found</returns>
        public static bool NotifyActiveSession(string sessionName, object attachment)
        {
            return Instance.NotifySession(sessionName, attachment);
        }

        /// <summary>
        /// Gets all active session names.
        /// </summary>
        /// <returns>List of names of running sessions</returns>
        public static List<string> GetAllActiveSessionNames()
        {
            return Instance.GetListOfSessionWidows();
        }
        #endregion

        #region Windows API Methods
        [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
        static extern IntPtr FindWindow(IntPtr zeroOnly, string lpWindowName);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);

        private delegate int EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern int GetWindowText(IntPtr hWnd, [Out] StringBuilder lpString, int nMaxCount);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern int GetWindowTextLength(IntPtr hWnd);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern IntPtr SendMessage(IntPtr hWnd, int nMsg, IntPtr wParam, IntPtr lParam);

        const short WM_COPYDATA = 74;

        struct COPYDATASTRUCT
        {
            public int dwData;
            public int cbData;
            public IntPtr lpData;
        }
        #endregion

        #region NativeWindow used to send and receive Inter Process Messages
        /// <summary>
        /// The CommunicationWindow class is used to identify the current session
        /// from any process by using FindWindow. The Window Name will be the 
        /// Session id followed by a GUID to make sure the window name is unique.
        /// </summary>
        private sealed class CommunicationWindow : NativeWindow
        {
            public CommunicationWindow(string sessionname)
            {
                CreateParams cp = new CreateParams();
                cp.Caption = sessionname;
                CreateHandle(cp);
            }

            /// <summary>
            /// Override WndProc to receive Messages from other Processes
            /// 
            /// Messages to catch are WM_COPYDATA messages. the lParam Value 
            /// points to a structure containing the commandline used to open the session 
            /// </summary>
            /// <param name="m">The Message received</param>
            protected override void WndProc(ref Message m)
            {
                if (m.Msg == WM_COPYDATA)
                {
                    // Get the Copydata structure from the pointer in lParam
                    COPYDATASTRUCT dataStructFromMessage = (COPYDATASTRUCT)Marshal.PtrToStructure(m.LParam, typeof(COPYDATASTRUCT));

                    // This will be the object encapsulated in the message
                    object receivedObject = null;

                    if (dataStructFromMessage.cbData > 0 && dataStructFromMessage.lpData != IntPtr.Zero)
                    {
                        // Copy the bytes in the struct to our local buffer
                        byte[] buffer = new byte[dataStructFromMessage.cbData];
                        Marshal.Copy(dataStructFromMessage.lpData, buffer, 0, buffer.Length);

                        //deserialize the buffer to a new object
                        receivedObject = MakeObject(buffer);
                    }

                    // Raise event
                    if (Notified != null) // if evenHandlers are connected
                        Notified(receivedObject);
                }
                else
                    base.WndProc(ref m);
            }
        }
        #endregion

        #region Tool functions
        /// <summary>
        /// Determines the GUID of the current assembly
        /// </summary>
        /// <returns>GUID as string</returns>
        private string GetAssemblyGUID()
        {
            string id = "";
            foreach (object attr in Assembly.GetExecutingAssembly().GetCustomAttributes(true))
            {
                if (attr is GuidAttribute)
                    id = ((GuidAttribute)attr).Value;
            }
            return id;
        }

        /// <summary>
        /// Gets the window text.
        /// </summary>
        /// <param name="hWnd">The handle to the window.</param>
        /// <returns>Caption of the window</returns>
        private string GetWindowText(IntPtr hWnd)
        {
            StringBuilder sb = new StringBuilder(GetWindowTextLength(hWnd) + 1);
            GetWindowText(hWnd, sb, sb.Capacity);
            return sb.ToString();
        }



        /// <summary>
        /// Deserializes an object in memory.
        /// </summary>
        /// <param name="buffer">Byte array of the object received from an external process</param>
        /// <returns>Deserialized object. Requires casting into its correct type.</returns>
        private static object MakeObject(byte[] buffer)
        {
            using (MemoryStream stream = new MemoryStream(buffer))
            {
                return new BinaryFormatter().Deserialize(stream);
            }
        }

        /// <summary>
        /// Serializes an object in memory into a byte array. 
        /// This can be used to attach any object to the COPYDATASTRUCT
        /// structure and send it to another process.the receivubg process
        /// must know which type to expect to make this work.
        /// </summary>
        /// <param name="obj">An object to serialize</param>
        /// <returns>A byte array containing the object.</returns>
        private static byte[] MakeBytes(Object obj)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                new BinaryFormatter().Serialize(stream, obj);
                return stream.ToArray();
            }
        }
        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            Shutdown();
        }

        #endregion
    }
}
Sie haben Fragen zu diesem Snippet oder brauchen Hilfe bei der .NET Entwicklung?
Freundliche und kompetente Entwickler helfen Ihnen gern weiter im Forum für .NET Entwicklung.



Kommentare:
(Zum Schreiben von Kommentaren bitte anmelden.)



Diese Snippets könnten für Sie interessant sein:
[C#] Ein kleiner Konsolen Taschenrechner
[C#] Prüft Zeitformat auf 24 Stunden
[C#] Datei/Ordner durch Erweiterungsmethoden abfragen
[C#] GetCharts
[C#] XML in DataTable laden
[C#] Generische Between Methode
[ASP.net] Formularelement fokusieren auf Ajax Seiten
[C#] Quadratwurzel ziehen
[C#] Cast to Enum
[C#] ASP.NET: Metatags und Titel zur Laufzeit setzen
[C#] Aufrufenden Typ identifizieren
[C#] Kaufmännisches Runden in Decimal
[C#] WMI Getter
[C#] Sql Server Instanzen finden
[C#] WPF: Image aus dem Web in Image-Element anzeigen
[C#] Quoted Printable Encoder
[C#] URL auslesen
[C#] User-Verwaltung in eine ASP.NET Website einbauen
[C#] GUID des aktuellen Assembly ermitteln
[C#] User-Management für WPF Smart Client Anwendung
[C#] Silverlight Anwendung erstellen
[C#] User-Verwaltung in eine WinForm einbauen
[C#] Java WebService aus einem WinForms-Client aufrufen
[C#] C# Ist ein POINT zwischen ... und ...
[C#] NumTextBox (Kurzversion)
[C#] Another Bin-Watch (Console)
[C#] SystemIconsImageListWrapper
[C#] WatchedList
[C#] Datenbankverbindung herstellen
[C#] Einfache Ini Klasse
[C#] Youtube Download Klasse für C#
[C#] InputBox WPF C#
[C#] C# Ordner auslesen und in Liste speichern "rekursiv"
[C#] C# XOR Crypt
[C#] externes Programm aufrufen
[C#] Prozess starten und Tasten senden (SendKeys)
[C#] Linklabel - Standard E-Mail-Client start
[C#] Verzeichnis im Windows Explorer öffnen
[C#] Process beenden
[VB.NET] Prozessprioritaet aendern
[C#] Process Helper Class
[VB.NET] Alle hängenden Prozesse beenden
[VB.NET] Hängende Processe beenden
[C#] Alle hängenden Prozesse beenden
[C#] Anwendung unter XP/Vista als Admin starten [Übersetzung]
[C#] Prüfen ob ein bestimmter Prozess gerade ausgeführt wird
[C#] Service Helper Class
[C#] Owner/Ersteller eines Prozesses ermitteln
[C#] Memory-Verbrauch des aktuellen Prozesses ermitteln
[C#] Kompilierzeit ermitteln
[C#] Shadow Copying
[VB.NET] Shadow Copying
[C#] Alle geladenen Assemblies ermitteln
[C#] Liefert alle Assemblies aus dem Global Assembly Cache (GAC)
[C#] Versionsnummer der Assembly ermitteln
[C#] Loads an embedded resource file of the calling assembly.
[C#] Dateiname des aktuellen Programms ermitteln
[VB.NET] Assembly Verzeichnis
[C#] Assembly Verzeichnis
[C#] .NET Komponente für COM zur Verfügung stellen
[VB.NET] Assembly Verzeichnis 2
[VB.NET] Eigene Form aus ClassLibrary DLL Aufrufen
[C#] Culture und UICulture in ASP.NET Sesion speichern (Facade)
[C#] Sessionverwaltung einmal anders
[C#] Size of object in bytes

schlecht sehr gut
1 2 3 4 5 6 7 8 9 10
Nur angemeldete User können Snippets bewerten.