今度はアプリ全体が停まる・・・12/21 土
次から次へと、問題が発生します。
Visual Studio 2019 C++ アプリが途中で止まる。困った・・・。
画像にいくつかのワクが表示してあり、カーソルを重なると、その都度、ワクが選択されるようなプログラムを作成しています。
実際には、マウスをうごかすたびに画像を表示しなおしているのですが、何度も動かしていると途中で止まります。
おそらく、リソースが不足していると思われますが、使用したツールはきちんと DeleteObject でリソースを開放しているはずなので、現時点では原因不明です。
しかし、このままでは、まったく役に立たちません。
困りました。
とりあえず、現時点での cpp プログラムを備忘録を兼ねて貼り付けておきますが、teratail と比べてプログラムの記載が難しいですね。
・・・と思ったら、<pre>を使うと簡単に表示できることを発見。htmlは、やっぱり知っておいた方が得だなあ。
#include "framework.h" #include "ScrollBar_Waku.h" #include "strconv.h" #include "atlimage.h" #includeusing namespace std; #define MAX_LOADSTRING 100 #define MAX_WAKU 100 // グローバル変数: HINSTANCE hInst; WCHAR szTitle[MAX_LOADSTRING]; WCHAR szWindowClass[MAX_LOADSTRING]; static CString filePath; static CImage img; static int width, height, myTop, mousex, mousey, memx, memy, mouseMode; static SCROLLINFO si; static int nowWaku, maxWaku; static RECT tmpWaku; static vector myWaku(MAX_WAKU); void InitWaku() { // テスト用にワクを設定しておく(将来的には削除) mouseMode = MODE_DONE; nowWaku = 0; maxWaku = 10; for (int i = 0; i < maxWaku; i++) { myWaku.at(i).top = 10 + i*50; myWaku.at(i).left = 50; myWaku.at(i).bottom = 50 + i*50; myWaku.at(i).right = 350; } } // このコード モジュールに含まれる関数の宣言を転送します: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // TODO: ここにコードを挿入してください。 filePath = L"sample.png"; img.Load(filePath); width = img.GetWidth(); height = img.GetHeight(); mousex = 0; mousey = 0; InitWaku(); // グローバル文字列を初期化する LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadStringW(hInstance, IDC_SCROLLBARWAKU, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // アプリケーション初期化の実行: if (!InitInstance(hInstance, nCmdShow)) { return FALSE; } HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SCROLLBARWAKU)); MSG msg; // メイン メッセージ ループ: while (GetMessage(&msg, nullptr, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return (int)msg.wParam; } // 目的: ウィンドウ クラスを登録します。 ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEXW wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SCROLLBARWAKU)); wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_SCROLLBARWAKU); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassExW(&wcex); } // 目的: インスタンス ハンドルを保存して、メイン ウィンドウを作成します BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { hInst = hInstance; HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW | WS_VSCROLL, // ウインドウの種類 50, // x座標 50, // y座標 800,// 幅 600,// 高さ nullptr, // 親ウインドのハンドル nullptr, // メニューハンドル nullptr はクラスメニュー hInstance, nullptr ); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } int CheckMouse() { int tmpwk = nowWaku; mouseMode = MODE_DONE; for (int i = 0; i < maxWaku; i++) { if ( (memy > myWaku.at(i).top - myTop) && (memy < myWaku.at(i).bottom - myTop) && (memx > myWaku.at(i).left) && (memx < myWaku.at(i).right)) { tmpwk = i; mouseMode = MODE_WAKU1; break; } } return tmpwk; } void DrawCursor(HDC mem) { COLORREF mycolor; mycolor = RGB(0xff, 0x00, 0x00); HPEN hpen = CreatePen(PS_SOLID, 5, mycolor); HGDIOBJ ohpen = SelectObject(mem, hpen); SelectObject(mem, GetStockObject(NULL_BRUSH)); Ellipse(mem, memx - 15, myTop + memy - 15, memx + 15, myTop + memy + 15); SelectObject(mem, ohpen); DeleteObject(hpen); } void DrawWaku(HDC mem,int wk) { COLORREF mycolor; if (wk == nowWaku) { mycolor = RGB(0xff, 0x00, 0x00); } else { mycolor = RGB(0x00, 0x00, 0xff); } HPEN hpen = CreatePen(PS_SOLID, 5, mycolor); SelectObject(mem, GetStockObject(NULL_BRUSH)); HGDIOBJ ohpen = SelectObject(mem, hpen); Rectangle(mem, myWaku.at(wk).left, myWaku.at(wk).top, myWaku.at(wk).right, myWaku.at(wk).bottom); SelectObject(mem, ohpen); DeleteObject(hpen); } // 目的: メイン ウィンドウのメッセージを処理します。 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { RECT recDisp; GetClientRect(hWnd, &recDisp); // クライアントを取得 int cx = recDisp.right; // クライアントのヨコ int cy = recDisp.bottom; // クライアントのタテ int tate; // イメージのタテ if (cx == 0) { tate = 0; memx = 0; memy = 0; } else { tate = cy * width / cx; memx = mousex * width / cx; memy = mousey * width / cx; } switch (message) { case WM_PAINT: { // ここから実際の描写 HDC hdc = GetDC(hWnd); HDC mem = CreateCompatibleDC(hdc); HBITMAP bmp = CreateCompatibleBitmap(hdc, width, height); HGDIOBJ obmp = SelectObject(mem, bmp); img.Draw(mem, 0, 0, width, height, 0, 0, width, height); for (int i = 0; i < maxWaku; i++) { DrawWaku(mem, i); } DrawCursor(mem); nowWaku = CheckMouse(); wstring wmouseMode; switch (mouseMode) { case MODE_DONE: wmouseMode = L"MODE_DONE"; break; case MODE_CLICK: wmouseMode = L"MODE_CLICK"; break; case MODE_WAKU1: wmouseMode = L"MODE_WAKU1"; break; case MODE_WAKU2: wmouseMode = L"MODE_WAKU2"; break; case MODE_END1: wmouseMode = L"MODE_END1"; break; case MODE_END2: wmouseMode = L"MODE_END2"; break; default: wmouseMode = L"default"; break; } PAINTSTRUCT ps; BeginPaint(hWnd, &ps); StretchBlt(hdc, 0, 0, cx, cy, mem, 0, myTop, width, tate, SRCCOPY); TextOut(hdc, 200, 50, wmouseMode.c_str(), (int)wmouseMode.length()); EndPaint(hWnd, &ps); SelectObject(mem, obmp); DeleteObject(bmp); si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; si.nMin = 0; si.nMax = height - tate; si.nPos = myTop; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); } break; case WM_VSCROLL: { switch (LOWORD(wParam)) { case SB_LINEUP: if (myTop > 10) { myTop -= 10; } else { myTop = 0; } break; case SB_LINEDOWN: if (myTop < height - tate - 10) { myTop += 10; } else { myTop = height - tate; } break; case SB_PAGEUP: if (myTop > tate) { myTop -= tate; } else { myTop = 0; } break; case SB_PAGEDOWN: if (myTop < height - tate * 2) { myTop += tate; } else { myTop = height - tate; } break; case SB_THUMBTRACK: myTop = HIWORD(wParam); break; } InvalidateRect(hWnd, NULL, FALSE); } break; case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_MOUSEMOVE: mousex = LOWORD(lParam); mousey = HIWORD(lParam); InvalidateRect(hWnd, NULL, FALSE); break; case WM_KEYDOWN: { switch (wParam) { case VK_ESCAPE: if (maxWaku == 0) { PostQuitMessage(0); } else { maxWaku--; nowWaku = maxWaku-1; } break; case VK_NEXT: if (myTop < height - tate * 2) { myTop += tate; } else { myTop = height - tate; } break; case VK_PRIOR: if (myTop > tate) { myTop -= tate; } else { myTop = 0; } break; case VK_DOWN: if (myTop < height - tate - 10) { myTop += 10; } break; case VK_UP: if (myTop > 10) { myTop -= 10; } break; } InvalidateRect(hWnd, NULL, FALSE); } break; case WM_COMMAND: { int wmId = LOWORD(wParam); // 選択されたメニューの解析: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // バージョン情報ボックス INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; }