ซอฟต์แวร์ที่ฉันกำลังดำเนินการเมื่อเร็ว ๆ นี้ซึ่งบางอย่างจำเป็นต้องเสร็จสิ้นโดยการโทรหาซอฟต์แวร์อื่น ๆ แต่ซอฟต์แวร์นั้นมีไฟล์ที่ใช้งานได้และไม่มีซอร์สโค้ดเลย เริ่มต้นหลังจากโปรแกรมของฉันเริ่มต้นขึ้น
เมื่อพูดถึงเรื่องนี้ฉันเชื่อว่าคุณมีแนวคิดเบื้องต้นสำหรับฟังก์ชั่นนี้
1) โทร CreateProcess () เพื่อเปิดโปรแกรมเป้าหมาย
2) ใช้ FindWindow () เพื่อค้นหาที่จับหน้าต่างของโปรแกรมเป้าหมาย
3) ค้นหาที่จับของกล่องข้อความและข้อความ MessageId ของปุ่มตั้งค่าข้อความโดยใช้เมธอด sendMessage () และทริกเกอร์เหตุการณ์
ตกลงนี่เป็นเรื่องง่ายมาก แต่เมื่อฉันนำไปใช้มันฉันพบว่าผลลัพธ์ของสิ่งนี้คือ: เมื่อโปรแกรมของฉันเริ่มต้นและเปิดโปรแกรมเป้าหมายหน้าต่างสาดและหน้าต่างหลักจะปรากฏขึ้นแม้ว่าฉันจะใช้ Findwindow () เพื่อค้นหาที่จับหน้าต่างหลักและการโทร SendMessage (WindowHandle, SW_HIDE) เพื่อซ่อนหน้าต่างหน้าต่างหลักจะปรากฏขึ้นสักครู่
ดังนั้นจะแก้ปัญหานี้ได้อย่างไร? มันไม่มีผล - - - ค้นหาเอกสารต่อไป และหากได้รับมอบหมายหลังจากชื่อเดสก์ท็อปกระบวนการจะถูกเปิดตัวบนเดสก์ท็อปที่ระบุ
1) ก่อนอื่นให้สร้างเดสก์ท็อปเสมือนจริง
const
DesktopName = 'MyDesk';
fdesktop: = createdesktop (เดสก์ท็อปชื่อ, nil, nil, 0, generic_all, nil);
สามารถสร้างเดสก์ท็อปหลายตัวใน Windows และ SwitchDesktop () สามารถใช้ในการสลับว่าเดสก์ท็อปใดที่ปรากฏขึ้น Windows ถูกนำมาใช้โดยฟังก์ชั่นเดสก์ท็อปเสมือนจริง . วัสดุ:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/enumdesktops.asp
2) เมื่อ CreateProcess ระบุโปรแกรมที่จะทำงานบนเดสก์ท็อปที่สร้างขึ้นใหม่ของฉัน:
วาจา
startInfo: tStartupInfo;
Fillchar (startInfo, sizeof (startInfo), 0);
startInfo.cb: = sizeof (startInfo);
startinfo.lpdesktop: = pchar (เดสก์ท็อปชื่อ);
startinfo.wshowwindow: = sw_hide;
startinfo.dwflags: = startf_useshowwindow;
startinfo.hstderror: = 0;
startInfo.hstDinput: = 0;
startInfo.hstdOutput: = 0;
หากไม่ได้สร้างสรรค์ (pchar (ชื่อไฟล์), nil, nil, nil, nil, true, create_new_console+high_priority_class, nil, pchar (extractfilepath (filepath)), startinfo, fproceinfo)
MessageBox (application.handle, 'ข้อผิดพลาดเมื่อเริ่มต้นเสียง (5)', pchar (application.title), mb_iconwarning);
ออก;
จบ;
3) ใช้ FindWindow เพื่อค้นหาหน้าต่างหลักของโปรแกรม
ตอนแรกฉันเขียนรหัสแบบนี้:
สำหรับ i: = 0 ถึง 60 เริ่ม // รอ 30 วินาทีสำหรับเปิดหน้าต่างหลัก
WindowHandle: = findWindow (ไม่มี, 'windowcaption');
ถ้า WindowHandle <> 0 แล้วเริ่มต้น
หยุดพัก;
จบ;
นอนหลับ (500);
จบ;
อย่างไรก็ตามการฝึกฝนได้พิสูจน์แล้วว่าด้วยวิธีนี้หน้าต่างที่ไม่ได้อยู่ในเดสก์ท็อปปัจจุบันไม่สามารถพบได้
คำตอบคือคุณสามารถใช้ฟังก์ชัน setThreadDeskTop () ซึ่งสามารถตั้งค่าเดสก์ท็อปที่เธรดทำงานได้ดังนั้นฉันจึงเพิ่มประโยคอื่นก่อนรหัสด้านบน:
หากไม่ได้ SetThreadDeskTop (FDESKTOP) ให้เริ่มต้น
ออก;
จบ;
อย่างไรก็ตามหลังจากที่โปรแกรมทำงานแล้วฟังก์ชั่นจะส่งกลับเท็จแสดงให้เห็นว่าการเรียกใช้วิธีนี้ล้มเหลว
ฟังก์ชั่น SetThreadDeskTop จะล้มเหลวหากเธรดการเรียกมี windows หรือ hooks ใด ๆ บนเดสก์ท็อปปัจจุบัน (เว้นแต่พารามิเตอร์ hdesktop จะเป็นที่จับไปยังเดสก์ท็อปปัจจุบัน)
โอ้ปรากฎว่าไม่มีสิ่งที่ UI ในเธรดที่ต้องเปลี่ยนเดสก์ท็อป แต่ฉันเรียกวิธีนี้ในหัวข้อหลักของโปรแกรมและแน่นอนว่ามันจะล้มเหลว ต้องใช้มันไม่สามารถผูกเธรด "สะอาด" กับเดสก์ท็อปใหม่แล้วใช้วิธี FindWindow () เพื่อค้นหา windowhandle ที่ฉันกำลังมองหา? รหัสมีดังนี้:
tfindWindowThread = คลาส (tthread)
ส่วนตัว
Fdesktop: Thandle;
FWINDOWHANDLE: Thandle;
ได้รับการคุ้มครอง
ขั้นตอนดำเนินการ (); แทนที่;
สาธารณะ
ตัวสร้างสร้าง (acreatesuspended: บูลีน; const adesktop: thandle); reintroduce;
Property Windowhandle: Thandle อ่าน fwindowhandle;
จบ;
{tfindWindowThread}
ขั้นตอน tfindWindowThread.execute ();
วาจา
ฉัน: จำนวนเต็ม;
เริ่ม
// ทำให้เธรดปัจจุบันค้นหาหน้าต่างบนเดสก์ท็อปใหม่!
หากไม่ได้ SetThreadDeskTop (FDESKTOP) ให้เริ่มต้น
ออก;
จบ;
สำหรับ i: = 0 ถึง 60 เริ่ม // รอ 30 วินาทีสำหรับเปิดหน้าต่างหลัก
fwindowhandle: = findwindow (nil, pchar ('windowcaption'));
ถ้า fwindowhandle <> 0 แล้วเริ่มต้น
หยุดพัก;
จบ;
นอนหลับ (500);
จบ;
จบ;
Constructor tfindwindowthread.create (Acreatesuspended: บูลีน; const adesktop: thandle);
เริ่ม
สร้างมรดก (acreatesuspended);
fdesktop: = adesktop;
จบ;
และรหัสในโปรแกรมหลักจะเป็นเช่นนี้:
findwindowthread: = tfindwindowthread.create (false, fdesktop);
พยายาม
findwindowthread.waitfor;
fmainwindowhandle: = findwindowthread.windowhandle;
ในที่สุด
findwindowthread.free;
จบ;
ถ้า fmainWindowHandle = 0 แล้วเริ่มต้น
MessageBox (application.handle, 'ข้อผิดพลาดเมื่อเริ่มต้นเสียง (6)', pchar (application.title), mb_iconwarning);
ออก;
จบ;
ฮ่าฮ่ามันประสบความสำเร็จดังนั้นคุณสามารถหาที่จับหน้าต่างได้อย่างราบรื่น
4) ในที่สุดใช้ที่จับหน้าต่างหลักนี้เพื่อค้นหาด้ามจับแก้ไขภายในดังนี้:
FeditWindow: = FindWindowex (fmainwindowhandle, 0, pchar ('แก้ไข'), ไม่มี);
ฉันได้ระบุชื่อคลาสของกล่องข้อความนี้ที่นี่และชื่อนี้สามารถรับได้ด้วย Spy ++
การเริ่มต้นงานจะสิ้นสุดที่นี่ ดังนั้นการเรียกใช้ฟังก์ชันจึงเหมือนปกติ:
ถ้า (fmainWindowHandle = 0) หรือ (feditWindow = 0) แล้วเริ่มต้น
ออก;
จบ;
SendMessage (FeditWindow, WM_SETTEXT, 0, Longint (@atext [1]));
SendMessage (fMainWindowHandle, WM_Command, $ 8012, $ 0);
หมายเลข $ 8012 ยังเป็นรหัสทรัพยากรที่ได้รับโดยใช้ Spy ++
ในที่สุดอย่าลืมปิดโปรแกรมและปล่อยเดสก์ท็อปเสมือนจริง:
ถ้า fproceinfo.hprocess <> 0 แล้วเริ่มต้น
ยุติการประมวลผล (fproceinfo.hprocess, 0);
จบ;
ถ้า fdesktop <> 0 แล้วเริ่มต้น
closeSktop (fdesktop);
จบ;
ตกลงสิ่งนี้เกือบจะใช้ฟังก์ชั่นของโปรแกรมการโทรพื้นหลังซึ่งจะโปร่งใสอย่างสมบูรณ์กับลูกค้าปลายทางและลูกค้าก็ไม่รู้สึกว่ามีโปรแกรมอื่นที่ทำงานอยู่เบื้องหลัง มันไม่ดีมาก?
หากคุณมีข้อเสนอแนะสำหรับการปรับปรุงหรือแลกเปลี่ยนคุณสามารถส่งจดหมายไปที่: tonyki [at] citiz.net