ひとりも見捨てないことを、あきらめない

学校教育、社会教育、数学、技術家庭科、Youtube、EdTech、ICT、プログラミング、その他

今度はアプリ全体が停まる・・・12/21 土

次から次へと、問題が発生します。


Visual Studio 2019 C++ アプリが途中で止まる。困った・・・。

 

画像にいくつかのワクが表示してあり、カーソルを重なると、その都度、ワクが選択されるようなプログラムを作成しています。

実際には、マウスをうごかすたびに画像を表示しなおしているのですが、何度も動かしていると途中で止まります。

おそらく、リソースが不足していると思われますが、使用したツールはきちんと DeleteObject でリソースを開放しているはずなので、現時点では原因不明です。

しかし、このままでは、まったく役に立たちません。

困りました。

 

とりあえず、現時点での cpp プログラムを備忘録を兼ねて貼り付けておきますが、teratail と比べてプログラムの記載が難しいですね。

・・・と思ったら、<pre>を使うと簡単に表示できることを発見。htmlは、やっぱり知っておいた方が得だなあ。

#include "framework.h"
#include "ScrollBar_Waku.h"
#include "strconv.h"
#include "atlimage.h"
#include 
using 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;
}

f:id:takase_hiroyuki:20191123160855p:plain