#include #include #include #include #include #include #include #include #include "TextAnalyser.h" using namespace Framework; ConsoleHandler* console; Datei result; int imgCount; Text resultFolder; void makePicture(HWND hwnd, WFenster* zf) { HDC hdcScreen = GetDC(NULL); HDC hdcWindow = GetDC(hwnd); HDC hdcMemDC = CreateCompatibleDC(hdcWindow); HDC hdcMemDC2 = CreateCompatibleDC(hdcWindow); if (!hdcMemDC) { MessageBoxA(hwnd, "CreateCompatibleDC has failed", "Failed", MB_OK); return; } RECT rcClient; GetWindowRect(hwnd, &rcClient); HBITMAP hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top); if (!hbmScreen) { MessageBox(hwnd, "CreateCompatibleBitmap Failed", "Failed", MB_OK); return; } SelectObject(hdcMemDC, hbmScreen); if (!BitBlt(hdcMemDC, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, hdcScreen, rcClient.left, rcClient.top, SRCCOPY)) { MessageBox(hwnd, "BitBlt has failed", "Failed", MB_OK); return; } BITMAP bmpScreen; GetObject(hbmScreen, sizeof(BITMAP), &bmpScreen); BITMAPINFOHEADER bi; bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = bmpScreen.bmWidth; bi.biHeight = bmpScreen.bmHeight; bi.biPlanes = 1; bi.biBitCount = 32; bi.biCompression = BI_RGB; bi.biSizeImage = 0; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrUsed = 0; bi.biClrImportant = 0; DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight; // Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented // as wrapper functions that call HeapAlloc using a handle to the process's // default heap. Therefore, GlobalAlloc and LocalAlloc have greater overhead // than HeapAlloc. HANDLE hDIB = GlobalAlloc(GHND, dwBmpSize); char* lpbitmap = (char*)GlobalLock(hDIB); // Gets the "bits" from the bitmap, and copies them into a buffer // that's pointed to by lpbitmap. GetDIBits(hdcWindow, hbmScreen, 0, (UINT)bmpScreen.bmHeight, lpbitmap, (BITMAPINFO*)&bi, DIB_RGB_COLORS); TextAnalyser ta(zf); RECT cutRect = ta.findRect(bmpScreen.bmWidth, bmpScreen.bmHeight, lpbitmap); if (ta.hasImage()) { HBITMAP hbmScreen2 = CreateCompatibleBitmap(hdcWindow, cutRect.right - cutRect.left, cutRect.bottom - cutRect.top); SelectObject(hdcMemDC2, hbmScreen2); if (!BitBlt(hdcMemDC2, 0, 0, cutRect.right - cutRect.left, cutRect.bottom - cutRect.top, hdcScreen, rcClient.left + cutRect.left, rcClient.top + cutRect.top, SRCCOPY)) { MessageBox(hwnd, "BitBlt has failed", "Failed", MB_OK); return; } BITMAP bmpScreen2; GetObject(hbmScreen2, sizeof(BITMAP), &bmpScreen2); BITMAPFILEHEADER bmfHeader; BITMAPINFOHEADER bi2; bi2.biSize = sizeof(BITMAPINFOHEADER); bi2.biWidth = bmpScreen2.bmWidth; bi2.biHeight = bmpScreen2.bmHeight; bi2.biPlanes = 1; bi2.biBitCount = 32; bi2.biCompression = BI_RGB; bi2.biSizeImage = 0; bi2.biXPelsPerMeter = 0; bi2.biYPelsPerMeter = 0; bi2.biClrUsed = 0; bi2.biClrImportant = 0; DWORD dwBmpSize2 = ((bmpScreen2.bmWidth * bi2.biBitCount + 31) / 32) * 4 * bmpScreen2.bmHeight; // Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are // implemented as wrapper functions that call HeapAlloc using a handle // to the process's default heap. Therefore, GlobalAlloc and LocalAlloc // have greater overhead than HeapAlloc. HANDLE hDIB2 = GlobalAlloc(GHND, dwBmpSize2); char* lpbitmap2 = (char*)GlobalLock(hDIB2); // Gets the "bits" from the bitmap, and copies them into a buffer // that's pointed to by lpbitmap. GetDIBits(hdcWindow, hbmScreen2, 0, (UINT)bmpScreen2.bmHeight, lpbitmap2, (BITMAPINFO*)&bi2, DIB_RGB_COLORS); // A file is created, this is where we will save the screen capture. Text imgName(imgCount++); imgName += ".bmp"; HANDLE hFile = CreateFile(Text("output/") + imgName.getText(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); DWORD dwSizeofDIB = dwBmpSize2 + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // Offset to where the actual bitmap bits start. bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER); // Size of the file. bmfHeader.bfSize = dwSizeofDIB; // bfType must always be BM for Bitmaps. bmfHeader.bfType = 0x4D42; // BM. DWORD dwBytesWritten = 0; WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL); WriteFile(hFile, (LPSTR)&bi2, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL); WriteFile(hFile, (LPSTR)lpbitmap2, dwBmpSize2, &dwBytesWritten, NULL); // Unlock and Free the DIB from the heap. GlobalUnlock(hDIB2); GlobalFree(hDIB2); // Close the handle for the file that was created. CloseHandle(hFile); DeleteObject(hbmScreen2); Text imgTag; imgTag.append() << "\n"; result.schreibe(imgTag.getText(), imgTag.getLength()); } else { ta.writeToFile(result); } GlobalUnlock(hDIB); GlobalFree(hDIB); DeleteObject(hbmScreen); DeleteObject(hdcMemDC); DeleteObject(hdcMemDC2); ReleaseDC(NULL, hdcScreen); ReleaseDC(hwnd, hdcWindow); } void nextPage(HWND hwnd, unsigned int scanCode) { SetForegroundWindow(hwnd); SetFocus(hwnd); SendMessageA(hwnd, WM_KEYDOWN, VK_RIGHT, 1 | ((scanCode & 0xFF) << 16)); SendMessageA(hwnd, WM_KEYUP, VK_RIGHT, 1 | ((scanCode & 0xFF) << 16)); Sleep(10000); } void doWork(HWND hwnd, WFenster* zf) { result.setDatei("output/index.html"); if (!result.existiert()) { result.erstellen(); } result.open( Datei::Style::lesen | Datei::Style::schreiben | Datei::Style::ende); resultFolder = "output"; Datei outF; outF.setDatei(resultFolder); imgCount = 5; RCArray* subFiles = outF.getDateiListe(); for (Text* t : *subFiles) { if (t->hatAt(t->getLength() - 4, ".bmp")) { imgCount++; } } subFiles->release(); RCArray commands; Critical cs; new AsynchronCall([&commands, &cs]() { while (true) { std::string line; getline(std::cin, line); cs.lock(); commands.add(new Text(line.c_str())); cs.unlock(); } }); DWORD dwPID = 0; DWORD hThread = GetWindowThreadProcessId(hwnd, &dwPID); HKL hkl = GetKeyboardLayout(hThread); unsigned int scanCode = MapVirtualKeyExW(VK_RIGHT, MAPVK_VK_TO_VSC, hkl); bool ok = 1; while (ok) { makePicture(hwnd, zf); std::cout << "Page completed" << std::endl; cs.lock(); while (commands.getEintragAnzahl() > 0) { Text* command = commands.z(0); commands.remove(0); if (command->istGleich("exit")) { ok = 0; } command->release(); } cs.unlock(); result.close(); result.open( Datei::Style::lesen | Datei::Style::schreiben | Datei::Style::ende); nextPage(hwnd, scanCode); } result.close(); } BOOL CALLBACK speichereFenster(HWND hwnd, LPARAM lParam) { const DWORD TITLE_SIZE = 1024; char processName[TITLE_SIZE]; unsigned long pid = 0; GetWindowThreadProcessId(hwnd, &pid); HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); if (process == nullptr) { return TRUE; // Skip this window if we can't open the process } // get process name int result = GetModuleBaseNameA(process, NULL, processName, TITLE_SIZE); Text txt(processName); if (txt.hatAt(0, "msedge")) { RECT rect; GetWindowRect(hwnd, &rect); GetWindowTextA(hwnd, processName, TITLE_SIZE); Text txt2(processName); if (txt2.hatAt(0, "Kindle")) { std::cout << "Found Kindle window!" << std::endl; doWork(hwnd, (WFenster*)lParam); } } return TRUE; } void updateChars(const char* result, WFenster* zf) { std::cout << "list all known chars '" << result << "'" << std::endl; Bild* b = new Bild(); int factor = 5; for (int i = 0; i < chars->getEintragAnzahl(); i++) { CharMask* charMask = chars->get(i); if (charMask->getResult().istGleich(result)) { b->neuBild(charMask->getWidth() * factor, charMask->getHeight() * factor, 0xFF000000); for (int x = 0; x < charMask->getWidth() * factor; x++) { for (int y = 0; y < charMask->getHeight() * factor; y++) { if (charMask->getMask()[(y / factor) * charMask->getWidth() + x / factor]) { b->setPixelDP(x, y, 0xFFFFFFFF); } } } BildZ* z = new Framework::BildZ(); z->setBildZ(dynamic_cast(b->getThis())); z->setSize( charMask->getWidth() * factor, charMask->getHeight() * factor); z->setPosition(5, 5); z->setStyle(Framework::BildZ::Style::Sichtbar | Framework::BildZ::Style::Erlaubt); zf->zBildschirm()->addMember(z); zf->zBildschirm()->setBackBufferSize( charMask->getWidth() * factor + 10, charMask->getHeight() * factor + 10); zf->setSize(charMask->getWidth() * factor + 10, charMask->getHeight() * factor + 10); zf->zBildschirm()->update(); zf->zBildschirm()->render(); zf->zBildschirm()->render(); std::string command; std::getline(std::cin, command); if (command.starts_with("del")) { std::cout << "deleted." << std::endl; chars->remove(i); i--; saveChars(); } if (command.starts_with("exit")) { i = chars->getEintragAnzahl(); } zf->zBildschirm()->removeMember(z); } } b->release(); std::cout << "finished editing masks for '" << result << "'" << std::endl; } int main() { initFramework(); loadChars(); LTDSDatei font; font.setPfad(new Framework::Text("normal.ltds")); font.leseDaten(); schrift = font.ladeSchrift(); WNDCLASS wc = F_Normal(GetModuleHandle(NULL)); wc.lpszClassName = "Kindle Grabber"; WFenster* f = new WFenster(); f->erstellen(WS_POPUP, wc); f->setMausAktion(_ret1ME); f->setTastaturAktion(_ret1TE); f->setAnzeigeModus(SW_SHOWNORMAL); f->setSize(100, 100); f->setPosition(Punkt(100, 100)); Bildschirm* screen = new Bildschirm3D( dynamic_cast(f->getThis()), GraphicApiType::DIRECTX11); screen->setRenderZeichnungen(1); screen->setdeckFarbe(0xFF000000); screen->setFill(1); screen->setTestRend(0); f->setBildschirm(screen); std::string response; std::getline(std::cin, response); while (response.length() > 0) { updateChars(response.c_str(), f); std::getline(std::cin, response); } new AsynchronCall( "Kindle Grabber", [f]() { EnumWindows(speichereFenster, reinterpret_cast(f)); }, 0); Framework::StartNachrichtenSchleife(); return 0; }