Search code examples
c#.netwinforms-interop

Does the value of APPCOMMAND_VOLUME_UP and APPCOMMAND_VOLUME_DOWN really matter as long as it starts with 0xA and 0x9?


I'm using the below code to modify system volume programmatically. I would be honest with you that I got the same code from the internet from a lot of sources.

    //private const int APPCOMMAND_VOLUME_UP = 0xA0000;
    private const int APPCOMMAND_VOLUME_UP = 0xAFFFF;
    private const int APPCOMMAND_VOLUME_DOWN = 0x90000;
    private const int WM_APPCOMMAND = 0x319;

    [DllImport("user32.dll")]
    public static extern IntPtr SendMessageW(IntPtr hWnd, int Msg,
        IntPtr wParam, IntPtr lParam);

    private void btnVolumeUp_Click(object sender, RoutedEventArgs e)
    {
        SendMessageW(new WindowInteropHelper(this).Handle, WM_APPCOMMAND, new WindowInteropHelper(this).Handle,
            (IntPtr)APPCOMMAND_VOLUME_UP);
    }

I've observed that the values of the two variables APPCOMMAND_VOLUME_UP and APPCOMMAND_VOLUME_DOWN don't really matter as long as the up value starts with 0xA and the down value starts with 0x9. I have tried with many different values between 0000 and FFFF for both UP and DOWN scenarios. Is it really true that the values don't matter?

I don't have much knowledge about the interop calls. Can someone please explain the significance of those values?

Thank you in advance!


Solution

  • There is no "value". The LPARAM argument encodes three distinct properties:

    • The command, for example APPCOMMAND_VOLUME_UP is 10 (0x0A).
    • The device, indicates how the command was generated and can be key, mouse or oem.
    • The "keys", indicates which modifiers were in effect when the command was generated. Like shift/ctrl for a keyboard and the clicked mouse button for a mouse

    These three properties are encoded the way bitfields work in the C language. The bit pattern in hex is 0xDCCCKKKK where C is command, D is device, K is keys.

    Since you synthesize the message yourself, you have no meaningful way to report the device or the keys. Nor does it matter, you should simply use 0 (device = keyboard, no modifier keys). Do note that the value you use now is not correct, 0xAFFFF does not use a correct keys value and you are saying that the CTRL and SHIFT keys are down. Probably not enough to terminally confuse the shell, these modifier keys don't affect the way that particular command works.

    So a sane implementation would look like:

    public enum AppCommand {
        VolumeDown = 9
        VolumeUp = 10,
        // etc..
    }
    
    private void SendAppCommand(AppCommand cmd) {
        var hwnd = new WindowInteropHelper(this).Handle;
        SendMessageW(hwnd, WM_APPCOMMAND, hwnd, (int)cmd << 16);
    }