とっておきの手土産を教えて

VCでデスクトップ画面に、テレビのチャンネル表示のような文字を表示させたいのですが、方法がわかりません。

別のウインドウに隠れることなく表示できて、マウスでクリックできないようなものを作ることは可能でしょうか?

A 回答 (3件)

 こんにちは。


 当方が知る限りでは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;
}
    • good
    • 0
この回答へのお礼

詳しい回答ありがとうございます。
DirectX環境構築して試してみます。

お礼日時:2009/05/18 14:27

試していないので出来るかどうかわからないのですが、


http://hp.vector.co.jp/authors/VA012320/directx6 …
でVRAMに直接アクセス可能のようですけど、詳しく見てないので分かりません。
(DirectXを使用しているみたいです。)

何らかのライブラリを使わないと、
難しいのではないかと思われます。

英語がある程度できるのであれば、
海外(アメリカ)サイトを探してみてはどうでしょうか?
    • good
    • 0

こんな感じのものでしょうか?


http://wisdom.sakura.ne.jp/system/winapi/win32/w …
もし違うなら無視してかまいません。

「別のウインドウに隠れることなく表示できて~」は、
もしかしたら出来ないかもしれません。
一応当方で試した結果出来ました。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
勉強になりました。
さらに欲を言いますと、ウインドウハンドルを持たず、VRAMに直接描画するような方法についても調べていました。メッセージフック関数に感知されない、描画したときにウインドウメッセージが流れないようにすることはできないですよね。

お礼日時:2009/05/15 23:58

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


おすすめ情報