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.
CodePudding user response:
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)));
}