スクリーンセーバーの描写が突然消えるバグの原因

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
スー

スクリーンセーバーの描写が突然消えるバグの原因

#1

投稿記事 by スー » 16年前

皆さんこんばんは。
何度も何度もスクリーンセーバーについて質問させてもらっているスーです。
悲しいかな、今回も自分の力では解決できそうにないので皆さんの力を貸してください。

WindowsAPIを使ってスクリーンセーバーを作っています。
デスクトップ画面を表示しながら、複数のベジュ曲線を描写するというものです。
そのベジュ曲線は残像?を表示しながら画面内を跳ね返ります。
ここまではできたのですが、スクリーンセーバーを起動してから一定時間でベジュ曲線だけが消えてしまいます。
消える時間も表示するベジュ曲線の数によって変わります。
ベジュ曲線*3 残像は0本 線の合計は3本 はおよそ90秒後に
ベジュ曲線*3 残像は4本 線の合計は15本 はおよそ10秒後に
ベジュ曲線*3 残像は9本 線の合計は30本 はおよそ5秒後に消えてしまいます。

この現象の原因が分かる方がいましたら、是非教えてください。
よろしくお願いします。

環境
VC++2005
WindowsXP

添付ファイルにスクリーンセーバーを入れようと思ったら容量オーバーでした;;
http://www1.axfc.net/uploader/He/so/217943
こちらに本体をアップしました。パスワードは「suu」です。

以下ソースです。
//-------------------------------------------
//               main.cpp
//-------------------------------------------
#include <windows.h> 
#include <scrnsave.h>
#include <time.h>
//ベジュ曲線の数
#define LINE 3
//ペンの作成
LOGPEN RedPen;

//ベジュ曲線のヘッダー
#include "BezierCurve.h"

//スクリーンセーバを作るためのライブラリ
#pragma comment(lib,"ScrnSave.lib")
#pragma comment(lib,"Comctl32.lib")

//タイマーのID
#define ID_TIMER 32767
//ウインドの縦、横幅
int wx,wy;

/*ハンドルコンテキスト*/
//ダブルバッファ用
HDC backhdc; 
//デスクトップ画面用
HDC DeskBmphdc;
//メインハンドル
RECT rc;
HDC hdc;

//デスクトップ画面をDeskBmphdcに保存する
void GetDeskTop(){
	HDC Deskhdc;
	HBITMAP DeskBmp;
	// 画面のデバイスコンテキスト取得
	Deskhdc = CreateDCA("DISPLAY",NULL,NULL,NULL);
	// /ビットマップ作成
	DeskBmp = CreateCompatibleBitmap(Deskhdc,wx,wy);
	// ビットマップ描画用デバイスコンテキスト作成
	DeskBmphdc = CreateCompatibleDC(Deskhdc);
	// デバイスコンテキストにビットマップを設定
	SelectObject(DeskBmphdc, DeskBmp);
	// 画面上の領域をビットマップに描く
	BitBlt(DeskBmphdc, 0, 0, wx, wy, Deskhdc, 0, 0, SRCCOPY);
	//解放
	ReleaseDC(NULL,Deskhdc);
	DeleteObject(DeskBmp);
}

//仮想的な裏画面を作る
HDC Back_Init_Surface(HWND hwnd){
	HDC hdc,BackDC;
	HBITMAP hBackBMP;

	//今の画面を取得
	hdc = GetDC(hwnd);          
	//仮想的なHDCの作成
	BackDC = CreateCompatibleDC(hdc);     
	//ビットマップ作成
	hBackBMP = CreateCompatibleBitmap(hdc,wx,wy);
	//hBackBMPとBackDCの設定
	SelectObject(BackDC,hBackBMP);
	//画面初期化
	PatBlt(BackDC,0,0,wx,wy,BLACKNESS);
	//解放
	DeleteObject(hBackBMP);
	ReleaseDC(hwnd,hdc);

	return BackDC;
}


LRESULT WINAPI ScreenSaverProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
	//乱数の初期化
	srand((unsigned)time(NULL));
	//ベジュ曲線を三つ作る
	static BezierCurve bez[LINE];

	switch(msg){   
		//画面を消さない
		case WM_ERASEBKGND:
			return true;
		case WM_CREATE:
			//ウインドの縦、横幅所得
			GetClientRect(hWnd,&rc);
			wx = rc.right-rc.left;
			wy = rc.bottom-rc.top;

			//デスクトップ画面所得
			GetDeskTop();

			//裏画面作成
			backhdc = Back_Init_Surface(hWnd); 

			//ペンの設定
			RedPen.lopnStyle = PS_SOLID;
			RedPen.lopnWidth.x = 2;

			//ベジュ曲線初期設定の
			for(int i=0;i<LINE;i++)
				bez.Set(wx,wy);

			//タイマーのセット
			SetTimer(hWnd,ID_TIMER,8,NULL);
			break;
        case WM_TIMER: 
			//画面初期化とデスクトップ画面描写
			BitBlt(backhdc, 0, 0, wx, wy, DeskBmphdc, 0, 0, SRCCOPY);
			// 今の画面を取得
			hdc = GetDC(hWnd);
			//ベジュ曲線の描写と移動等
			for(int i=0;i<LINE;i++){
				bez.Draw(backhdc);
				bez.Action();
			}
			//もう描写しませんよ~
			ReleaseDC(hWnd,hdc);
			//ダブルバッファ 裏画面にあるものを表画面に書く
			BitBlt(hdc,0,0,wx,wy,backhdc,0,0,SRCCOPY);
			break;
		case WM_DESTROY:
			//いろいろ解放
			KillTimer(hWnd,ID_TIMER);
			ReleaseDC(hWnd,backhdc); 
			ReleaseDC(hWnd,hdc); 
			ReleaseDC(hWnd,DeskBmphdc); 
			PostQuitMessage(0);
			return 0;
        default:
			break;
    }
    return DefScreenSaverProc(hWnd, msg, wParam, lParam);
}
//設定画面 まだ作れていない
BOOL WINAPI ScreenSaverConfigureDialog(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam){
    return TRUE;
}
BOOL WINAPI RegisterDialogClasses(HANDLE hInst){
    return TRUE;
}

スー

Re:スクリーンセーバーの描写が突然消えるバグの原因

#2

投稿記事 by スー » 16年前

続きです。
//-------------------------------------------
//               BezierCurve.h
//-------------------------------------------

//残像線の数
#define MAXLINE 5
//ベジュ曲線クラス
class BezierCurve{
public:
	//カレントポジション(始点)
	float st_x[MAXLINE],st_y[MAXLINE];
	//制御点
	POINT pt[MAXLINE][3];
	//色
	int r[MAXLINE],g[MAXLINE],b[MAXLINE];

	/*速度*/
	//カレントポジションの加速度
	int st_vx,st_vy;
	//制御点の加速度
	int pt_vx[3],pt_vy[3];

	//色の加算率
	int pr,pg,pb;
	//ウインドの縦、横幅
	int wx,wy;
	
	//コンストラクタ(初期化)
	BezierCurve();
	//初期化
	void Set(int WX,int WY);
	//描写
	void Draw(HDC);
	//移動、色の加算
	void Action();
};

BezierCurve::BezierCurve(){

	//初期位置設定
	st_x[0] = rand()%640;
	st_y[0] = rand()%480;
	for(int i=0;i<3;i++){
		pt[0].x = rand()%640;
		pt[0].y = rand()%480;
	}
	r[0] = rand()%105+150;
	g[0] = rand()%105+150;
	b[0] = rand()%105+150;

	//配列の[1]~[MAXLINE]まで[0]を代入
	for(int i=0;i<MAXLINE;i++){
		st_x = st_x[0];
		st_y = st_y[0];
		for(int j=0;j<3;j++)
			pt[j] = pt[0][j];
		r = r[0];
		g = g[0];
		b = b[0];
	}

	//初期速度の設定
	st_vx = rand()%5+1,st_vy = rand()%5+1;
	for(int i=0;i<3;i++){
		pt_vx = i+rand()%5+1;
		pt_vy = i+rand()%5+1;
	}
	//色の加算の設定
	pr = rand()%3+1;
	pg = rand()%3+1;
	pb = rand()%3+1;

}
void BezierCurve::Set(int WX,int WY){
	//縦、横幅を所得
	wx = WX;
	wy = WY;
}

void BezierCurve::Draw(HDC hdc){
	for(int i=0;i<MAXLINE;i++){
		//色選択
		RedPen.lopnColor = RGB(r[i] , g[i] , b[i]);
		//ペンとハンドルコンテキストの設定
		SelectObject(hdc, CreatePenIndirect(&RedPen));
		//ベジュ曲線描写
		MoveToEx(hdc, st_x[i], st_y[i], NULL);
		PolyBezierTo(hdc, pt[i], 3);
		//オブジェクトの解放
		DeleteObject(SelectObject(hdc , GetStockObject(WHITE_BRUSH)));
	}
}

void BezierCurve::Action(){
	//先頭の処理(移動)
	st_x[0] += st_vx;
	st_y[0] += st_vy;
	if(st_x[0] < 0 || st_x[0] > wx)st_vx *= -1;
	if(st_y[0] < 0 || st_y[0] > wy)st_vy *= -1;
	for(int i=0;i<3;i++){
		pt[0][i].x += pt_vx[i];
		pt[0][i].y += pt_vy[i];
		if(pt[0][i].x < 0 || pt[0][i].x > wx)pt_vx[i] *= -1;
		if(pt[0][i].y < 0 || pt[0][i].y > wy)pt_vy[i] *= -1;
	}
	//色の加算
	r[0] += pr;
	g[0] += pg;
	b[0] += pb;
	if(r[0] > 250 || r[0] < 150)pr *= -1;
	if(g[0] > 250 || g[0] < 150)pg *= -1;
	if(b[0] > 250 || b[0] < 150)pb *= -1;

	//後ろの処理 [9]=[8] [8]=[7]っていう風に次々代入
	for(int j=0;j<MAXLINE-1;j++){
		st_x[MAXLINE-j-1] = st_x[MAXLINE-j-2];
		st_y[MAXLINE-j-1] = st_y[MAXLINE-j-2];
		for(int i=0;i<3;i++){
			pt[MAXLINE-j-1][i] = pt[MAXLINE-j-2][i];
		}
		r[MAXLINE-j-1] = r[MAXLINE-j-2];
	}
}

スー

Re:スクリーンセーバーの描写が突然消えるバグの原因

#3

投稿記事 by スー » 16年前

いろいろ実験してみた所バグの原因がわかりました。

//-------------------------------------------
// BezierCurve.h
//-------------------------------------------
void BezierCurve::Draw(HDC hdc){
	for(int i=0;i<MAXLINE;i++){
		HPEN Pen = CreatePen(PS_SOLID , 2 , RGB(r[0] , g[0] , b[0]));
		SelectObject(hdc , Pen);
		//ベジュ曲線描写
		MoveToEx(hdc, (int)st_x, (int)st_y, NULL);
		PolyBezierTo(hdc, pt, 3);
		//オブジェクトの解放
		DeleteObject(Pen);
	}
}

使うペンの型をLOGPEN型からHPEN型に変えて、解放をしたら直りました;;
皆様お騒がせしました。


閉鎖

“C言語何でも質問掲示板” へ戻る