public static string[] GetPhysicalMonitorNames(IntPtr hMonitor) { var mm = new MemPtr(); string[] sOut = null; PHYSICAL_MONITOR pm; uint nmon = 0; if (!GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, out nmon)) { return(null); } int cb = Marshal.SizeOf <PHYSICAL_MONITOR>(); int size = cb * (int)nmon; mm.Alloc(size); try { if (GetPhysicalMonitorsFromHMONITOR(hMonitor, size, mm)) { sOut = new string[size]; int i; for (i = 0; i < nmon; i++) { pm = mm.ToStructAt <PHYSICAL_MONITOR>(i * cb); sOut[i] = pm.szPhysicalMonitorDescription; } DestroyPhysicalMonitors((uint)size, mm); } else { sOut = new string[] { NativeErrorMethods.FormatLastError() }; } mm.Free(); } catch { mm.Free(); } return(sOut); }
/// <summary> /// Internal message pump handler and event dispatcher. /// </summary> /// <param name="m"></param> /// <remarks></remarks> protected override void WndProc(ref Message m) { switch (m.Msg) { case FileSystemMonitor.WM_SIGNAL: { // don't block on the main thread, block on the watching thread, instead. if (System.Threading.Monitor.TryEnter(_WaitList)) { int c; int i; // there are items waiting to be dequeued, let's dequeue one. i = _lastIndex; c = _WaitList.Count - 1; // make sure we're not jumping ahead of a previous cleaning. if (c >= i) { if (_WaitList[i] is object) { // post the events so that whatever is watching this folder can do its thing. _WaitList[i]._Info = (FileNotifyInfo)_WaitList[i]._Info.Clone(); WatchNotifyChange?.Invoke(this, _WaitList[i]); // remove the item from its slot in the queue, thereby // eliminating any chance the same event will be fired, again. _WaitList[i] = null; } // post a message to the queue cleaner. if there are more files, it will send the pump back this way. _lastIndex = i + 1; User32.PostMessage(Handle, FileSystemMonitor.WM_SIGNAL_CLEAN, IntPtr.Zero, IntPtr.Zero); } System.Threading.Monitor.Exit(_WaitList); } // going too fast? we'll get there, eventually. At least we know they're queuing. else if (_WaitList.Count > 0) { User32.PostMessage(Handle, FileSystemMonitor.WM_SIGNAL, IntPtr.Zero, IntPtr.Zero); } break; } case FileSystemMonitor.WM_SIGNAL_CLEAN: { // don't block on the main thread, block on the watching thread, instead. if (System.Threading.Monitor.TryEnter(_WaitList)) { // we have a lock, let's clean up the queue int i; int c = _WaitList.Count - 1; for (i = c; i >= 0; i -= 1) { // we want to only remove slots that have been dequeued. if (_WaitList[i] is null) { _WaitList.RemoveAt(i); } } // reset the lastindex to 0, indicating that any items still in the queue have not fired, yet. _lastIndex = 0; System.Threading.Monitor.Exit(_WaitList); // if we still have more signals in the queue, tell the message pump to keep on truckin'. if (_WaitList.Count > 0) { User32.PostMessage(Handle, FileSystemMonitor.WM_SIGNAL, IntPtr.Zero, IntPtr.Zero); } } else { // oh snap! can't lock it, let's send another clean message to make sure we do finally execute, eventually. User32.PostMessage(Handle, FileSystemMonitor.WM_SIGNAL_CLEAN, IntPtr.Zero, IntPtr.Zero); } break; } case FileSystemMonitor.WM_SIGNAL_OPEN: { _isWatching = true; MonitorOpened?.Invoke(this, new EventArgs()); break; } case FileSystemMonitor.WM_SIGNAL_CLOSE: { _isWatching = false; if (m.LParam.ToInt32() >= 1) { MonitorClosed?.Invoke(this, new MonitorClosedEventArgs(MonitorClosedState.ClosedOnError, m.LParam.ToInt32(), NativeErrorMethods.FormatLastError((uint)m.LParam.ToInt32()))); } else { MonitorClosed?.Invoke(this, new MonitorClosedEventArgs(MonitorClosedState.Closed)); } break; } default: { base.WndProc(ref m); break; } } }
/// <summary> /// Enumerate all display monitors. /// </summary> /// <returns>An array of PrinterDeviceInfo objects.</returns> /// <remarks></remarks> public static MonitorDeviceInfo[] EnumMonitors() { var minf = _internalEnumerateDevices <MonitorDeviceInfo>(DevProp.GUID_DEVINTERFACE_MONITOR, ClassDevFlags.DeviceInterface | ClassDevFlags.Present); var mon = new Monitors(); DISPLAY_DEVICE dd; dd.cb = (uint)Marshal.SizeOf <DISPLAY_DEVICE>(); var mm = new MemPtr(); mm.Alloc(dd.cb); mm.UIntAt(0) = dd.cb; if (minf is object && minf.Count() > 0) { foreach (var x in minf) { foreach (var y in mon) { if (MultiMon.EnumDisplayDevices(y.DevicePath, 0, mm, MultiMon.EDD_GET_DEVICE_INTERFACE_NAME)) { dd = mm.ToStruct <DISPLAY_DEVICE>(); DEVMODE dev = new DEVMODE(); dev.dmSize = (ushort)Marshal.SizeOf <DEVMODE>(); dev.dmDriverExtra = 0; var mm2 = new MemPtr(65535 + dev.dmSize); var b = MultiMon.EnumDisplaySettingsEx(y.DevicePath, 0xffffffff, ref dev, 0); if (!b) { var s = NativeErrorMethods.FormatLastError(); } mm2.Free(); if (dd.DeviceID.ToUpper() == x.DevicePath.ToUpper()) { x.Source = y; break; } } } } } mm.Free(); if (minf is null) { return(null); } Array.Sort(minf, new Comparison <MonitorDeviceInfo>((x, y) => { if (x.FriendlyName is object && y.FriendlyName is object) { return(string.Compare(x.FriendlyName, y.FriendlyName)); } else { return(string.Compare(x.Description, y.Description)); } })); return(minf); }