Beispiel #1
0
            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));
            }
Beispiel #2
0
        // 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);
        }
Beispiel #3
0
            //
            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)));
            }
Beispiel #4
0
        /* 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);
            }
        }
Beispiel #5
0
        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);
        }
Beispiel #7
0
        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));
        }
Beispiel #11
0
        // 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());
        }
Beispiel #12
0
        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));
        }
Beispiel #13
0
        /// <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());
        }
Beispiel #17
0
        public static async Task <MorphicResult <MorphicUnit, MorphicUnit> > SendKeysAsync(FunctionArgs args)
        {
            await SelectionReader.Default.ActivateLastActiveWindow();

            System.Windows.Forms.SendKeys.SendWait(args["keys"]);
            return(MorphicResult.OkResult());
        }
Beispiel #18
0
        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());
        }
Beispiel #19
0
        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());
            }
        }
Beispiel #20
0
#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());
        }
Beispiel #21
0
        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());
        }
Beispiel #22
0
        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());
        }
Beispiel #23
0
        //
        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));
        }
Beispiel #27
0
        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));
        }
Beispiel #29
0
            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));
        }