Hi folks! I'm new here and new to PowerBASIC as well. Currently, I'm trying to create a DLL that can be used to capture text from a third-party program. Unfortunately, the program does not use standard Windows controls and so, attempting to use WM_GETTEXT only yields empty strings. After searching around for a solution, I learnt that setting up Hooks to monitor the DrawText, TextOut and ExtTextOut APIs is the best way to go.
I did managed to find related example code in these forums, although the example shows only how to hook for TextOut. See link below:
I modified the same code and replaced it with DrawText and ExtTextOut. Tested the DLL with the exe included (code for exe is in the example above). After I compile and run the exe, I open PowerBASIC's Help file just to test it out. Immediately, I get a msgbox with the string "Help &Topics" which comes from DrawText. The funny thing is that I can't find that string anywhere on the frontpage of the Help file itself!
After that, i get another msgbox which is blank, this time from ExtTextOut. Immediately after these two msgboxs, the Help file generates a Windows error and has to be closed. I've included my modified code below. If anyone here can please take a look and let me know where I'm going wrong, I'd really appreciate it. Thanks!
I did managed to find related example code in these forums, although the example shows only how to hook for TextOut. See link below:
I modified the same code and replaced it with DrawText and ExtTextOut. Tested the DLL with the exe included (code for exe is in the example above). After I compile and run the exe, I open PowerBASIC's Help file just to test it out. Immediately, I get a msgbox with the string "Help &Topics" which comes from DrawText. The funny thing is that I can't find that string anywhere on the frontpage of the Help file itself!

Code:
#COMPILE DLL "CaptureText.Dll" #REGISTER NONE #DIM ALL #INCLUDE "Win32Api.Inc" '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTION SetMyDrawText(Op AS LONG) AS LONG STATIC hProc AS LONG, tProc AS STRING LOCAL hLib AS LONG IF hProc = 0 THEN hLib = GetModuleHandle("user32.dll") hProc = GetProcAddress(hLib, "DrawTextA") tProc = PEEK$(hProc, 7) IF ISFALSE(VirtualProtect (BYVAL hProc, 7, BYVAL %PAGE_EXECUTE_READWRITE, BYREF hLib)) THEN _ MSGBOX "Error in VirtualProtect": hProc = 0: EXIT FUNCTION ' Under 9x VirtualProtect doesn't work in the shared virtual address space (from 0x80000000 through 0xBFFFFFFF). ' For example, for system dlls. END IF IF Op = 1 THEN POKE$ hProc, CHR$(&HB8) + MKL$(CODEPTR(MyDrawText)) + CHR$(&HFF, &HE0) IF Op = 2 THEN POKE$ hProc, tProc FlushInstructionCache GetCurrentProcess, BYVAL hProc, BYVAL 7 END FUNCTION '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTION MyDrawText (BYVAL hdc AS LONG, BYVAL lpString AS DWORD, BYVAL nCount AS LONG, BYVAL lpRect AS RECT, BYVAL uFormat AS DWORD) AS LONG LOCAL MyString AS STRING IF lpString THEN MyString = PEEK$(lpString, nCount) MSGBOX MyString, %MB_OK, "Captured by DrawText" 'LSET MyString = "Ha-ha" SetMyDrawText 2 DrawText hdc, BYVAL STRPTR(MyString), LEN(MyString), lpRect, uFormat SetMyDrawText 1 END FUNCTION '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTION SetMyExtTextOut(Op AS LONG) AS LONG STATIC hProc AS LONG, tProc AS STRING LOCAL hLib AS LONG IF hProc = 0 THEN hLib = GetModuleHandle("gdi32.dll") hProc = GetProcAddress(hLib, "ExtTextOutA") 'DrawTextA tProc = PEEK$(hProc, 7) IF ISFALSE(VirtualProtect (BYVAL hProc, 7, BYVAL %PAGE_EXECUTE_READWRITE, BYREF hLib)) THEN _ MSGBOX "Error in VirtualProtect": hProc = 0: EXIT FUNCTION ' Under 9x VirtualProtect doesn't work in the shared virtual address space (from 0x80000000 through 0xBFFFFFFF). ' For example, for system dlls. END IF IF Op = 1 THEN POKE$ hProc, CHR$(&HB8) + MKL$(CODEPTR(MyExtTextOut)) + CHR$(&HFF, &HE0) IF Op = 2 THEN POKE$ hProc, tProc FlushInstructionCache GetCurrentProcess, BYVAL hProc, BYVAL 7 END FUNCTION '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTION MyExtTextOut (BYVAL hdc AS DWORD, BYVAL x AS LONG, BYVAL y AS LONG, BYVAL dwOptions AS DWORD, BYVAL lpRect AS RECT, BYVAL lpString AS DWORD, BYVAL nCount AS DWORD, lpDx AS LONG) AS LONG LOCAL MyString AS STRING IF lpString THEN MyString = PEEK$(lpString, nCount) MSGBOX MyString, %MB_OK, "Captured by ExtTextOut" 'LSET MyString = "Ha-ha" SetMyExtTextOut 2 ExtTextOut hdc, x, y, dwOptions, lpRect, BYVAL STRPTR(MyString), LEN(MyString), lpDx SetMyExtTextOut 1 END FUNCTION '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $UniqueName = "My Hook" GLOBAL hInstDLL AS LONG, MainDll AS LONG FUNCTION LIBMAIN(BYVAL hInstance AS LONG, BYVAL fwdReason AS LONG, _ BYVAL lpvReserved AS LONG) EXPORT AS LONG SELECT CASE fwdReason CASE %DLL_PROCESS_ATTACH: hInstDLL = hInstance: LIBMAIN = 1: SetMyDrawText 1: SetMyExtTextOut 1 CASE %DLL_PROCESS_DETACH: LIBMAIN = 1: SetMyDrawText 2: SetMyExtTextOut 2 END SELECT END FUNCTION '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTION HookProc(BYVAL nCode AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG) EXPORT AS LONG STATIC hHook AS LONG, hDlg AS LONG hDlg = FindWindow("", $UniqueName) IF hHook = 0 THEN IF hDlg THEN hHook = GetProp(hDlg, BYVAL 1) IF hHook THEN FUNCTION = CallNextHookEx(BYVAL hHook, BYVAL nCode, BYVAL wParam, BYVAL lParam) IF ISFALSE(MainDll) AND (ISFALSE(hDlg) OR ISFALSE(hHook)) THEN FreeLibrary hInstDll END FUNCTION '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTION SetHook ALIAS "SetHook" (hWnd AS LONG) EXPORT AS LONG LOCAL hHook AS LONG hHook = SetWindowsHookEx (%WH_CBT, CODEPTR(HookProc), BYVAL hInstDLL, BYVAL 0) SetProp hWnd, BYVAL 1, BYVAL hHook MainDll = 1 END FUNCTION
Comment