#背景
Windows10 Visual Studio 2019 C++ でアプリを作成しようと考えています。Visual Studio を使い始めてから、まだ 1か月程度の初心者です。
サンプル画像を表示し、そのサンプル画像の上にいくつかの「ワク」を表示させ、マウスで移動させたり、大きさを変化させたりしたいと考えています。
実際のプログラム( cpp ファィル )は、以下に引用するとおりですが、動いている様子については、次の Youtube の動画のようになっています。
⇒ Visual Studio 2019 C++ アプリが途中で止まる。
#エラーメッセージ
エラーメッセージは、表示されていません。
しかし、Youtube の動画のとおり、途中で動きが止まってしまいます。
#プログラムソース
cppファイルの内容をまるごと以下に引用します。
C++
1#include "framework.h" 2#include "ScrollBar_Waku.h" 3#include "strconv.h" 4#include "atlimage.h" 5#include <string> 6using namespace std; 7 8#define MAX_LOADSTRING 100 9#define MAX_WAKU 100 10 11// グローバル変数: 12HINSTANCE hInst; 13WCHAR szTitle[MAX_LOADSTRING]; 14WCHAR szWindowClass[MAX_LOADSTRING]; 15 16static CString filePath; 17static CImage img; 18static int width, height, myTop, mousex, mousey, memx, memy, mouseMode; 19static SCROLLINFO si; 20 21static int nowWaku, maxWaku; 22static RECT tmpWaku; 23static vector <RECT> myWaku(MAX_WAKU); 24 25void InitWaku() { // テスト用にワクを設定しておく(将来的には削除) 26 mouseMode = MODE_DONE; 27 nowWaku = 0; 28 maxWaku = 10; 29 for (int i = 0; i < maxWaku; i++) { 30 myWaku.at(i).top = 10 + i*50; myWaku.at(i).left = 50; 31 myWaku.at(i).bottom = 50 + i*50; myWaku.at(i).right = 350; 32 } 33} 34 35// このコード モジュールに含まれる関数の宣言を転送します: 36ATOM MyRegisterClass(HINSTANCE hInstance); 37BOOL InitInstance(HINSTANCE, int); 38LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 39INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); 40 41int APIENTRY wWinMain(_In_ HINSTANCE hInstance, 42 _In_opt_ HINSTANCE hPrevInstance, 43 _In_ LPWSTR lpCmdLine, 44 _In_ int nCmdShow) { 45 UNREFERENCED_PARAMETER(hPrevInstance); 46 UNREFERENCED_PARAMETER(lpCmdLine); 47 48 // TODO: ここにコードを挿入してください。 49 filePath = L"sample.png"; 50 img.Load(filePath); 51 width = img.GetWidth(); 52 height = img.GetHeight(); 53 mousex = 0; 54 mousey = 0; 55 InitWaku(); 56 57 // グローバル文字列を初期化する 58 LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 59 LoadStringW(hInstance, IDC_SCROLLBARWAKU, szWindowClass, MAX_LOADSTRING); 60 MyRegisterClass(hInstance); 61 62 // アプリケーション初期化の実行: 63 if (!InitInstance(hInstance, nCmdShow)) { return FALSE; } 64 HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SCROLLBARWAKU)); 65 MSG msg; 66 67 // メイン メッセージ ループ: 68 while (GetMessage(&msg, nullptr, 0, 0)) { 69 if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { 70 TranslateMessage(&msg); 71 DispatchMessage(&msg); 72 } 73 } 74 return (int)msg.wParam; 75} 76 77// 目的: ウィンドウ クラスを登録します。 78ATOM MyRegisterClass(HINSTANCE hInstance) { 79 WNDCLASSEXW wcex; 80 wcex.cbSize = sizeof(WNDCLASSEX); 81 wcex.style = CS_HREDRAW | CS_VREDRAW; 82 wcex.lpfnWndProc = WndProc; 83 wcex.cbClsExtra = 0; 84 wcex.cbWndExtra = 0; 85 wcex.hInstance = hInstance; 86 wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SCROLLBARWAKU)); 87 wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); 88 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 89 wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_SCROLLBARWAKU); 90 wcex.lpszClassName = szWindowClass; 91 wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); 92 return RegisterClassExW(&wcex); 93} 94 95// 目的: インスタンス ハンドルを保存して、メイン ウィンドウを作成します 96BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { 97 hInst = hInstance; 98 HWND hWnd = CreateWindowW(szWindowClass, szTitle, 99 WS_OVERLAPPEDWINDOW | WS_VSCROLL, // ウインドウの種類 100 50, // x座標 101 50, // y座標 102 800,// 幅 103 600,// 高さ 104 nullptr, // 親ウインドのハンドル 105 nullptr, // メニューハンドル nullptr はクラスメニュー 106 hInstance, 107 nullptr 108 ); 109 if (!hWnd) { return FALSE; } 110 ShowWindow(hWnd, nCmdShow); 111 UpdateWindow(hWnd); 112 return TRUE; 113} 114 115int CheckMouse() { 116 int tmpwk = nowWaku; 117 mouseMode = MODE_DONE; 118 for (int i = 0; i < maxWaku; i++) { 119 if ( (memy > myWaku.at(i).top - myTop) 120 && (memy < myWaku.at(i).bottom - myTop) 121 && (memx > myWaku.at(i).left) 122 && (memx < myWaku.at(i).right)) { 123 tmpwk = i; 124 mouseMode = MODE_WAKU1; 125 break; 126 } 127 } 128 return tmpwk; 129} 130 131void DrawCursor(HDC mem) { 132 COLORREF mycolor; 133 mycolor = RGB(0xff, 0x00, 0x00); 134 HPEN hpen = CreatePen(PS_SOLID, 5, mycolor); 135 HGDIOBJ ohpen = SelectObject(mem, hpen); 136 SelectObject(mem, GetStockObject(NULL_BRUSH)); 137 Ellipse(mem, memx - 15, myTop + memy - 15, memx + 15, myTop + memy + 15); 138 SelectObject(mem, ohpen); 139 DeleteObject(hpen); 140} 141 142void DrawWaku(HDC mem,int wk) { 143 COLORREF mycolor; 144 if (wk == nowWaku) { 145 mycolor = RGB(0xff, 0x00, 0x00); 146 } 147 else { 148 mycolor = RGB(0x00, 0x00, 0xff); 149 } 150 HPEN hpen = CreatePen(PS_SOLID, 5, mycolor); 151 SelectObject(mem, GetStockObject(NULL_BRUSH)); 152 HGDIOBJ ohpen = SelectObject(mem, hpen); 153 Rectangle(mem, myWaku.at(wk).left, myWaku.at(wk).top, myWaku.at(wk).right, myWaku.at(wk).bottom); 154 SelectObject(mem, ohpen); 155 DeleteObject(hpen); 156} 157 158// 目的: メイン ウィンドウのメッセージを処理します。 159LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { 160 161 RECT recDisp; 162 GetClientRect(hWnd, &recDisp); // クライアントを取得 163 int cx = recDisp.right; // クライアントのヨコ 164 int cy = recDisp.bottom; // クライアントのタテ 165 int tate; // イメージのタテ 166 if (cx == 0) { 167 tate = 0; memx = 0; memy = 0; 168 } else { 169 tate = cy * width / cx; memx = mousex * width / cx; memy = mousey * width / cx; 170 } 171 172 switch (message) { 173 174 case WM_PAINT: { 175 // ここから実際の描写 176 HDC hdc = GetDC(hWnd); 177 HDC mem = CreateCompatibleDC(hdc); 178 HBITMAP bmp = CreateCompatibleBitmap(hdc, width, height); 179 HGDIOBJ obmp = SelectObject(mem, bmp); 180 181 img.Draw(mem, 0, 0, width, height, 0, 0, width, height); 182 for (int i = 0; i < maxWaku; i++) { DrawWaku(mem, i); } 183 DrawCursor(mem); 184 185 nowWaku = CheckMouse(); 186 wstring wmouseMode; 187 switch (mouseMode) { 188 case MODE_DONE: wmouseMode = L"MODE_DONE"; break; 189 case MODE_CLICK: wmouseMode = L"MODE_CLICK"; break; 190 case MODE_WAKU1: wmouseMode = L"MODE_WAKU1"; break; 191 case MODE_WAKU2: wmouseMode = L"MODE_WAKU2"; break; 192 case MODE_END1: wmouseMode = L"MODE_END1"; break; 193 case MODE_END2: wmouseMode = L"MODE_END2"; break; 194 default: wmouseMode = L"default"; break; 195 } 196 197 PAINTSTRUCT ps; 198 BeginPaint(hWnd, &ps); 199 StretchBlt(hdc, 0, 0, cx, cy, mem, 0, myTop, width, tate, SRCCOPY); 200 TextOut(hdc, 200, 50, wmouseMode.c_str(), (int)wmouseMode.length()); 201 EndPaint(hWnd, &ps); 202 203 SelectObject(mem, obmp); 204 DeleteObject(bmp); 205 206 si.cbSize = sizeof(SCROLLINFO); 207 si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; 208 si.nMin = 0; 209 si.nMax = height - tate; 210 si.nPos = myTop; 211 SetScrollInfo(hWnd, SB_VERT, &si, TRUE); 212 } break; 213 214 case WM_VSCROLL: { 215 switch (LOWORD(wParam)) { 216 case SB_LINEUP: 217 if (myTop > 10) { myTop -= 10; } else { myTop = 0; } break; 218 case SB_LINEDOWN: 219 if (myTop < height - tate - 10) { myTop += 10; } else { myTop = height - tate; } break; 220 case SB_PAGEUP: 221 if (myTop > tate) { myTop -= tate; } else { myTop = 0; } break; 222 case SB_PAGEDOWN: 223 if (myTop < height - tate * 2) { myTop += tate; } else { myTop = height - tate; } break; 224 case SB_THUMBTRACK: 225 myTop = HIWORD(wParam); break; 226 } 227 InvalidateRect(hWnd, NULL, FALSE); 228 } break; 229 230 case WM_LBUTTONDOWN: 231 case WM_LBUTTONUP: 232 case WM_MOUSEMOVE: 233 mousex = LOWORD(lParam); 234 mousey = HIWORD(lParam); 235 InvalidateRect(hWnd, NULL, FALSE); 236 break; 237 238 case WM_KEYDOWN: { 239 switch (wParam) { 240 case VK_ESCAPE: 241 if (maxWaku == 0) { 242 PostQuitMessage(0); 243 } else { 244 maxWaku--; 245 nowWaku = maxWaku-1; 246 } 247 break; 248 case VK_NEXT: 249 if (myTop < height - tate * 2) { myTop += tate; } 250 else { myTop = height - tate; } break; 251 case VK_PRIOR: 252 if (myTop > tate) { myTop -= tate; } 253 else { myTop = 0; } break; 254 case VK_DOWN: 255 if (myTop < height - tate - 10) { myTop += 10; } break; 256 case VK_UP: 257 if (myTop > 10) { myTop -= 10; } break; 258 } 259 InvalidateRect(hWnd, NULL, FALSE); 260 } break; 261 262 case WM_COMMAND: { 263 int wmId = LOWORD(wParam); 264 // 選択されたメニューの解析: 265 switch (wmId) { 266 case IDM_ABOUT: 267 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); 268 break; 269 case IDM_EXIT: 270 DestroyWindow(hWnd); 271 break; 272 default: 273 return DefWindowProc(hWnd, message, wParam, lParam); 274 } 275 } break; 276 case WM_DESTROY: PostQuitMessage(0); break; 277 default: return DefWindowProc(hWnd, message, wParam, lParam); 278 } 279 return 0; 280} 281 282// バージョン情報ボックス 283INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { 284 UNREFERENCED_PARAMETER(lParam); 285 switch (message) { 286 case WM_INITDIALOG: return (INT_PTR)TRUE; 287 case WM_COMMAND: 288 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { 289 EndDialog(hDlg, LOWORD(wParam)); 290 return (INT_PTR)TRUE; 291 } break; 292 } 293 return (INT_PTR)FALSE; 294} 295
#リソース不足が原因でしょうか
「途中で止まってしまう」という現象から考えて、リソースの開放に失敗しているのではないかと予想しています。しかし該当すると思われるところについては、以下のとおり DeleteObject で開放していると思うのですが、間違っていますでしょうか。
C++
1 HGDIOBJ ohpen = SelectObject(mem, hpen); 2 SelectObject(mem, GetStockObject(NULL_BRUSH)); 3 Ellipse(mem, memx - 15, myTop + memy - 15, memx + 15, myTop + memy + 15); 4 SelectObject(mem, ohpen); 5 DeleteObject(hpen); 6
C++
1 HPEN hpen = CreatePen(PS_SOLID, 5, mycolor); 2 SelectObject(mem, GetStockObject(NULL_BRUSH)); 3 HGDIOBJ ohpen = SelectObject(mem, hpen); 4 Rectangle(mem, myWaku.at(wk).left, myWaku.at(wk).top, myWaku.at(wk).right, myWaku.at(wk).bottom); 5 SelectObject(mem, ohpen); 6 DeleteObject(hpen);
C++
1 HGDIOBJ obmp = SelectObject(mem, bmp); 2(途中省略) 3 SelectObject(mem, obmp); 4 DeleteObject(bmp); 5
リソースの開放が必要な場所は、以上の3か所かと存じます。
お忙しいところを恐縮ですが、御回答いただければ幸いです。
#補足
止まった時点で、ステップイン(でいいのでしょうか?)をクリックしたところ、最初に次のような画面が表示されました。
回答2件
あなたの回答
tips
プレビュー