Knowledge Base Nr: 00286 keymouse.cpp - http://www.swe-kaiser.de

Downloads: Prototyp ScreenshotRemoteApp ScreenshotRemoteApp Beschreibung

Win32/.NET/c#: tastendrücke/mousevents an anderen prozess schicken (c#-gui und c++-dll)

  
//unter XP/Win2000 funktioniert SetForegroundWindow() anders als unter NT! (siehe MSN)
//da das umschalten auf einen anderen prozess nicht mehr funktioniert empfehle ich folgendes:
//- zuerst fernzusteuerndes programm aktivieren
//- danach das fernsteuernde programm
//- dadurch dass das fernsteuernde programm den focus verliert (Hide()) erhält das zuvor
// aktive fernzusteuernde programm wieder den focus und kann fernbedient werden

////////////////// cs-file

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace Remote
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

[DllImport("remotedll2.dll")]
private static extern void DoMouseClick(int x, int y, bool bRightClick, bool bDoubleClick, bool bDown, bool bUp);
[DllImport("remotedll2.dll")]
private static extern int SendKeyToProcess(string lpszProcessname, string lpszKeys
, int nDelayBefore, int nDelayBetween, int nDelayAfter);

private void button1_Click(object sender, EventArgs e)
{
string keys = textBox1.Text;
string lpszProcessname = textBox2.Text;
int nDelay = 1;

Hide();

int res = SendKeyToProcess(lpszProcessname, keys, 500, 10, 500);

labelResKey.Text = "res = " + res.ToString();

Show();
}

private void button2_Click(object sender, EventArgs e)
{
try
{
Process app = new Process();

app.StartInfo.FileName = textBox3.Text;
app.Start();
}
catch (Win32Exception ex)
{
MessageBox.Show("'" + textBox3.Text + "' can not be started!\n\n" + ex.Message, "Process Error");
}
}

private void timer1_Tick(object sender, EventArgs e)
{
Point mouse = Control.MousePosition;

labelMousePos.Text = "mouse " + mouse.X + "/" + mouse.Y;
}

private void buttonLeft_Click(object sender, EventArgs e)
{
DoMouseClick(int.Parse(textBoxX.Text), int.Parse(textBoxY.Text)
, false, false, true, true);//, bool bRightClick, bool bDoubleClick, bool bDown, bool bUp);
}

private void buttonRight_Click(object sender, EventArgs e)
{
DoMouseClick(int.Parse(textBoxX.Text), int.Parse(textBoxY.Text)
, true, false, true, true);//, bool bRightClick, bool bDoubleClick, bool bDown, bool bUp);
}

private void buttonDoubleLeft_Click(object sender, EventArgs e)
{
DoMouseClick(int.Parse(textBoxX.Text), int.Parse(textBoxY.Text)
, false, true, true, true);//, bool bRightClick, bool bDoubleClick, bool bDown, bool bUp);
}
}
}

//statt der eigenen dll-funktion kann unter c# besser die SendKeys-Klasse verwendet werden (siehe VS-Hilfe)
//achtung: die SetForegroundWindow()-einschränkungen unter XP/200 gelzten auch für das hilfe-beispiel!
[DllImport("User32.dll")]
private static extern short GetAsyncKeyState(System.Int32 vKey);
[DllImport("User32.dll")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);

private int DoSendCSKeys(string sWindowTitle, string keys, int nKeyDelayBefore, int nKeyDelayBetween, int nKeyDelayAfter)
{
if (sWindowTitle != "")
{
IntPtr calculatorHandle = FindWindow(null, sWindowTitle);

if (calculatorHandle == IntPtr.Zero)
{
return -1;
}

SetForegroundWindow(calculatorHandle);
}

Thread.Sleep(nKeyDelayBefore);
SendKeys.SendWait(keys);
Thread.Sleep(nKeyDelayAfter);

return 0;
}

////////////////// h-file

#ifdef REMOTEDLL2_EXPORTS
#define REMOTEDLL2_API __declspec(dllexport)
#else
#define REMOTEDLL2_API __declspec(dllimport)
#endif

extern "C"
{
REMOTEDLL2_API void DoMouseClick(int x, int y, bool bRightClick, bool bDoubleClick, bool bDown, bool bUp);
REMOTEDLL2_API int SendKeyToProcess(const char* lpszProcessname, const char* lpszKeys
, int nDelayBefore, int nDelayBetween, int nDelayAfter);
}

///////////////// cpp-file

// remotedll2.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include <stdio.h>
#include <tlhelp32.h>
#include "remotedll2.h"

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}


///////////////////////////////////////////////////////////////


// tastendrücke an den eigenen prozess schicken.
// hilfreich um aus einer c-dll fremdapplikationen zu triggern
// z.b. nach beeenden eines threads
// int nErr = DoKeysPress("F8#", 100);
// int nErr = DoKeysPress("SHIFT+F8#", 100);
// int nErr = DoKeysPress("ALT+F8#", 100);
// int nErr = DoKeysPress("CTRL+F8#", 100);
// int nErr = DoKeysPress("F7#F7#F8#", 100);
REMOTEDLL2_API int DoKeysPress(const char* szKeys, int nDelay)
{
int nKeysPressed = 0;

char szError[100] = {0};
char szTmp[100] = {0};
bool bWithAlt = false;
bool bWithShift = false;
bool bWithCtrl = false;

int i = 0;
for (int n=0; szKeys[n]; n++)
{
szTmp[i++] = szKeys[n];

if (szKeys[n] == '+')
{
szTmp[i-1] = 0;
i = 0;

if (stricmp(szTmp, "ALT") == 0)
bWithAlt = true;
else if (stricmp(szTmp, "SHIFT") == 0)
bWithShift = true;
else if (stricmp(szTmp, "CTRL") == 0)
bWithCtrl = true;
else
{
sprintf(szError, "<%s> muss sein ALT, SHIFT oder CTRL", szTmp);
MessageBox(NULL, szTmp, "Fehler in DoKeysPress()", MB_OK|MB_ICONERROR);
return -1;
}
}
else if (szKeys[n] == '#')
{
szTmp[i-1] = 0;
i = 0;

int nWert = -1;

/* VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */
/* VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */
if (stricmp(szTmp, "A") == 0)
nWert = 'A';
else if (stricmp(szTmp, "B") == 0)
nWert = 'B';
else if (stricmp(szTmp, "C") == 0)
nWert = 'C';
else if (stricmp(szTmp, "D") == 0)
nWert = 'D';
else if (stricmp(szTmp, "E") == 0)
nWert = 'E';
else if (stricmp(szTmp, "F") == 0)
nWert = 'F';
else if (stricmp(szTmp, "G") == 0)
nWert = 'G';
else if (stricmp(szTmp, "H") == 0)
nWert = 'H';
else if (stricmp(szTmp, "I") == 0)
nWert = 'I';
else if (stricmp(szTmp, "J") == 0)
nWert = 'J';
else if (stricmp(szTmp, "K") == 0)
nWert = 'K';
else if (stricmp(szTmp, "L") == 0)
nWert = 'L';
else if (stricmp(szTmp, "M") == 0)
nWert = 'M';
else if (stricmp(szTmp, "N") == 0)
nWert = 'N';
else if (stricmp(szTmp, "O") == 0)
nWert = 'O';
else if (stricmp(szTmp, "P") == 0)
nWert = 'P';
else if (stricmp(szTmp, "Q") == 0)
nWert = 'Q';
else if (stricmp(szTmp, "R") == 0)
nWert = 'R';
else if (stricmp(szTmp, "S") == 0)
nWert = 'S';
else if (stricmp(szTmp, "T") == 0)
nWert = 'T';
else if (stricmp(szTmp, "U") == 0)
nWert = 'U';
else if (stricmp(szTmp, "V") == 0)
nWert = 'V';
else if (stricmp(szTmp, "W") == 0)
nWert = 'W';
else if (stricmp(szTmp, "X") == 0)
nWert = 'X';
else if (stricmp(szTmp, "Y") == 0)
nWert = 'Y';
else if (stricmp(szTmp, "Z") == 0)
nWert = 'Z';

else if (stricmp(szTmp, "0") == 0)
nWert = '0';
else if (stricmp(szTmp, "1") == 0)
nWert = '1';
else if (stricmp(szTmp, "2") == 0)
nWert = '2';
else if (stricmp(szTmp, "3") == 0)
nWert = '3';
else if (stricmp(szTmp, "4") == 0)
nWert = '4';
else if (stricmp(szTmp, "5") == 0)
nWert = '5';
else if (stricmp(szTmp, "6") == 0)
nWert = '6';
else if (stricmp(szTmp, "7") == 0)
nWert = '7';
else if (stricmp(szTmp, "8") == 0)
nWert = '8';
else if (stricmp(szTmp, "9") == 0)
nWert = '9';

else if (stricmp(szTmp, "F1") == 0)
nWert = VK_F1;
else if (stricmp(szTmp, "F2") == 0)
nWert = VK_F2;
else if (stricmp(szTmp, "F3") == 0)
nWert = VK_F3;
else if (stricmp(szTmp, "F4") == 0)
nWert = VK_F4;
else if (stricmp(szTmp, "F5") == 0)
nWert = VK_F5;
else if (stricmp(szTmp, "F6") == 0)
nWert = VK_F6;
else if (stricmp(szTmp, "F7") == 0)
nWert = VK_F7;
else if (stricmp(szTmp, "F8") == 0)
nWert = VK_F8;
else if (stricmp(szTmp, "F9") == 0)
nWert = VK_F9;
else if (stricmp(szTmp, "F10") == 0)
nWert = VK_F10;
else if (stricmp(szTmp, "F11") == 0)
nWert = VK_F11;
else if (stricmp(szTmp, "F12") == 0)
nWert = VK_F12;

else if (stricmp(szTmp, "TAB") == 0)
nWert = VK_TAB;
else if (stricmp(szTmp, "SPACE") == 0)
nWert = VK_SPACE;
else if ((stricmp(szTmp, "ESC") == 0) || (stricmp(szTmp, "ESCAPE") == 0))
nWert = VK_ESCAPE;
else if ((stricmp(szTmp, "ENTER") == 0) || (stricmp(szTmp, "RETURN") == 0))
nWert = VK_RETURN;
else if ((stricmp(szTmp, "BACKSPACE") == 0) || (stricmp(szTmp, "BACK") == 0))
nWert = VK_BACK;
else if ((stricmp(szTmp, "PGUP") == 0) || (stricmp(szTmp, "PRIOR") == 0))
nWert = VK_PRIOR;
else if ((stricmp(szTmp, "DEL") == 0) || (stricmp(szTmp, "DELETE") == 0))
nWert = VK_DELETE;
else if ((stricmp(szTmp, "PGDN") == 0) || (stricmp(szTmp, "NEXT") == 0))
nWert = VK_NEXT;
else if (stricmp(szTmp, "LEFT") == 0)
nWert = VK_LEFT;
else if (stricmp(szTmp, "RIGHT") == 0)
nWert = VK_RIGHT;
else if (stricmp(szTmp, "UP") == 0)
nWert = VK_UP;
else if (stricmp(szTmp, "DOWN") == 0)
nWert = VK_DOWN;
else
{
sprintf(szError, "Unbekannter oder nicht implementierter VK_xxx Code <%s>", szTmp);
MessageBox(NULL, szError, "Fehler in DoKeysPress()", MB_OK|MB_ICONERROR);
return -2;
}

//event an process schicken
if (nWert > 0)
{
if (bWithAlt)
keybd_event(VK_MENU, 0, 0, 0);
if (bWithShift)
keybd_event(VK_SHIFT, 0, 0, 0);
if (bWithCtrl)
keybd_event(VK_CONTROL, 0, 0, 0);

keybd_event(nWert ,0,0,0);
Sleep(20);
keybd_event(nWert ,0,KEYEVENTF_KEYUP,0);

if (bWithAlt)
keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
if (bWithShift)
keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
if (bWithCtrl)
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
}

Sleep(nDelay);
bWithAlt = false;
bWithShift = false;
bWithCtrl = false;
i = 0;

nKeysPressed++;
}
}

return nKeysPressed;
}

///////////////////////////////////////////////////////////////

HWND g_hwnd = 0;

BOOL CALLBACK EnumChildProc(HWND hwndChild, LPARAM lParam)
{
DWORD dwFindProcessId = (DWORD)lParam;
DWORD dwProcessId = 0;
DWORD dwThId = ::GetWindowThreadProcessId(hwndChild, &dwProcessId);
if (dwProcessId == dwFindProcessId)
{
g_hwnd = hwndChild;
return FALSE;
}
return TRUE;
}

REMOTEDLL2_API void DoMouseClick(int x, int y, bool bRightClick, bool bDoubleClick, bool bDown, bool bUp)
{
for (int n=0; n<(bDoubleClick ? 2 : 1); n++)
{
::SetCursorPos(x, y);

if (bDown)
{
mouse_event( bRightClick ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_LEFTDOWN,
0, // horizontal position or change
0, // vertical position or change
0, // wheel movement
NULL // application-defined information
);
}

Sleep(100);
::SetCursorPos(x+2, y);

if (bDown)
{
mouse_event( bRightClick ? MOUSEEVENTF_RIGHTUP : MOUSEEVENTF_LEFTUP,
0, // horizontal position or change
0, // vertical position or change
0, // wheel movement
NULL // application-defined information
);
}

Sleep(100);
}
}

REMOTEDLL2_API int SendKeyToProcess(const char* lpszProcessname, const char* lpszKeys, int nDelayBefore, int nDelayBetween, int nDelayAfter)
{
HANDLE ss = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (ss == INVALID_HANDLE_VALUE)
return -1000;

PROCESSENTRY32 pe;
pe.dwSize = sizeof(pe);

DWORD dwFindProcessId = 0;
bool bFound = false;
BOOL bSucc = ::Process32First(ss, &pe);
for (/**/; bSucc; bSucc = ::Process32Next(ss, &pe))
{
if (stricmp(lpszProcessname, pe.szExeFile) == 0)
{
dwFindProcessId = pe.th32ProcessID;
bFound = true;
break;
}
}

::CloseHandle(ss);

if (!bFound)
return -1002;

g_hwnd = 0;
EnumWindows(EnumChildProc, (LPARAM) dwFindProcessId);

if (!g_hwnd)
return -1003;

Sleep(nDelayBefore);
int nErr = DoKeysPress(lpszKeys, nDelayBetween);
Sleep(nDelayAfter);

return nErr;
}

//char szTmp[500];
//sprintf(szTmp, "in:<%s> enum:<%s>", lpszProcessname, pe.szExeFile);
//MessageBox(NULL, szTmp, "SendKeyToProcess()", MB_OK);