画面拡大ソフトウェア

[戻る]
T 2004/12/01(水) 17:14:06
マウスの周辺を拡大して表示するソフトウェアをつくっています。
開発環境はWindows XP, VC++6.0, SDKです。

マウスの周辺を拡大表示することと、それを追跡することはできたのですが、
タイマをつかっているせいか、画面がチカチカしてしまいます。
また、プログラムを実行した時点で一番上にある情報しか得られません。
そのウィンドウを閉じたり、そのウィンドウの上に新しいウィンドウを開いたとしても
取得できる情報はかわりません。
情報が更新されないという問題が発生しています。

どのようにすればよいでしょうか?
以下に私のつくったプログラムをのせておきます。
どなたかおわかりになる方がいらっしゃいましたら、お教えください。
よろしくお願いいたします。


---以下、ソースです---
WINAPI    WndProc(
    HWND    hwnd,
    UINT    message,
    UINT    wParam,
    LONG    lParam)
{
    static short    cxClient, cyClient;
    BITMAP        bm;
    HDC            hdc;
    PAINTSTRUCT    ps;
    static POINT pt;

    switch (message) {
    case WM_SIZE:
        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);
        return 0;
    case WM_CREATE:
        SetTimer(hwnd, 1, 100, NULL);
        return 0;
    case WM_TIMER:
        GetCursorPos(&pt);
        ReleaseDC(hwnd, hdc);
    case WM_PAINT:
        InvalidateRect(hwnd, NULL, TRUE);
        hdc = BeginPaint(hwnd, &ps);
        if (hBitmap != NULL) {
            SelectObject(hdcMem, hBitmap);
            GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);
            if (draw_mode == IDM_BITBLT) {
                StretchBlt(hdc, 0, 0, cxClient, cyClient,
                        hdcMem, pt.x - 8, pt.y - 6, pt.x + 8, 
pt.y + 6, SRCCOPY);
            } else {
                SetStretchBltMode(hdc, COLORONCOLOR);
                StretchBlt(hdc, 0, 0, cxClient, cyClient,
                           hdcMem, 0, 0, bm.bmWidth, 
bm.bmHeight, SRCCOPY);
            }
        }
        EndPaint(hwnd, &ps);
        return 0;

    case WM_COMMAND:
        switch (LOWORD(wParam)) {
        case IDM_CAPTURE:
            ShowWindow(hwnd, SW_HIDE);
            Sleep(2000);
            CaptureScreen();
            ShowWindow(hwnd, SW_SHOW);
            break;
        case IDM_BITBLT:
        case IDM_STRETCH:
            draw_mode = LOWORD(wParam);
            break;
        case IDM_EXIT:
            DestroyWindow(hwnd);
            break;
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

isshi 2004/12/01(水) 21:06:30
とりあえず気づいたところ。

case WM_TIMER: に break; がない。
もし意図しているとしたら、WM_PAINT でしか使ってはいけない
BeginPaint を WM_TIMER でも使っていることになる。

case WM_TIMER: のところにある ReleaseDC(hwnd, hdc);
の hdc は不定値。
そもそも ReleaseDC は必要ない。(対応する GetDC が見当たらない。)

case WM_PAINT: に InvalidateRect があるのはおかしい。

hdcMem, hBitmap が何なのか不明。

T 2004/12/02(木) 15:23:18
> case WM_TIMER: に break; がない。
> もし意図しているとしたら、WM_PAINT でしか使ってはいけない
> BeginPaint を WM_TIMER でも使っていることになる。

> case WM_TIMER: のところにある ReleaseDC(hwnd, hdc);
> の hdc は不定値。
> そもそも ReleaseDC は必要ない。(対応する GetDC が見当たらない。)

breakを入れると、更新されなくなってしまい、マウスを動かしてもその周辺の情報を取
得し続けることができなくなってしまいました。

ReleaseDCは削除しても、変わらず動きました。。
実は、現在警告が3つ出ます。(実行はできるのですが。)
ReleaseDCを削除すると、警告が一つ減りました。

> case WM_PAINT: に InvalidateRect があるのはおかしい。

> hdcMem, hBitmap が何なのか不明。

申し忘れてしまい、御迷惑おかけしてしまいました。
すべてを私がつくったわけではなく、一部を以下のサイトから引用させていただいており
ます。case WM_PAINTは引用させていただいた箇所です。
私の勉強不足ではありますが、ここの内容は理解しきれておりません。

http://www.microsoft.com/japan/developer/winds/Sdk/Samples/SDKSample04.htm

なお、InvalidateRect を削除してしまってもマウスの動きに合わせて画面情報を更新し
続けることはできなくなってしまいます。

isshi 2004/12/02(木) 16:32:44
>http://www.microsoft.com/japan/developer/winds/Sdk/Samples/SDKSample04.htm
酷いソースですね。

>hdcMem = CreateCompatibleDC(hdc);
>hBitmap = CreateCompatibleBitmap(hdc, screen.cx, screen.cy);
リソースを解放してないし。
WM_PAINT に InvalidateRect があるのはどうなんですかね?
BeginPaint の前にあるから意味があるのでしょうか?
普通は、InvalidateRectで更新リージョンを追加した結果としてWM_PAINTが送られると
思うのですが。

とりあえず、

case WM_TIMER:
  InvalidateRect(hwnd, NULL, FALSE);  // 更新リージョンを追加して
  UpdateWindow(hwnd);  // 再描画を指示
  return 0;

case WM_PAINT:
  CaptureScreen();  // 最新の画像を取得
  hdc = BeginPaint(hwnd, &ps);
  (省略)  
  EndPaint(hwnd, &ps);
  return 0;

のようにしてみてください。
あと、前述のように CaptureScreen() 内に問題があるので直す必要があります。

T 2004/12/02(木) 17:07:32
え・・・ひどいソースだったのですか・・・。

まず、isshiさんのおっしゃるとおりに修正してみました。
すると、実行しても何も起こりませんでした。
そこで、私が重要だと思って入れた
GetCursorPos を追加したところ、以前までは「実行」メニューの「全画面のコピー」と
いうものを選択してから動き出していたのですが、このプログラムを実行した段階ですで
に動き出していました。
また、30秒くらいすると、エラー音のようなものが連続して鳴り始めて止まらなくなって
しまいました。

CaptureScreen の内容もどのように変更すればよいのかわかりません。
もう少し勉強が必要ですね。

isshi 2004/12/02(木) 22:04:23
こんな感じでどうでしょうか?
Tさんの期待する動作かどうか分かりませんが。
WinMain は省略。
(WindowsXP home SP1, VC++7.1 で動作確認)

// test.c
#define ID_TIMER 1
#define ELAPSE 100
#define MAG 4  // 拡大倍率

int draw_mode = IDM_BITBLT;

void OnPaint(HWND hwnd)
{
  HDC hdcsrc, hdcdst;
  PAINTSTRUCT ps;
  SIZE sizesrc;
  RECT dstrect;

  hdcdst = BeginPaint(hwnd, &ps);
  hdcsrc = GetDC(NULL);
  sizesrc.cx = GetDeviceCaps(hdcsrc, HORZRES);
  sizesrc.cy = GetDeviceCaps(hdcsrc, VERTRES);
  GetClientRect(hwnd, &dstrect);

  if (draw_mode == IDM_BITBLT){
    POINT pt;
    GetCursorPos(&pt);
    StretchBlt(
      hdcdst, 0, 0, dstrect.right, dstrect.bottom,
      hdcsrc, pt.x - 8, pt.y - 6, dstrect.right / MAG, dstrect.bottom / MAG,
      SRCCOPY);
  }
  else {
    SetStretchBltMode(hdcdst, COLORONCOLOR);
    StretchBlt(
      hdcdst, 0, 0, dstrect.right, dstrect.bottom,
      hdcsrc, 0, 0, sizesrc.cx, sizesrc.cy, 
      SRCCOPY);
  }
  ReleaseDC(NULL, hdcsrc);
  EndPaint(hwnd, &ps);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM
    lParam)
{
  switch (message) {
  case WM_CREATE:
    SetTimer(hwnd, ID_TIMER, ELAPSE, NULL);
    break;

  case WM_TIMER:
    if (wParam == ID_TIMER){
      KillTimer(hwnd, ID_TIMER);
      InvalidateRect(hwnd, NULL, FALSE);
      UpdateWindow(hwnd);
      SetTimer(hwnd, ID_TIMER, ELAPSE, NULL);
    }
    break;

  case WM_PAINT:
    OnPaint(hwnd);
    break;

  case WM_COMMAND:
    switch (LOWORD(wParam)){
    case IDM_BITBLT:
    case IDM_STRETCH:
      draw_mode = LOWORD(wParam);
      break;
    case IDM_EXIT:
      DestroyWindow(hwnd);
      break;
    }
    break;

  case WM_DESTROY:
    PostQuitMessage(0);
    break;

  default:
    return DefWindowProc(hwnd, message, wParam, lParam);
  }
  return 0;
}

T 2004/12/03(金) 14:09:59
isshiさんのおっしゃるとおりに書き換えてみました。
なんとかエラーも警告も0にできたのですが、
実行するときにAccessViolationというエラーがでてしまい、
デバッガが起動します。

そして、解決方法がわからず、実行はできませんでした・・・。

isshi 2004/12/03(金) 14:36:29
私のソースをそのままコピーしましたか?
ステップ実行するなりして、エラー個所を特定してください。

(Windows2000 SP4, VC++6.0 SP6 でも問題ありませんでした。)

T 2004/12/03(金) 15:12:31
isshiさんのソースをそのまま追記するのではないんですよね?
もとのプログラムの一部を削除しないとだめだと思って、削除した部分がよくなかったの
でしょうか・・・。

ステップ実行しても、常に同じエラーが出てしまいます。

T 2004/12/03(金) 15:40:24
[[解決]]
isshiさん、どうもありがとうございます。
再度、いじってみたらできました。
プログラムを実行した時点ですでに画面拡大をはじめているので、こちらのほうがよいと
思います。
isshiさんの教えていただいたソースはまだちょっと理解できていないので、
じっくり読んで理解したいと思います。

どうもありがとうございました。

古いスレッドには追加発言できません。