- 締切済み
オーバーレイみたいな処理がしたい
VCでデスクトップ画面に、テレビのチャンネル表示のような文字を表示させたいのですが、方法がわかりません。 別のウインドウに隠れることなく表示できて、マウスでクリックできないようなものを作ることは可能でしょうか?
- みんなの回答 (3)
- 専門家の回答
みんなの回答
- machongola
- ベストアンサー率60% (434/720)
こんにちは。 当方が知る限りではDirectDrawで出来ます(Direct3Dでは分からない)。 以下は1秒間デスクトップの中央に描写を行いますが、実際のプログラムは、1秒で終わる事は無いので、別途DirectInputを併用して、入力を待機する事になると思います。 ビットマップファイルを読み込んで、DirectDrawSurfaceに向かって送り込む際、必ず、SYSTEMメモリ側のDirectDrawSurfaceを仲介してください。 ビデオカードの種類によっては、VRAM側で出来てしまう物もあるのですが、其れを期待すると、別のビデオカードで失敗する事があります。 昔のゲームはこのような理由で、シャットダウンする物がありました。以下参考程度に。 #include<windows.h> #include<tchar.h> #include<ddraw.h> #include<mmsystem.h> #pragma comment(lib, "dxguid.lib") #pragma comment(lib, "ddraw.lib") #pragma comment(lib, "winmm.lib") //スレッドから参照するデータ struct DATA { LPDIRECTDRAW7 pDD; LPDIRECTDRAWSURFACE7 pDDSScreen;//デスクトップ LPDIRECTDRAWSURFACE7 pDDSOffScreen;//VRAM側バックバッファ LPDIRECTDRAWSURFACE7 pDDSBitmap;//SYSTEM側バックバッファ DWORD dwDesktopWidth; DWORD dwDesktopHeight; }; //COMの解放 static VOID Destruct(DATA& data) { data.pDDSScreen->Release(); data.pDDSOffScreen->Release(); data.pDDSBitmap->Release(); data.pDD->Release(); } //DirectDrawの作成 static LPDIRECTDRAW7 CreateDD() { LPDIRECTDRAW7 pDD = NULL; ::DirectDrawCreateEx(NULL, (LPVOID*)&pDD, IID_IDirectDraw7, NULL); if(!pDD)return NULL; pDD->SetCooperativeLevel(NULL, DDSCL_NORMAL); return pDD; } //DirectDrawSurface作成(デスクトップ側) static LPDIRECTDRAWSURFACE7 CreateScreenSurface(LPDIRECTDRAW7 pDD) { LPDIRECTDRAWSURFACE7 pDDS = NULL; DDSURFACEDESC2 ddsd2 = {sizeof(ddsd2)}; ddsd2.dwFlags = DDSD_CAPS; ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; pDD->CreateSurface(&ddsd2, &pDDS, NULL); return pDDS; } //DirectDrawSurface作成(オフスクリーン側:バックバッファの事) static LPDIRECTDRAWSURFACE7 CreateOffScreenSurface(LPDIRECTDRAW7 pDD, DWORD dwWidth, DWORD dwHeight, bool bSystem = false) { LPDIRECTDRAWSURFACE7 pDDS = NULL; DDSURFACEDESC2 ddsd2 = {sizeof(ddsd2)}; ddsd2.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; ddsd2.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | (bSystem ? DDSCAPS_SYSTEMMEMORY : DDSCAPS_VIDEOMEMORY); ddsd2.dwWidth = dwWidth; ddsd2.dwHeight= dwHeight; pDD->CreateSurface(&ddsd2, &pDDS, NULL); return pDDS; } //ビットマップを読み込んで、SYSTEMメモリ側のDirectDrawSurfaceに送り込む static LPDIRECTDRAWSURFACE7 CreateBitmapSurface(LPDIRECTDRAW7 pDD, LPCTSTR tstrFileName, DWORD dwWidth, DWORD dwHeight) { DDSURFACEDESC2 ddsd2 = {sizeof(ddsd2)}; LPDIRECTDRAWSURFACE7 pDDS = ::CreateOffScreenSurface(pDD, dwWidth, dwHeight, true); if(!pDDS)return NULL; //ビットマップをファイルから読む HBITMAP hBitmap = (HBITMAP)::LoadImage(NULL, tstrFileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION | LR_DEFAULTSIZE); BITMAP bitmap; ::GetObject(hBitmap, sizeof(bitmap), &bitmap); //ビットマップデバイスコンテキストの作成 HDC hDCMem = ::CreateCompatibleDC(NULL); HGDIOBJ hGdiObj = ::SelectObject(hDCMem, hBitmap); //サーフェースデバイスコンテキストの作成(ビデオカードによってはVRAMから作成出来るが、SYSTEMメモリ側で行うのが無難) HDC hDCSurface = NULL; pDDS->GetDC(&hDCSurface); ::StretchBlt(hDCSurface, 0, 0, dwWidth, dwHeight, hDCMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY); pDDS->ReleaseDC(hDCSurface); //ビットマップの解放 ::SelectObject(hDCMem, hGdiObj); ::DeleteDC(hDCMem); ::DeleteObject(hBitmap); return pDDS; } //DirectDrawSurfaceから矩形サイズを取る static const RECT GetSurfaceRect(LPDIRECTDRAWSURFACE7 pDDS) { DDSURFACEDESC2 ddsd2 = {sizeof(ddsd2)}; ddsd2.dwFlags = DDSD_WIDTH | DDSD_HEIGHT; pDDS->GetSurfaceDesc(&ddsd2); const RECT rc = {0, 0, ddsd2.dwWidth, ddsd2.dwHeight}; return rc; } //スレッド static DWORD WINAPI ThreadProc(LPVOID p) { DATA* pdata = (DATA*)p; const DWORD dwStart = ::timeGetTime(); RECT rc = ::GetSurfaceRect(pdata->pDDSOffScreen); //デスクトップの中央に来る様に座標x,yを計算する const POINT pt = {(pdata->dwDesktopWidth - rc.right) / 2, (pdata->dwDesktopHeight - rc.bottom) / 2}; //一秒間回す while(::timeGetTime() - dwStart <= 1000) { //VRAMに描写 pdata->pDDSScreen->BltFast(pt.x, pt.y, pdata->pDDSOffScreen, &rc, DDBLTFAST_WAIT); } return 0; } //お試し int main(void) { DATA data = {NULL}; //デスクトップのサイズを計測する HWND hWndDesktop = ::GetDesktopWindow(); HDC hDCDesktop = ::GetDC(hWndDesktop); data.dwDesktopWidth = ::GetDeviceCaps(hDCDesktop, HORZRES); data.dwDesktopHeight= ::GetDeviceCaps(hDCDesktop, VERTRES); ::ReleaseDC(hWndDesktop, hDCDesktop); //DirectDrawの初期化 data.pDD = ::CreateDD(); data.pDDSScreen = ::CreateScreenSurface(data.pDD); data.pDDSBitmap = ::CreateBitmapSurface(data.pDD, _T("test.bmp"), 640, 480); data.pDDSOffScreen = ::CreateOffScreenSurface(data.pDD, 640, 480); //SYTEM→VRAMへ複写 RECT rc = {0, 0, 640, 480}; data.pDDSOffScreen->BltFast(0, 0, data.pDDSBitmap, &rc, DDBLTFAST_WAIT); //タイマ解像度の初期化 TIMECAPS tc = {0}; ::timeGetDevCaps(&tc, sizeof(tc)); ::timeBeginPeriod(tc.wPeriodMin); //スレッドを回転させる DWORD dwThreadID = 0; HANDLE hThread = ::CreateThread(NULL, 0, &::ThreadProc, &data, CREATE_SUSPENDED, &dwThreadID); ::SetThreadPriority(hThread, THREAD_PRIORITY_LOWEST); ::ResumeThread(hThread); //スレッドが落ちてくるまで待つ ::WaitForSingleObject(hThread, INFINITE); ::CloseHandle(hThread); //デスクトップを書き直す ::InvalidateRect(NULL, NULL, NULL); //COMの解放 ::Destruct(data); //タイマ解像度を戻す ::timeEndPeriod(tc.wPeriodMin); return 0; }
試していないので出来るかどうかわからないのですが、 http://hp.vector.co.jp/authors/VA012320/directx6.html でVRAMに直接アクセス可能のようですけど、詳しく見てないので分かりません。 (DirectXを使用しているみたいです。) 何らかのライブラリを使わないと、 難しいのではないかと思われます。 英語がある程度できるのであれば、 海外(アメリカ)サイトを探してみてはどうでしょうか?
こんな感じのものでしょうか? http://wisdom.sakura.ne.jp/system/winapi/win32/win93.html もし違うなら無視してかまいません。 「別のウインドウに隠れることなく表示できて~」は、 もしかしたら出来ないかもしれません。 一応当方で試した結果出来ました。
お礼
回答ありがとうございます。 勉強になりました。 さらに欲を言いますと、ウインドウハンドルを持たず、VRAMに直接描画するような方法についても調べていました。メッセージフック関数に感知されない、描画したときにウインドウメッセージが流れないようにすることはできないですよね。
お礼
詳しい回答ありがとうございます。 DirectX環境構築して試してみます。