|
Zdravím, narazil jsem na takový docela zajímavý problém, se kterým si tady lámu hlavu už asi týden a nemůžu s tím hnout. Udělal jsem si mininimální verzi daného problému, na které jde reprodukovat, dám jí na konec tototo příspěvku (UI je konzolovka psaná v C#, ale jde mi spíše o knihovnu, která je čistě céčková). Vyvíjím aplikaci, která má (v minimální verzi) kliknout do okna prohlížeče (handler a souřadnice dodávám ručně přes Spy++) a následně poslat několik úderů do klávesnice, kde potom (v ostré verzi následuje další logika co s tím, v té minimální se jen chvíli počká) a následně další kliknutí na stejný prvek a poslání opět několik úderů do klávesnice aby se vybraný prvek vrátil do původního stavu. Problémem je, že na mém stroji (který není nijak výjimečný) to funguje a běhá skvěle a přesně jak má, ovšem vezmu-li to na několik dalších počítačů (i s různými OS - W7/W10) tak nikoli i přesto, že návratová hodnota SendInput pošle správný počet úhozů, resp. eventů klávesnice a GetLastError vrací nulu. Ovšem, žádné úhozy se fyzicky u cíle neobjeví, kliknutí je v pořádku, ale když má posílat struktury přes SendInput, tak dělá že nic, ač vrací hodnoty správné. Pokud si někdo bude potřebovat problém replikovat, ideálně to provádět na webové aplikaci společnosti HighLow (www.highlow.net [nedělám doufám nepovolenou reklamu, nic s nima nemám společnýho, jen potřebuju automatizovat užití jejich aplikace], kde je nutné si otevřít demo (to je zdarma a bez registrace) a následně běží o ten combobox s výběrem instrumentů co je vpravo (default tam je All). Zná někdo, v čem by mohl být problém? Co je tom kódu špatně? Případně neznáte alernativu k SendInput(), která by udělala stejný job, ale spolehlivě? Díky moc Zdrojáky zde: ****C# ovládací aplikace té knihovny, **** nic složitého i když v tom neděláte, co ten kód má za úkol pochopí snad každý. Je to minimalistická verze, neošetřju výjimky na vstupu a podobný "balast", se kterým se mi nechtěo psát, přeci jen smysl programu je jinde :)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Globalization;
namespace clickTest1
{
class Program
{
enum SYMBOLS
{
AUDJPY, AUDNZD, CADJPY, CHFJPY, EURAUD, EURGBP,
EURJPY, EURUSD, GBPAUD, GBPJPY, GBPUSD, NZDJPY,
NZDUSD, USDCAD, USDCHF, USDJPY, GOLD, UNKNOWN
};
const int SW_SHOWMAXIMIZED = 3;
const int SW_HIDE = 0;
const uint SWP_NOSIZE = 0x0001;
const uint SWP_NOMOVE = 0x0002;
const uint SWP_SHOWWINDOW = 0x0040;
[DllImport(@"tradeInterop.dll")]
public static extern void PutSingleClick(IntPtr hwnd, int x, int y);
[DllImport(@"tradeInterop.dll")]
public static extern uint PutKeystroke(IntPtr shouldBeNULL, int times, int isDown, out int err);
[DllImport(@"user32.dll")]
public static extern int SetWindowPos(IntPtr hwnd, IntPtr precendingHwnd, int x, int y, int cx, int cy, uint flags);
[DllImport(@"user32.dll")]
public static extern int ShowWindow(IntPtr hwnd, int cmdShow);
[DllImport(@"user32.dll")]
public static extern IntPtr GetParent(IntPtr hwnd);
static void Main(string[] args)
{
UInt32 handler = 0;
int x, y = 0;
int keystrokesCount = 0;
IntPtr HWND_BOTTOM = new IntPtr(1);
IntPtr HWND_TOPMOST = new IntPtr(-1);
UInt32 originalHandler = 0;
while (true)
{
Console.WriteLine("H WND (hexadecimal) 0 = exit: ");
handler = UInt32.Parse(Console.ReadLine(), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
if (handler == 0)
{
ShowBrowser((IntPtr)originalHandler, IntPtr.Zero);
break;
}
originalHandler = handler;
HideBrowser((IntPtr)handler, HWND_BOTTOM);
Console.WriteLine("X: ");
x = int.Parse(Console.ReadLine());
Console.WriteLine("Y: ");
y = int.Parse(Console.ReadLine());
Console.WriteLine("Choose instrument index (e.g. EURUSD=7)");
keystrokesCount = int.Parse(Console.ReadLine());
Console.WriteLine("Getting browser maximized and topomost");
ShowBrowser((IntPtr)handler, HWND_TOPMOST);
Console.WriteLine("Clicking on combobox");
PutSingleClick((IntPtr)handler, x, y);
Thread.Sleep(1000); // for content of combo full load
Console.WriteLine("Putting keystrokes");
int lastErr = -1;
uint strokesPut = PutKeystroke(IntPtr.Zero, keystrokesCount, 1, out lastErr); // 1 = TRUE, is key down
System.Threading.Thread.Sleep(5000);
HideBrowser((IntPtr)handler, HWND_BOTTOM);
Console.WriteLine("Keys down pressed, {0} would be choosen", (SYMBOLS)keystrokesCount);
Console.WriteLine("From library: Sent {0} strokes, error: {1}", strokesPut, lastErr);
Console.WriteLine("Press enter to continue");
Console.ReadLine();
ShowBrowser((IntPtr)handler, HWND_TOPMOST);
PutSingleClick((IntPtr)handler, x, y);
Thread.Sleep(1000);
strokesPut = PutKeystroke(IntPtr.Zero, keystrokesCount + 5, 0, out lastErr);
System.Threading.Thread.Sleep(5000);
HideBrowser((IntPtr)handler, HWND_BOTTOM);
Console.WriteLine("Keys up pressed, ALL would be choosen");
Console.WriteLine("From library: Sent {0} strokes, error: {1}", strokesPut, lastErr);
Console.WriteLine("Press enter to continue");
Console.ReadLine();
}
}
private static void ShowBrowser(IntPtr hwnd, IntPtr precHwnd)
{
Console.WriteLine("Showing browser...");
ShowWindow(GetParent(hwnd), SW_SHOWMAXIMIZED);
SetWindowPos(GetParent(hwnd), precHwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}
private static void HideBrowser(IntPtr hwnd, IntPtr precHwnd)
{
Console.WriteLine("Hiding browser...");
SetWindowPos(GetParent(hwnd), precHwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
ShowWindow(GetParent(hwnd), SW_HIDE);
}
}
**knihovna, resp. relevantní část, psaná v čistém C / WinAPI ****
int _stdcall DllMain(HINSTANCE hInst, DWORD fdwReason, PVOID pvReserved)
{
return true;
}
extern "C" __declspec(dllexport) void __stdcall PutSingleClick(HWND hwnd, int x, int y, BOOL needFocus = TRUE)
{
if(needFocus == TRUE)
{
SendMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(0,0));
SendMessage(hwnd, WM_LBUTTONUP, MK_LBUTTON, MAKELPARAM(0,0));
}
SendMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(x, y));
SendMessage(hwnd, WM_LBUTTONUP, MK_LBUTTON, MAKELPARAM(x, y));
}
extern "C" __declspec(dllexport) UINT __stdcall PutKeystroke(HWND hnd, int index, BOOL isDown, int& err)
{
INPUT ip = {0};
ip.type = INPUT_KEYBOARD;
ip.ki.wVk =isDown? VK_DOWN : VK_UP;
int times;
if(index < 2)
times = index+1;
else
times = index+2;
INPUT ips[100] = {0};
for(int i = 0; i < times*2; i+=2)
{
ip.ki.dwFlags = 0;
ips[i] = ip;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
ips[i+1] = ip;
}
ip.ki.dwFlags = 0;
ip.ki.wVk = VK_RETURN;
ips[times*2] = ip;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
ips[(times*2)+1] = ip;
err = -1;
UINT s = SendInput((times*2)+2, &ips[0], sizeof(INPUT));
err = GetLastError();
return s;
}
Tuší někdo, v čem je problém, popř. co zkusit? Já už jsem úplně v koncích a bez nápadu, a bez vyřešení tohoto s projektem dále nepohnu, je téměř hotový, zbývá jen toto odřešit. A je mi fakt strašně divný, že to u mně funguje dobře (takže kód nijak moc zprasený být nemůže), ale jinde ne. Za každou pomoc a dobře míněnou radu děkuji
|