[C#] Unmanaged Code (SendInput) Problem

Munro

Lt. Commander
Mitglied seit
02.06.2003
Beiträge
126
Renomée
0
Standort
Österreich
Hi!

Ich hab hier eine kleine Applikation zum Testen (in der Konsole). Das Programm soll die Tastenkombination STRG+ALT+ENDE "simulieren".

Nun habe ich versucht aus der Win API (benutze XP) aus der User32.dll die Funktion SendInput (http://msdn.microsoft.com/library/d...eference/keyboardinputfunctions/sendinput.asp) aufzurufen - da man ja seit Windows 2000 SendInput anstatt von keybd_event benutzen sollte.

Nur irgendwie will das nicht klappen - bekomme immer nur die Errorcodes 2, 5, 87 (http://msdn.microsoft.com/library/d...-us/debug/base/system_error_codes__0-499_.asp)

Errorcode 2 bekam ich als ich die Applikation aus dem Explorer heraus startete und nicht mit dem Debugger (weiters funktionierten danach keine Links-Klicks mehr mit der Maus :-[ )

Definitionen der Structures und der Funktion:
Code:
[StructLayout(LayoutKind.Sequential)]
        public struct MOUSEINPUT
        {
            public int dx;
            public int dy;
            public int mouseData;
            public int dwFlags;
            public int time;
            public int dwExtraInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct KEYBDINPUT
        {
            public short wVk;
            public short wScan;
            public int dwFlags;
            public int time;
            public int dwExtraInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct HARDWAREINPUT
        {
            public int uMsg;
            public short wParamL;
            public short wParamH;
        }

        [StructLayout(LayoutKind.Explicit,Size=28)]
        public struct INPUT
        {
            [FieldOffset(0)]
            public int type;
            [FieldOffset(4)]
            public MOUSEINPUT mi;
            [FieldOffset(4)]
            public KEYBDINPUT ki;
            [FieldOffset(4)]
            public HARDWAREINPUT hi;
        }
        [DllImport("User32.dll", SetLastError = true)]
        public static extern int SendInput(int nInputs, ref INPUT[] pInputs, int cbSize);

Nun das Array welches STRG+ALT+ENDE (keydown und danach wieder keyup) beinhaltet:
Code:
            INPUT []input = new INPUT[6];
            input[0].type = 1;
            input[0].ki.wVk = 0x11; // Keycode für STRG
            input[0].ki.wScan = 0;
            input[0].ki.dwFlags = 0x00; // Keydown
            input[0].ki.time = 0;
            input[0].ki.dwExtraInfo = 0;
            input[1].type = 1;
            input[1].ki.wVk = 0x12;  // Keycode für ALT
            input[1].ki.wScan = 0;
            input[1].ki.dwFlags = 0x00;
            input[1].ki.time = 0;
            input[1].ki.dwExtraInfo = 0;
            input[2].type = 1;
            input[2].ki.wVk = 0x23;  // Keycode für ENDE
            input[2].ki.wScan = 0;
            input[2].ki.dwFlags = 0x00;
            input[2].ki.time = 0;
            input[2].ki.dwExtraInfo = 0;
            input[3].type = 1;
            input[3].ki.wVk = 0x23;
            input[3].ki.wScan = 0;
            input[3].ki.dwFlags = 0x02; // Keyup
            input[3].ki.dwExtraInfo = 0;
            input[4].type = 1;
            input[4].ki.wVk = 0x12;
            input[4].ki.wScan = 0;
            input[4].ki.dwFlags = 0x02; // Keyup
            input[4].ki.time = 0;
            input[4].ki.dwExtraInfo = 0;
            input[5].type = 1;
            input[5].ki.wVk = 0x11;
            input[5].ki.wScan = 0;
            input[5].ki.dwFlags = 0x02; // Keyup
            input[5].ki.time = 0;
            input[5].ki.dwExtraInfo = 0;
        
            SendInput(input.Length, ref input, Marshal.SizeOf(input[0]));
            if (Marshal.GetLastWin32Error() != 0)
            {
                Console.WriteLine(Marshal.GetLastWin32Error());
            }

Dieser Code verursacht beim Ausführen im Debugger einen Errorcode 5, im Datei Explorer gestartet einen Errorcode 2 (und hat zusätzlich eben meine Maus fast lahmgelegt).

Wenn ich "[StructLayout(LayoutKind.Sequential)]" wegnehme, dann kommt ein Errorcode 87.

Benutze .net Framework 2.0 und Windows XP.

Falls damit schon mal jemand gearbeitet hat und mir helfen könnte wäre ich sehr dankbar :)

lg, nixtreffen

PS.: Sämtliche Codebeispiele die ich im Internet gefunden habe, mit jeweils immer unterschiedlichen Typdefinitionen in den Structures haben alle samt nicht funktioniert :-[ :-/
 
Du darfst KeyDown und KeyUp anscheinend nicht zusammen senden. Folgender Code funktioniert bei mir:
Code:
		[StructLayout(LayoutKind.Sequential)]
		struct MOUSEINPUT
		{
			public int dx;
			public int dy;
			public int mouseData;
			public int dwFlags;
			public int time;
			public IntPtr dwExtraInfo;
		}

		[StructLayout(LayoutKind.Sequential)]
		struct KEYBDINPUT
		{
			public short wVk;
			public short wScan;
			public int dwFlags;
			public int time;
			public IntPtr dwExtraInfo;
		}

		[StructLayout(LayoutKind.Sequential)]
		struct HARDWAREINPUT
		{
			public int uMsg;
			public short wParamL;
			public short wParamH;
		}

		[StructLayout(LayoutKind.Explicit)]
		struct INPUT
		{
			[FieldOffset(0)]
			public int type;
			[FieldOffset(4)]
			public MOUSEINPUT mi;
			[FieldOffset(4)]
			public KEYBDINPUT ki;
			[FieldOffset(4)]
			public HARDWAREINPUT hi;
		}

		[DllImport("user32.dll")]
		static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);

			INPUT[] input = new INPUT[3];
			input[0].type = 1;
			input[0].ki.wVk = 0x11; // Keycode für STRG
			input[0].ki.dwFlags = 0x00; // Keydown

			input[1].type = 1;
			input[1].ki.wVk = 0x12;  // Keycode für ALT
			input[1].ki.dwFlags = 0x00;

			input[2].type = 1;
			input[2].ki.wVk = 0x23;  // Keycode für ENDE
			input[2].ki.dwFlags = 0x00;

			SendInput((uint) input.Length, input, Marshal.SizeOf(input[0]));

			input[0].type = 1;
			input[0].ki.wVk = 0x23;
			input[0].ki.dwFlags = 0x02; // Keyup

			input[1].type = 1;
			input[1].ki.wVk = 0x12;
			input[1].ki.dwFlags = 0x02; // Keyup

			input[2].type = 1;
			input[2].ki.wVk = 0x11;
			input[2].ki.dwFlags = 0x02; // Keyup

			SendInput((uint) input.Length, input, Marshal.SizeOf(input[0]));
 
Danke, so funktionierts :)

Obwohl Marshal.GetLastWin32Error() noch immer 5 zurückgibt, was ja "Access_Denied" bedeutet - komisch komisch ;D

Trotzdem noch mal danke.

lg, nixtreffen

Edit: Der Errorcode tritt aber auch nur beim "Keyup" auf - seltsam
 
Zuletzt bearbeitet:
GetLastError gibt nur dann etwas brauchbares zurück, wenn SendInput eine 0 zurückgibt.
 
Ich hab grad gelesen, dass: some functions set the last-error code to 0 on success and others do not.

Die Funktion SendInput gibt ja bei Erfolg die Anzahl der "Tastenschläge" aus -> also 3 im Fall von Keyup und GetLastWin32Error() gibt 5 zurück (obwohl ja eine 0 als fehlerfrei gilt)

GetLastWin32Error() nach dem Keydown aufgerufen gibt nämlich 0 zurück - deshlab war ich verwirrt, aber anscheinend liegt das an SendInput :)

Edit: ich hab nun den return wert der SendInput abgefragt und nun ist auch GetLastWin32Error() beim KeyUp 0 (also so wie es sein soll)
 
Zuletzt bearbeitet:
Edit: ich hab nun den return wert der SendInput abgefragt und nun ist auch GetLastWin32Error() beim KeyUp 0 (also so wie es sein soll)
Also so gibt GetLastWin32Error() 5 zurück:
Code:
SendInput(bla, blubb, lala);
int err = Marshal.GetLastWin32Error();
und so nicht:
Code:
uint success = SendInput(bla, blubb, lala);
int err = Marshal.GetLastWin32Error();
?

Hmm, das dürfte eigentlich nicht sein. Das klingt irgendwie so, als würde da auf dem Stack etwas schieflaufen.
 
Irgendwie beim 1.ten und 2.ten mal ausführen kam noch der Errorcode 5. Danach hab ich den Returnwert abgefragt und dann kam er nicht mehr - war aber nur Zufall, denn es läuft jetzt auch ohne abfragen alles ganz normal mit Errorcode 0 usw.. (sogar nur 1 Array mit Keydown und Keyup funktioniert jetzt:o *noahnung* - vlt. lag mein Fehler einfach nur da, dass ich time und Extrainfo immer nen Wert zugewiesen hab *noahnung* )


Auf jeden Fall nochmal danke, denn erst durch dich hat das ganze funktioniert :D


lg, nixtreffen
 
Wahrscheinlich hast Du GetLastWin32Error() aufgerufen, obwohl SendInput() erfolgreich war. SendInput() setzt den Fehlercode wie gesagt nur, wenn es wirklich fehlschlägt.
Korrekt wäre also:
Code:
uint success = SendInput(bla, blubb, lala);
if(success == 0) {
  int err = Marshal.GetLastWin32Error();
}
Die Fehlercodes, die Du erhalten hast, kamen also höchstwahrscheinlich nicht von SendInput(), sondern von irgendeinem zuvor aufgerufenen API.
 
Zurück
Oben Unten