I would like to start and stop the audio and video screen recording function in Windows programmatically in C#/.NET 6 - preferably in a console program.
Manually, this can be done by holding down the Windows/Menu key and the Alt-key while pressing R on the keyboard.
I have tried to use the user32.dll and InterOp to send Alt (MENU) + LWIN + R key without success. Since I have a GeForce ShadowPlay-enabled video card, I have also tried to capture video sending Alt + F9, but this also fails.
I do not want to encode the audio and video in the program, just start and stop the Windows audio/video recording. Is there an API for this in Windows or any other way to start/stop recording?
using System.Runtime.InteropServices;
namespace StartStopWindowsBuiltInAudioVideoRecorder
{
internal class NativeWin32
{
public const ushort KEYEVENTF_KEYUP = 0x0002;
public enum VK : ushort
{
MENU = 0x12,
F9 = 0x78,
R = 0x52,
LWIN = 0x5B,
}
public struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public long time;
public uint dwExtraInfo;
};
[StructLayout(LayoutKind.Explicit, Size = 28)]
public struct INPUT
{
[FieldOffset(0)] public uint type;
[FieldOffset(4)] public KEYBDINPUT ki;
};
[DllImport("user32.dll")]
public static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);
// Method will hold down Windows and Left Alt while pressing R
internal static void StartOrStopVideoRecorder()
{
NativeWin32.INPUT structInput;
structInput = new NativeWin32.INPUT();
structInput.type = (uint)1;
structInput.ki.wScan = 0;
structInput.ki.time = 0;
structInput.ki.dwFlags = 0;
structInput.ki.dwExtraInfo = 0;
//Press Alt key
structInput.ki.wVk = (ushort)NativeWin32.VK.MENU;
NativeWin32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));
Thread.Sleep(100);
//Press LeftWin key
structInput.ki.wVk = (ushort)NativeWin32.VK.LWIN;
NativeWin32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));
Thread.Sleep(100);
//Press the R key
structInput.ki.wVk = (ushort)NativeWin32.VK.R;//vk;
NativeWin32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));
Thread.Sleep(500);
//Release the R key
structInput.ki.dwFlags = NativeWin32.KEYEVENTF_KEYUP;
structInput.ki.wVk = (ushort)NativeWin32.VK.R;//vk;
NativeWin32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));
Thread.Sleep(100);
//Release LeftWin key
structInput.ki.wVk = (ushort)NativeWin32.VK.LWIN;
NativeWin32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));
Thread.Sleep(100);
//Release the ALT key
structInput.ki.wVk = (ushort)NativeWin32.VK.MENU;
NativeWin32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));
}
}
}
I expected the code to start the audio/video recording, but nothing happens. Other software reacts to these keys if configured to listen for them, so the NativeWin32 API still works as it should.
You were missing some stuff, first of all
SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
Sendinput expects an input array with: MouseInput,KeyboardInput,HardwareInput
In the mouse input, dwExtraInfo is a IntPtr public readonly IntPtr dwExtraInfo;
You were using SendInput with ref which should also not be used as far as I know.
SendInput((uint)1, structInput, Marshal.SizeOf(typeof(INPUT)));
Also the Thread.Sleeps are useless, but that’s irrelevant.
public const ushort KEYEVENTF_KEYUP = 0x0002;
public enum VK : ushort
{
MENU = 0x12,
F9 = 0x78,
R = 0x52,
LWIN = 0x5B,
}
public struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public long time;
public uint dwExtraInfo;
};
public struct INPUT
{
public int type;
public InputUnion u;
}
[StructLayout(LayoutKind.Explicit)]
public struct InputUnion
{
[FieldOffset(0)] public readonly MouseInput mi;
[FieldOffset(0)] public KeyboardInput ki;
[FieldOffset(0)] public readonly HardwareInput hi;
}
[StructLayout(LayoutKind.Sequential)]
public struct MouseInput
{
public readonly int dx;
public readonly int dy;
public readonly uint mouseData;
public readonly uint dwFlags;
public readonly uint time;
public readonly IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct KeyboardInput
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public readonly uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct HardwareInput
{
public readonly uint uMsg;
public readonly ushort wParamL;
public readonly ushort wParamH;
}
[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
[DllImport("user32.dll")]
private static extern IntPtr GetMessageExtraInfo();
// Method will hold down Windows and Left Alt while pressing R
internal static void StartOrStopVideoRecorder()
{
INPUT[] structInput =
{
new INPUT
{
type = 1,
u = new InputUnion
{
ki = new KeyboardInput
{
wVk = 0,
dwFlags = 0x0,
dwExtraInfo = GetMessageExtraInfo()
}
}
} };
//Press Alt key
structInput[0].u.ki.wVk = (ushort)VK.MENU;
SendInput((uint)1, structInput, Marshal.SizeOf(typeof(INPUT)));
//Press LeftWin key
structInput[0].u.ki.wVk = (ushort)VK.LWIN;
SendInput((uint)1, structInput, Marshal.SizeOf(typeof(INPUT)));
//Press the R key
structInput[0].u.ki.wVk = (ushort)VK.R;//vk;
SendInput((uint)1, structInput, Marshal.SizeOf(typeof(INPUT)));
//Thread.Sleep(500);
//Release the R key
structInput[0].u.ki.dwFlags = KEYEVENTF_KEYUP;
structInput[0].u.ki.wVk = (ushort)VK.R;//vk;
SendInput((uint)1, structInput, Marshal.SizeOf(typeof(INPUT)));
//Release LeftWin key
structInput[0].u.ki.wVk = (ushort)VK.LWIN;
SendInput((uint)1, structInput, Marshal.SizeOf(typeof(INPUT)));
//Release the ALT key
structInput[0].u.ki.wVk = (ushort)VK.MENU;
SendInput((uint)1, structInput, Marshal.SizeOf(typeof(INPUT)));
}