プロが教えるわが家の防犯対策術!

通常のスクリーン画面を加工して更新し続ける、たとえば拡大ツールのようなプログラムを作るにあたりまして、
ひとまずスクリーンショットを1秒ごとに更新し続ける動作をさせたいのですが、うまくいきません。

下記のソースはWEBのサンプルをお借りし参考書を見ながら
作りました。

ずっと動かしているとメモリ使用量が上がってしまったりします。
ご指導いただけると助かります。

スクリーン画像を映し続けるプログラム/**
画面キャプチャし続ける
*/
#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

void getScreenShot(int iX, int iY, int iWidth, int iHeight);

HBITMAP _bmpShot = NULL, _bmpOld;
HDC _hdcShot = NULL;

int _iWidth, _iHeight;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){

MSG msg;
WNDCLASS wndclass;

/* ウインドウクラス設定 */
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = "vcshot";

RegisterClass(&wndclass);

/* メインウインドウ作成 */
HWND hwMain = CreateWindow("vcshot", "", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 680, NULL, NULL, hInstance, NULL);

ShowWindow(hwMain, iCmdShow);

/* メッセージループ */
while (GetMessage(&msg, NULL, 0, 0)) {

TranslateMessage(&msg);
DispatchMessage(&msg);

}

return (int)msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {

HDC hdc;
PAINTSTRUCT ps;

switch (iMsg) {

case WM_CREATE:

/* スクリーンショット取得 */
getScreenShot(0, 0, 600, 480);
SetTimer(hwnd , 1 , 100 , NULL);
return 0;

case WM_TIMER:
getScreenShot(0, 0, 600, 480);
return 0;

case WM_PAINT:

hdc = BeginPaint(hwnd, &ps);

/* ビットマップが作成されていれば描画 */
if (_bmpShot != NULL) {
BitBlt(hdc, 0, 0, _iWidth, _iHeight, _hdcShot, 0, 0, SRCCOPY);
}

EndPaint(hwnd, &ps);

return 0;

case WM_DESTROY :

/* ビットマップが作成されていたら関連リソースを削除 */
if (_bmpShot != NULL) {

SelectObject(_hdcShot, _bmpOld);

DeleteObject(_bmpShot);
DeleteObject(_hdcShot);

}

PostQuitMessage(0);

return 0;

}

return DefWindowProc (hwnd, iMsg, wParam, lParam);

}

void getScreenShot(int iX, int iY, int iWidth, int iHeight) {

/* キャプチャサイズを保存 */
_iWidth = iWidth;
_iHeight = iHeight;

/* 画面のデバイスコンテキスト取得 */
HDC hdcScreen = GetDC(0);

/* スクリーンショット保存用ビットマップ作成 */
_bmpShot = CreateCompatibleBitmap(hdcScreen, iWidth, iHeight);

/* ビットマップ描画用デバイスコンテキスト作成 */
_hdcShot = CreateCompatibleDC(hdcScreen);

/* デバイスコンテキストにビットマップを設定 */
_bmpOld = (HBITMAP)SelectObject(_hdcShot, _bmpShot);

/* 画面上の領域をビットマップに描く */
BitBlt(_hdcShot, 0, 0, iWidth, iHeight, hdcScreen, 0, 0, SRCCOPY);

/* 画面のデバイスコンテキスト解放 */
//ReleaseDC(NULL, hdcScreen);

}

A 回答 (1件)

 こんばんは。


 何箇所かで、怪しい部分を発見いたしました。修正してみましたので参考程度に。

/*ビットマップハンドル*/
static HBITMAP _bmpShot = 0;

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
switch (iMsg)
{
case WM_CREATE:
{
/*先に外側で作成してしまう方が得策かもしれない*/
HDC hDC = ::GetDC(0);
_bmpShot = ::CreateCompatibleBitmap(hDC, 600, 480);
::ReleaseDC(0, hDC);

/* スクリーンショット取得 */
getScreenShot(_bmpShot, 0, 0, 600, 480);
SetTimer(hwnd , 1 , 100 , NULL);
return 0;
}
case WM_TIMER:
getScreenShot(_bmpShot, 0, 0, 600, 480);
return 0;

case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);

/* ビットマップが作成されていれば描画 */
if(_bmpShot != NULL)
{
BITMAP bmp;
/*この関数でビットマップから、詳細を知る事が出来る*/
::GetObject(_bmpShot, sizeof(BITMAP), &bmp);

/*以下決まり文句*/
HDC _hdcShot = ::CreateCompatibleDC(0);
::SelectObject(_hdcShot, _bmpShot);
BitBlt(hdc, 0, 0, bmp.bmWidth, bmp.bmHeight, _hdcShot, 0, 0, SRCCOPY);

/*使い終えたら直に閉じる*/
::DeleteDC(_hdcShot);
}

EndPaint(hwnd, &ps);
return 0;
}

case WM_DESTROY :
/* ビットマップが作成されていたら関連リソースを削除 */
if(_bmpShot != NULL)
{
/*SelectObject(_hdcShot, _bmpOld);*/
DeleteObject(_bmpShot);
/*DeleteObject(_hdcShot);←よく見ると、デバイスコンテキストに対してDeleteObjectを使用しています。*/
}

PostQuitMessage(0);

return 0;

}
return DefWindowProc (hwnd, iMsg, wParam, lParam);
}

void getScreenShot(HBITMAP hBmpShot, int iX, int iY, int iWidth, int iHeight)
{
/* キャプチャサイズを保存
_iWidth = iWidth;
_iHeight = iHeight;
*/

/* 画面のデバイスコンテキスト取得 */
HDC hdcScreen = GetDC(0);

/* ビットマップ描画用デバイスコンテキスト作成 */
HDC _hdcShot = CreateCompatibleDC(hdcScreen);

/* スクリーンショット保存用ビットマップ作成 */
/*_bmpShot = CreateCompatibleBitmap(hdcScreen, iWidth, iHeight);*/

/* デバイスコンテキストにビットマップを設定 */
/*_bmpOld = (HBITMAP)*/SelectObject(_hdcShot, hBmpShot);

/* 画面上の領域をビットマップに描く */
BitBlt(_hdcShot, 0, 0, iWidth, iHeight, hdcScreen, 0, 0, SRCCOPY);

/* 画面のデバイスコンテキスト解放 */
ReleaseDC(0, hdcScreen);

/*使用したら直に閉じる*/
::DeleteDC(_hdcShot);
}

この回答への補足

ご丁寧にソースを書き直していただきありがとうございます。
さっそくデバックしてみたところ
'getScreenShot' : 関数に 5 個の引数を指定できません。と
出てしまったので、hBmpShotをbmpShotに変えたところ
ウインドウを別のウインドウで覆い、再度、再上層へ
出すと更新されるのですが、そのままウインドウを出していても更新されません。
元々、
case WM_TIMER:
getScreenShot(0, 0, 600, 480);
return 0;
に原因があると思うのですが、お手上げ状態です。
下記はデバックするように書きかけてしまったソースです
#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

void getScreenShot(int iX, int iY, int iWidth, int iHeight);
/*ビットマップハンドル*/

static HBITMAP _bmpShot = NULL, _bmpOld;
HDC _hdcShot = NULL;

int _iWidth, _iHeight;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){

MSG msg;
WNDCLASS wndclass;

/* ウインドウクラス設定 */
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = "vcshot";

RegisterClass(&wndclass);

/* メインウインドウ作成 */
HWND hwMain = CreateWindow("vcshot", "", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 680, NULL, NULL, hInstance, NULL);

ShowWindow(hwMain, iCmdShow);

/* メッセージループ */
while (GetMessage(&msg, NULL, 0, 0)) {

TranslateMessage(&msg);
DispatchMessage(&msg);

}

return (int)msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
switch (iMsg)
{
case WM_CREATE:
{
/*先に外側で作成してしまう方が得策かもしれない*/
HDC hDC = ::GetDC(0);
_bmpShot = ::CreateCompatibleBitmap(hDC, 600, 480);
::ReleaseDC(0, hDC);

/* スクリーンショット取得 */
getScreenShot( 0, 0, 600, 480);
SetTimer(hwnd , 1 , 100 , NULL);
return 0;
}
case WM_TIMER:
getScreenShot( 0, 0, 600, 480);
return 0;

case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);

/* ビットマップが作成されていれば描画 */
if(_bmpShot != NULL)
{
BITMAP bmp;
/*この関数でビットマップから、詳細を知る事が出来る*/
::GetObject(_bmpShot, sizeof(BITMAP), &bmp);

/*以下決まり文句*/
HDC _hdcShot = ::CreateCompatibleDC(0);
::SelectObject(_hdcShot, _bmpShot);
BitBlt(hdc, 0, 0, bmp.bmWidth, bmp.bmHeight, _hdcShot, 0, 0, SRCCOPY);

/*使い終えたら直に閉じる*/
::DeleteDC(_hdcShot);
}

EndPaint(hwnd, &ps);
return 0;
}

case WM_DESTROY :
/* ビットマップが作成されていたら関連リソースを削除 */
if(_bmpShot != NULL)
{
/*SelectObject(_hdcShot, _bmpOld);*/
DeleteObject(_bmpShot);
/*DeleteObject(_hdcShot);←よく見ると、デバイスコンテキストに対してDeleteObjectを使用しています。*/
}

PostQuitMessage(0);

return 0;

}
return DefWindowProc (hwnd, iMsg, wParam, lParam);
}

void getScreenShot(int iX, int iY, int iWidth, int iHeight)
{
/* キャプチャサイズを保存
_iWidth = iWidth;
_iHeight = iHeight;
*/

/* 画面のデバイスコンテキスト取得 */
HDC hdcScreen = GetDC(0);

/* ビットマップ描画用デバイスコンテキスト作成 */
HDC _hdcShot = CreateCompatibleDC(hdcScreen);

/* スクリーンショット保存用ビットマップ作成 */
/*_bmpShot = CreateCompatibleBitmap(hdcScreen, iWidth, iHeight);*/

/* デバイスコンテキストにビットマップを設定 */
/*_bmpOld = (HBITMAP)*/SelectObject(_hdcShot, _bmpShot);

/* 画面上の領域をビットマップに描く */
BitBlt(_hdcShot, 0, 0, iWidth, iHeight, hdcScreen, 0, 0, SRCCOPY);

/* 画面のデバイスコンテキスト解放 */
ReleaseDC(0, hdcScreen);

/*使用したら直に閉じる*/
::DeleteDC(_hdcShot);
}

補足日時:2008/10/07 11:59
    • good
    • 0
この回答へのお礼

すみません。
上記のデバックエラーは
私の関数宣言が引数4つのままでした。
しかし状況がかわらず、試行錯誤もむなしく
解決できないため、新たに質問を作らせていただきます。
ご親切にありがとうございます。

お礼日時:2008/10/07 15:05

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!