質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

1309閲覧

おそらくリソース不足と思われますが、アプリが止まってしまいます。Visual Studio 2019 C++

TAKASE_Hiroyuki

総合スコア21

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2019/12/22 01:12

編集2019/12/22 01:38

#背景
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か所かと存じます。
お忙しいところを恐縮ですが、御回答いただければ幸いです。

#補足
止まった時点で、ステップイン(でいいのでしょうか?)をクリックしたところ、最初に次のような画面が表示されました。
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Bull

2019/12/22 02:20

リソース不足を疑っているのでしたら、GDI オブジェクトはどうなっていますか? GDI オブジェクトと USER オブジェクトはタスクマネージャで確認出来ます。
TAKASE_Hiroyuki

2019/12/22 09:44

御回答いただき、ありがとうございました。 なにしろ、Visual Studio を使い始めてから日が浅いため、なかなか使いこなすことができません。この場合の、タスクマネージャーは、Visual Studio の機能ではなく、Windows10 のタスクマネージャーだと思いますが、間違いありませんでしょうか。一応「見る」ことはできるのですが、「どういう風に分析すればいいのか」が分かっていません。今後、さらに勉強しようと思います。
guest

回答2

0

ベストアンサー

大きなリソースリーク部分が2箇所あります。

WM_PAINTメッセージのハンドリング部分で CreateCompatibleDCでデバイスコンテキストを作成していますが、DeleteDCで削除していません。

CreateCompatibleDC function - Microsoft Docs

更に、GetDCで取得したデバイスコンテキストも、ReleaseDCで解放されていません。

GetDC - Microsoft Docs

CreateCompatibleDCで作ったらDeleteDCで削除、GetDCで取得したらReleaseDCで解放するようにしてください。

尚、WM_PAINTメッセージの処理では、GetDCでデバイスコンテキストを取得するというよりは、WM_PAINTメッセージ受信時に必ず呼ばなければならないBeginPaintで返されるものを使うのが一般的です。

C++

1PAINTSTRUCT ps; 2HDC hdc; 3 4// WM_PAINTメッセージ受信部分でははBeginPaintのDCが使える。 5hdc = BeginPaint(hWnd, &ps); 6// hdc = GetDC(hWnd); これで取得できたものと同等に使える 7 8...hdc を使って色々と処理。 9 10// ReleaseDC(hWnd, hdc); 11EndPaint(hWnd, &ps);

投稿2019/12/22 03:11

編集2019/12/22 03:15
dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TAKASE_Hiroyuki

2019/12/22 10:02

御回答いただき、ありがとうございました。 ご指摘いただいたことについて、WM_PAINT の中身を書き換えたところ、メモリ使用量はほとんど増えなくなりました。絶対に大丈夫かと言われると、私自身は心もとないのですが、以前に比べると明らかに改善されたと思います。ありがとうございました。
dodox86

2019/12/22 10:15

回答中には書かなかったのですが、こちらでは一応、ご提示のコードをWindows 7(64ビット)、Visual Studio 2019でGDIやUSERのハンドルがリークしていないことを確認済みです。コメントでBullさんがアドバイスされていますが、タスクマネージャーでGDIオブジェクトやUSERオブジェクトの数が稼働中に増え続けてないか確認することで、より確実な対応となると思います。
guest

0

VisualStudio使ってるならデバッグ機能使いましょうよ。
その止まった状態で停止ボタン押したらどうなりますか?
そして、そこからワンステップづつ実行させたら、どこで止まってるのかわかると思います。

さて、どこでどうなって止まってる(とみえる)んでしょうか。


その止まった状態で停止ボタン押したらどうなりますか?(二回目

投稿2019/12/22 01:15

編集2019/12/22 02:25
y_waiwai

総合スコア87782

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TAKASE_Hiroyuki

2019/12/22 09:46

御回答いただき、ありがとうございました。 追記にも書きましたが、どうも、うまく表示されません。Visual Studio の使い方そのものを、さらに勉強しようと思います。 なお、「一番最初からワンステップずつ実行させたらどうなるのか」は、やってみました。同じような場所を何度も何度も行ったり来たりしたあと、WM_PAINT等に進み、だんだん出力が変化していく様子がわかりました。そのことだけでも、とても勉強になりました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問