public MorphicResult <RegistryKey, MorphicUnit> OpenSubKey(string name, bool writable = false) { // configure key access requirements PInvoke.Kernel32.ACCESS_MASK accessMask = (PInvoke.Kernel32.ACCESS_MASK) 131097 /* READ_KEY [0x2_0000 | KEY_NOTIFY = 0x0010 | KEY_ENUMERATE_SUB_KEYS = 0x0008 | KEY_QUERY_VALUE = 0x0001] */; if (writable == true) { accessMask |= (PInvoke.Kernel32.ACCESS_MASK) 131078 /* WRITE_KEY [0x2_0000 | KEY_CREATE_SUB_KEY = 0x0004 | KEY_SET_VALUE = 0x0002] */; } // TODO: make "notify" access an option (although it looks like it's already in the READ access mask specified above) accessMask |= 0x0010 /* KEY_NOTIFY */; // open our key SafeRegistryHandle subKeyHandle; var openKeyErrorCode = PInvoke.AdvApi32.RegOpenKeyEx(_handle, name, PInvoke.AdvApi32.RegOpenKeyOptions.None, accessMask, out subKeyHandle); switch (openKeyErrorCode) { case PInvoke.Win32ErrorCode.ERROR_SUCCESS: break; default: // NOTE: in the future, we may want to consider returning a specific result (i.e. "could not open for write access" etc.) return(MorphicResult.ErrorResult()); } var subKey = new RegistryKey(subKeyHandle); return(MorphicResult.OkResult(subKey)); }
// NOTE: we return both success/failure and a set of values so that we can return a partially list in case of partial failure public override async Task <(MorphicResult <MorphicUnit, MorphicUnit>, Values)> GetAsync(SettingGroup settingGroup, IEnumerable <Setting> settings) { var success = true; Values values = new Values(); try { Ini ini = this.serviceProvider.GetRequiredService <Ini>(); await ini.ReadFile(settingGroup.Path); foreach (Setting setting in settings) { string?value = ini.GetValue(setting.Name); if (value is not null) { values.Add(setting, value); } } } catch { success = false; } return(success ? MorphicResult.OkResult() : MorphicResult.ErrorResult(), values); }
// private MorphicResult <GetValueAndTypeAsObjectResult, RegistryValueError> GetValueAndTypeAsObject(string?name) { var handleAsUIntPtr = (UIntPtr)(_handle.DangerousGetHandle().ToInt64()); // pass 1: set dataSize to zero (so that RegQueryValueEx returns the size of the value uint dataSize = 0; ExtendedPInvoke.RegistryValueType valueType; var queryValueErrorCode = ExtendedPInvoke.RegQueryValueEx(handleAsUIntPtr, name, IntPtr.Zero, out valueType, IntPtr.Zero, ref dataSize); switch (queryValueErrorCode) { case PInvoke.Win32ErrorCode.ERROR_SUCCESS: break; case PInvoke.Win32ErrorCode.ERROR_FILE_NOT_FOUND: return(MorphicResult.ErrorResult(RegistryValueError.ValueDoesNotExist)); default: // NOTE: in the future, we may want to consider returning a specific result (i.e. "could not open for write access" etc.) return(MorphicResult.ErrorResult(RegistryValueError.Win32Error((int)queryValueErrorCode))); } // pass 2: capture the actual data var getValueResult = RegistryKey.GetValueForHandleAsUInt32(handleAsUIntPtr, name, dataSize); if (getValueResult.IsError) { return(MorphicResult.ErrorResult(getValueResult.Error !)); } var data = getValueResult.Value; return(MorphicResult.OkResult(new GetValueAndTypeAsObjectResult(data, valueType))); }
/* helper functions */ // some more details: https://blog.quarkslab.com/playing-with-the-windows-notification-facility-wnf.html private static MorphicResult <byte[], MorphicUnit> QueryWnfStateData(ExtendedPInvoke.WNF_STATE_NAME stateName) { const uint MAX_BUFFER_LENGTH = 4096; uint bufferSize = MAX_BUFFER_LENGTH; var pointerToBuffer = Marshal.AllocHGlobal((int)bufferSize); try { uint changeStamp; var queryWnfStateDataResult = ExtendedPInvoke.NtQueryWnfStateData(ref stateName, IntPtr.Zero, IntPtr.Zero, out changeStamp, pointerToBuffer, ref bufferSize); if (queryWnfStateDataResult != 0) { return(MorphicResult.ErrorResult()); } var bufferSizeAsInt = (int)bufferSize; var result = new byte[bufferSizeAsInt]; Marshal.Copy(pointerToBuffer, result, 0, bufferSizeAsInt); return(MorphicResult.OkResult(result)); } finally { Marshal.FreeHGlobal(pointerToBuffer); } }
public async Task <MorphicResult <MorphicUnit, MorphicUnit> > ApplyPreferencesAsync(Preferences preferences, bool captureCurrent = false, bool async = false) { var success = true; if (preferences.Default is null) { // NOTE: unsure whether this is an error condition or a success condition return(MorphicResult.ErrorResult()); } foreach ((string solutionId, SolutionPreferences solutionPreferences) in preferences.Default) { if (this.All.TryGetValue(solutionId, out Solution? solution)) { if (captureCurrent) { solutionPreferences.Previous ??= new Dictionary <string, object?>(); } try { await solution.ApplyAsync(solutionPreferences); } catch { success = false; } } } return(success ? MorphicResult.OkResult() : MorphicResult.ErrorResult()); }
/// <summary> /// Invokes the action. /// </summary> /// <param name="source">Button ID, for multi-button bar items.</param> /// <param name="toggleState">New state, if the button is a toggle.</param> /// <returns></returns> public async Task <MorphicResult <MorphicUnit, MorphicUnit> > InvokeAsync(string?source = null, bool?toggleState = null) { MorphicResult <MorphicUnit, MorphicUnit> result; try { try { result = await this.InvokeAsyncImpl(source, toggleState); } catch (Exception e) when(!(e is ActionException || e is OutOfMemoryException)) { throw new ActionException(e.Message, e); } } catch (ActionException e) { App.Current.Logger.LogError(e, $"Error while invoking action for bar {this.Id} {this}"); if (e.UserMessage is not null) { MessageBox.Show($"There was a problem performing the action:\n\n{e.UserMessage}", "Custom MorphicBar", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } result = MorphicResult.ErrorResult(); } finally { // record telemetry data for this action await this.SendTelemetryForBarAction(source, toggleState); } return(result); }
public static MorphicResult <MorphicUnit, Win32ApiError> GenerateApplicationCommandEvent(IntPtr sourceHwnd, IntPtr targetHwnd, ushort uDevice, ushort dwKeys, AppCommand appCommand) { if ((uDevice & 0xF000) != uDevice) { throw new ArgumentOutOfRangeException(nameof(uDevice)); } IntPtr wParam = sourceHwnd; // var cmd = (ushort)appCommand & 0x0FFF; IntPtr lParam = (IntPtr)(((cmd | uDevice) << 16) | dwKeys); // NOTE: Microsoft does not seem to provide clear documentation on the successful result from SendMessage when sending WM_APPCOMMAND; the following error condition is based on observation only (which is why we use debug.assert instead of returning an error); // [as we expand our use of WM_APPCOMMAND beyond our initial use case of fire-and-forget system commands such as volume up/down/mute, we should revisit this; sending commands like COPY/PASTE to a window may actually return a different result, based on APPCOMMAND] var sendMessageResult = PInvoke.User32.SendMessage(targetHwnd, PInvoke.User32.WindowMessage.WM_APPCOMMAND, wParam, lParam); if (sendMessageResult != IntPtr.Zero) { // unexpected error var win32ErrorCode = PInvoke.Kernel32.GetLastError(); Debug.Assert(false, "SendMessage WM_APPCOMMAND returned an unexpected result; win32 error code is: " + win32ErrorCode.ToString()); } return(MorphicResult.OkResult()); }
public static MorphicResult <MMDeviceEnumerator, WindowsComError> CreateNew() { // get a Type reference for MMDeviceEnumerator Type MMDeviceEnumeratorType; try { MMDeviceEnumeratorType = Type.GetTypeFromCLSID(new Guid(CLSID_MMDeviceEnumerator), true) !; } catch { // TODO: consider providing a more specific exception result return(MorphicResult.ErrorResult(WindowsComError.ComException(new COMException()))); } MMDeviceEnumerator result; try { // NOTE: objects created by Activator.CreateInstance do not need to be manually freed var mmDeviceEnumeratorAsNullable = Activator.CreateInstance(MMDeviceEnumeratorType) as IMMDeviceEnumerator; if (mmDeviceEnumeratorAsNullable is null) { throw new COMException(); } result = new MMDeviceEnumerator(mmDeviceEnumeratorAsNullable !); } catch { // TODO: in the future, consider throwing different exceptions for different failure conditions throw new COMException(); } return(MorphicResult.OkResult(result)); }
public MorphicResult <MMDevice, WindowsComError> GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role) { IMMDevice?immDevice; var result = _mmDeviceEnumerator.GetDefaultAudioEndpoint(dataFlow, role, out immDevice); if (result != ExtendedPInvoke.S_OK) { if (result == ExtendedPInvoke.E_NOTFOUND) { throw new NoDeviceIsAvailableException(); } else { // TODO: consider throwing more granular exceptions here var comException = new COMException("IMMDeviceEnumerator.GetDefaultAudioEndpoint failed", Marshal.GetExceptionForHR(result)); return(MorphicResult.ErrorResult(WindowsComError.ComException(comException))); } } if (immDevice is null) { // NOTE: this code should never be executed since GetDefaultAudioEndpoint should have returned an HRESULT of E_POINTER if it failed var comException = new COMException("IMMDeviceEnumerator.GetDefaultAudioEndpoint returned a null pointer", new NullReferenceException()); return(MorphicResult.ErrorResult(WindowsComError.ComException(comException))); } var mmDevice = MMDevice.CreateFromIMMDevice(immDevice !); return(MorphicResult.OkResult(mmDevice)); }
// private static MorphicResult <XmlNode?, MorphicUnit> GetRibbonTabNodeFromXmlDocument(XmlDocument xmlDocument, string ribbonId) { XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(xmlDocument.NameTable); xmlNamespaceManager.AddNamespace("mso", WordRibbon.MSO_NAMESPACE); var msoTabsParentNode = xmlDocument.SelectSingleNode("mso:customUI/mso:ribbon/mso:tabs", xmlNamespaceManager); if (msoTabsParentNode is null) { // parent tabs node doesn't exist; we are missing our template ribbons return(MorphicResult.ErrorResult()); } var msoTabNodes = xmlDocument.SelectNodes("mso:customUI/mso:ribbon/mso:tabs/mso:tab", xmlNamespaceManager); if (msoTabNodes is null) { // child tab nodes (i.e. ribbon templates) don't exist return(MorphicResult.ErrorResult()); } foreach (XmlNode?msoTabNode in msoTabNodes !) { if (msoTabNode?.Attributes["id"].Value == ribbonId) { return(MorphicResult.OkResult(msoTabNode)); } } // if we did not find the ribbon in our list of tabs, return null return(MorphicResult.OkResult <XmlNode?>(null)); }
// TODO: consider adding an "async" operation which can capture multiple settings in parallel; for now we're keeping it simple and using serial captures public async Task <MorphicResult <MorphicUnit, MorphicUnit> > CapturePreferencesAsync(Preferences preferences) { var success = true; List <Task> tasks = new List <Task>(); preferences.Default ??= new Dictionary <string, SolutionPreferences>(); foreach ((string?solutionId, Solution? solution) in this.All) { if (!preferences.Default.TryGetValue(solutionId, out SolutionPreferences? solutionPreferences)) { solutionPreferences = new SolutionPreferences(); preferences.Default.Add(solutionId, solutionPreferences); } // NOTE: CaptureAsync is adding data to the class (which we only have a reference to) var captureAsyncResult = await solution.CaptureAsync(solutionPreferences); if (captureAsyncResult.IsError == true) { success = false; continue; } } return(success ? MorphicResult.OkResult() : MorphicResult.ErrorResult()); }
public static MorphicResult <AudioEndpoint, WindowsComError> GetDefaultAudioOutputEndpoint() { // get a reference to our default output device var createDeviceEnumeratorResult = MMDeviceEnumerator.CreateNew(); if (createDeviceEnumeratorResult.IsError == true) { return(MorphicResult.ErrorResult(createDeviceEnumeratorResult.Error !)); } var mmDeviceEnumerator = createDeviceEnumeratorResult.Value !; // // NOTE: .NET should automatically release the defaultAudioOutputEndpoint var getDefaultAudioEndpointResult = mmDeviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia); if (getDefaultAudioEndpointResult.IsError == true) { return(MorphicResult.ErrorResult(getDefaultAudioEndpointResult.Error !)); } var defaultAudioOutputEndpoint = getDefaultAudioEndpointResult.Value !; // activate the endpoint so we can read/write its volume and mute state, etc. Guid IID_IAudioEndpointVolume = new Guid("5CDF2C82-841E-4546-9722-0CF74078229A"); var activateResult = defaultAudioOutputEndpoint.Activate(IID_IAudioEndpointVolume, CLSCTX.CLSCTX_INPROC_SERVER); if (activateResult.IsError == true) { return(MorphicResult.ErrorResult(activateResult.Error !)); } var audioEndpointVolumeAsObject = activateResult.Value !; var audioEndpointVolume = (IAudioEndpointVolume)audioEndpointVolumeAsObject; var result = new AudioEndpoint(audioEndpointVolume); return(MorphicResult.OkResult(result)); }
/// <summary>Gets the values of the given settings.</summary> // NOTE: we return both success/failure and a list of results so that we can return partial results in case of partial failure public override async Task <(MorphicResult <MorphicUnit, MorphicUnit>, Values)> GetAsync(SettingGroup settingGroup, IEnumerable <Setting> settings) { var success = true; Values values = new Values(); foreach (Setting setting in settings) { object?value; var getResult = await this.GetAsync(setting); if (getResult.IsSuccess == true) { value = getResult.Value; if (!(value is NoValue)) { values.Add(setting, value); } } else { success = false; // not captured; skip to the next setting continue; } } return((success ? MorphicResult.OkResult() : MorphicResult.ErrorResult()), values); }
// public static MorphicResult <string, GetPathToExecutableForFileError> GetAssociatedExecutableForFile(string path) { StringBuilder pathToExecutable = new StringBuilder(ExtendedPInvoke.MAX_PATH + 1); var resultCode = ExtendedPInvoke.FindExecutable(path, null, pathToExecutable); if (resultCode.ToInt64() > 32) { // success return(MorphicResult.OkResult(pathToExecutable.ToString())); } else { // failure switch (resultCode.ToInt64()) { case (Int64)ExtendedPInvoke.ShellExecuteErrorCode.SE_ERR_FNF: return(MorphicResult.ErrorResult(GetPathToExecutableForFileError.FileNotFound)); case (Int64)ExtendedPInvoke.ShellExecuteErrorCode.SE_ERR_PNF: return(MorphicResult.ErrorResult(GetPathToExecutableForFileError.PathIsInvalid)); case (Int64)ExtendedPInvoke.ShellExecuteErrorCode.SE_ERR_ACCESSDENIED: return(MorphicResult.ErrorResult(GetPathToExecutableForFileError.AccessDenied)); case (Int64)ExtendedPInvoke.ShellExecuteErrorCode.SE_ERR_OOM: return(MorphicResult.ErrorResult(GetPathToExecutableForFileError.OutOfMemoryOrResources)); case (Int64)ExtendedPInvoke.ShellExecuteErrorCode.SE_ERR_NOASSOC: return(MorphicResult.ErrorResult(GetPathToExecutableForFileError.NoAssociatedExecutable)); default: return(MorphicResult.ErrorResult(GetPathToExecutableForFileError.UnknownShellExecuteErrorCode)); } } }
// NOTE: we return both success/failure and a list of results so that we can return partial results in case of partial failure public override async Task <(MorphicResult <MorphicUnit, MorphicUnit>, Values)> GetAsync(SettingGroup settingGroup, IEnumerable <Setting> settings) { var success = true; Values values = new Values(); foreach (Setting setting in settings) { try { SystemSettingItem?settingItem = this.GetSettingItem(setting.Name); if (settingItem is null) { success = false; // skip to the next setting continue; } // NOTE: this is another area where changing the result of GetValue to a MorphicResult<,> could provide clear and granular success/error result object?value = await settingItem !.GetValue(); values.Add(setting, value); } catch { success = false; // skip to the next setting continue; } } return(success ? MorphicResult.OkResult() : MorphicResult.ErrorResult(), values); }
public override async Task <MorphicResult <MorphicUnit, MorphicUnit> > SetAsync(SettingGroup settingGroup, Values values) { var success = true; foreach ((Setting setting, object?value) in values) { SystemSettingItem?settingItem = this.GetSettingItem(setting.Name); if (settingItem is null) { success = false; // skip to the next setting continue; } try { await settingItem !.SetValue(value); } catch { success = false; } } return(success ? MorphicResult.OkResult() : MorphicResult.ErrorResult()); }
public static async Task <MorphicResult <MorphicUnit, MorphicUnit> > SendKeysAsync(FunctionArgs args) { await SelectionReader.Default.ActivateLastActiveWindow(); System.Windows.Forms.SendKeys.SendWait(args["keys"]); return(MorphicResult.OkResult()); }
private static async Task <MorphicResult <MorphicUnit, MorphicUnit> > ClearClipboardAsync(uint numberOfRetries, TimeSpan interval) { // NOTE from Microsoft documentation (something to think about when working on this in the future...and perhaps something we need to handle): /* "The Clipboard class can only be used in threads set to single thread apartment (STA) mode. * To use this class, ensure that your Main method is marked with the STAThreadAttribute attribute." * https://docs.microsoft.com/es-es/dotnet/api/system.windows.forms.clipboard.clear?view=net-5.0 */ for (var i = 0; i < numberOfRetries; i++) { try { // NOTE: some developers have reported unhandled exceptions with this function call, even when inside a try...catch block. If we experience that, we may need to look at our threading model, UWP alternatives, and Win32 API alternatives. Clipboard.Clear(); return(MorphicResult.OkResult()); } catch { // failed to copy to clipboard; wait an interval and then try again await Task.Delay(interval); } } App.Current.Logger.LogDebug("ReadAloud: Could not clear selected text from the clipboard."); return(MorphicResult.ErrorResult()); }
internal static MorphicResult <bool, MorphicUnit> GetMuteState() { try { var getDefaultAudioOutputEndpointResult = Morphic.WindowsNative.Audio.AudioEndpoint.GetDefaultAudioOutputEndpoint(); if (getDefaultAudioOutputEndpointResult.IsError == true) { return(MorphicResult.ErrorResult()); } var audioEndpoint = getDefaultAudioOutputEndpointResult.Value !; // if we didn't get a state in the request, try to reverse the state var getMasterMuteStateResult = audioEndpoint.GetMasterMuteState(); if (getMasterMuteStateResult.IsError == true) { return(MorphicResult.ErrorResult()); } var state = getMasterMuteStateResult.Value !; return(MorphicResult.OkResult(state)); } catch { return(MorphicResult.ErrorResult()); } }
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously public static async Task <MorphicResult <MorphicUnit, MorphicUnit> > SetVolumeAsync(FunctionArgs args) #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously { // NOTE: ideally we should switch this functionality to use AudioEndpoint.SetMasterVolumeLevel instead // [it may not be practical to do that, however, if AudioEndpoint.SetMasterVolumeLevel doesn't activate to on-screen volume change dialog in Windows 10/11; to be tested...] var percent = Convert.ToUInt32(args["amount"]); // clean up the percent argument (if it's not even, is out of range, etc.) if (percent % 2 != 0) { percent += 1; } percent = System.Math.Clamp(percent, 0, 100); if (args["direction"] == "up") { var sendCommandResult = Morphic.WindowsNative.Audio.Utils.VolumeUtils.SendVolumeUpCommand(percent); if (sendCommandResult.IsError == true) { return(MorphicResult.ErrorResult()); } } else { var sendCommandResult = Morphic.WindowsNative.Audio.Utils.VolumeUtils.SendVolumeDownCommand(percent); if (sendCommandResult.IsError == true) { return(MorphicResult.ErrorResult()); } } return(MorphicResult.OkResult()); }
public async static Task <MorphicResult <MorphicUnit, MorphicUnit> > ShowMenuAsync(FunctionArgs args) { // NOTE: this internal function is only called by the MorphicBar's Morphie menu button await App.Current.ShowMenuAsync(null, Morphic.Client.Menu.MorphicMenu.MenuOpenedSource.morphicBarIcon); return(MorphicResult.OkResult()); }
public static async Task <MorphicResult <MorphicUnit, MorphicUnit> > DarkModeAsync(FunctionArgs args) { // if we have a "value" property, this is a multi-segmented button and we should use "value" instead of "state" bool on; if (args.Arguments.Keys.Contains("value")) { on = (args["value"] == "on"); } else if (args.Arguments.Keys.Contains("state")) { on = (args["state"] == "on"); } else { System.Diagnostics.Debug.Assert(false, "Function 'darkMode' did not receive a new state"); on = false; } var setDarkModeStateResult = await Functions.SetDarkModeStateAsync(on); if (setDarkModeStateResult.IsError == true) { return(MorphicResult.ErrorResult()); } return(MorphicResult.OkResult()); }
// private static async Task <MorphicResult <GetRemovableDisksAndDrivesResult, MorphicUnit> > GetRemovableDisksAndDrivesAsync() { // get a list of all disks (but not non-disks such as CD-ROM drives) var getAllDisksResult = await Morphic.WindowsNative.Devices.Disk.GetAllDisksAsync(); if (getAllDisksResult.IsError == true) { Debug.Assert(false, "Cannot get list of disks"); return(MorphicResult.ErrorResult()); } // filter out all disks which are not removable var allDisks = getAllDisksResult.Value !; var removableDisks = new List <Morphic.WindowsNative.Devices.Disk>(); foreach (var disk in allDisks) { var getIsRemovableResult = disk.GetIsRemovable(); if (getIsRemovableResult.IsError == true) { Debug.Assert(false, "Cannot determine if disk is removable"); return(MorphicResult.ErrorResult()); } var diskIsRemovable = getIsRemovableResult.Value !; if (diskIsRemovable) { removableDisks.Add(disk); } } // now get all the drives associated with our removable disks var removableDrives = new List <Morphic.WindowsNative.Devices.Drive>(); foreach (var removableDisk in removableDisks) { var getDrivesForDiskResult = await removableDisk.GetDrivesAsync(); if (getDrivesForDiskResult.IsError == true) { Debug.Assert(false, "Cannot get list of drives for removable disk"); // gracefully degrade; skip this disk continue; } var drivesForRemovableDisk = getDrivesForDiskResult.Value !; removableDrives.AddRange(drivesForRemovableDisk); } var result = new GetRemovableDisksAndDrivesResult { AllDisks = allDisks, RemovableDisks = removableDisks, RemovableDrives = removableDrives }; return(MorphicResult.OkResult(result)); }
/// <summary> /// Save the given preferences /// </summary> /// <param name="service"></param> /// <param name="preferences">The preferences to save</param> /// <returns><code>MorphicResult.OkResult()</code> if the request succeeded, <code>MorphicResult.ErrorResult()</code> otherwise</returns> public static async Task <MorphicResult <MorphicUnit, MorphicUnit> > SaveAsync(this HttpService service, Preferences preferences) { if (preferences.UserId is string userId) { var success = await service.Send(() => HttpRequestMessageExtensions.Create(service, string.Format("v1/users/{0}/preferences/{1}", userId, preferences.Id), HttpMethod.Put, preferences)); return(success ? MorphicResult.OkResult() : MorphicResult.ErrorResult()); } return(MorphicResult.ErrorResult()); }
// public static MorphicResult <MorphicUnit, Win32ApiError> SendVolumeMuteToggleCommand(IntPtr sourceHwnd) { var generateAppCommandResult = VolumeUtils.InternalSendAppCommand(sourceHwnd, Keyboard.Utils.AppCommandUtils.AppCommand.APPCOMMAND_VOLUME_MUTE); if (generateAppCommandResult.IsError == true) { return(MorphicResult.ErrorResult(generateAppCommandResult.Error !)); } return(MorphicResult.OkResult()); }
/// <summary>Gets the value of this setting.</summary> public async Task <MorphicResult <object?, MorphicUnit> > GetValueAsync() { var getResult = await this.SettingGroup.SettingsHandler.GetAsync(this); if (getResult.IsError == true) { return(MorphicResult.ErrorResult()); } this.CurrentValue = getResult.Value; return(MorphicResult.OkResult(this.CurrentValue)); }
public MorphicResult <MorphicUnit, MorphicUnit> Activate(IntPtr?hWndBeingDeactivated = null, bool emulateClickActivation = false) { var sendMessageResult = PInvoke.User32.SendMessage( this.hWnd, PInvoke.User32.WindowMessage.WM_ACTIVATE, emulateClickActivation ? ExtendedPInvoke.WA_CLICKACTIVE : ExtendedPInvoke.WA_ACTIVE, hWndBeingDeactivated ?? IntPtr.Zero ); return((sendMessageResult == IntPtr.Zero) ? MorphicResult.OkResult() : MorphicResult.ErrorResult()); }
// public static MorphicResult <String?, MorphicUnit> GetHighContrastModeDefaultColorScheme() { var getHighContrastInfoResult = DisplayUtils.GetHighContrastInfo(); if (getHighContrastInfoResult.IsError == true) { return(MorphicResult.ErrorResult()); } var highContrastInfo = getHighContrastInfoResult.Value !; return(MorphicResult.OkResult(highContrastInfo.DefaultColorScheme)); }
public MorphicResult <MorphicUnit, MorphicUnit> RegisterForValueChangeNotification(RegistryKeyChangedEvent eventHandler) { if (_disposed == true) { return(MorphicResult.ErrorResult()); } var waitHandle = new ManualResetEvent(false); // NOTE: REG_NOTIFY_CHANGE_LAST_SET will trigger on any changes to the key's values // NOTE: registration will auto-unregister after the wait handle is trigger once. Registration will also auto-unregister when the RegistryKey is closed/disposed PInvoke.Win32ErrorCode regNotifyErrorCode; try { // NOTE: if _handle has been disposed, this will throw an ObjectDisposedException regNotifyErrorCode = PInvoke.AdvApi32.RegNotifyChangeKeyValue(_handle, false, PInvoke.AdvApi32.RegNotifyFilter.REG_NOTIFY_CHANGE_LAST_SET, waitHandle.SafeWaitHandle, true); } catch (ObjectDisposedException ex) { return(MorphicResult.ErrorResult()); } // switch (regNotifyErrorCode) { case PInvoke.Win32ErrorCode.ERROR_SUCCESS: break; default: return(MorphicResult.ErrorResult()); } // add our registry key (and accompanying wait handle) to the notify pool // NOTE: this must be the only code which is allowed to add to the notify pool; if we change this behavior, we must re-evaluate and QA the corresponding lock strategy change lock (s_registryKeyNotifyPoolLock) { var notifyInfo = new RegistryKeyNotificationInfo(this, waitHandle, eventHandler); s_registerKeyNotifyPool.Add(notifyInfo); if (s_registryKeyNotifyPoolThread is null) { s_registryKeyNotifyPoolThread = new Thread(RegistryKey.ListenForRegistryKeyChanges); s_registryKeyNotifyPoolThread.IsBackground = true; // set up as a background thread (so that it shuts down automatically with our application, even if all the RegistryKeys weren't fully disposed) s_registryKeyNotifyPoolThread.Start(); } else { // trigger our notify pool thread to see and watch for the new entries s_registryKeyNotifyPoolUpdatedEvent.Set(); } } return(MorphicResult.OkResult()); }
public static MorphicResult <bool, MorphicUnit> GetHighContrastModeIsOn() { var getHighContrastInfoResult = DisplayUtils.GetHighContrastInfo(); if (getHighContrastInfoResult.IsError == true) { return(MorphicResult.ErrorResult()); } var highContrastInfo = getHighContrastInfoResult.Value !; return(MorphicResult.OkResult(highContrastInfo.FeatureIsOn)); }