顯示具有 windows 標籤的文章。 顯示所有文章
顯示具有 windows 標籤的文章。 顯示所有文章

2009年6月16日 星期二

Sleep(1)精準嗎?

在用Sleep(1)函數的時候, 遇到一個怪現象, 就是在不同電腦下, 使用Sleep(1)的精準度會不一樣.

我的測試的方法, 是使用FPS來當測試依據 , 而FPS指的是 "Frame Per Second", 也就是每秒畫面更新的次數, 而FPS對遊戲程式也相當重要, 它會影響畫面的流暢(閃爍和停格等), 下面code為測試程式的source code:

void FPSTest(void)
{
static int Frames = 0; //更新的次數
static int UpdateTime = 1000; //多久算一次FPS
static int LastTime = 0; //上次計算FPS的時間
static double FPS = 0;

Frames++; // 增加更新的次數

if(GetTickCount()-LastTime>UpdateTime) // 如果時間超過,該更新
{
FPS = ((double)Frames/(double)(GetTickCount()-LastTime))*1000.0; // FPS的計算公式
LastTime = GetTickCount(); // 設定時間,給下次用
Frames = 0; // 更新次數歸0

}
}


int _tmain(int argc, _TCHAR* argv[])
{

while(
1)

{
FPSTest();

Sleep(1);

}
return 0;
}


以下是我的測試結果:

(1)
TOSHIBA Intel Core 2 Duo T550 1.83GHZ WinXP SP3
平均 FPS = 512

(2)
ACER Intel Core 2 Duo T7300 2.00GHZ Windows 7 Ultimate
平均 FPS = 64


去請教Google大師, 找到有部份文章提到,多媒體程式庫中有個 timeBeginPeriodAPI,可以設定時間解析度, 用法也很簡單,需要包含mmsystem.h和連結 winmm.lib, 因此將原本測試程式改成 :

int _tmain(int argc, _TCHAR* argv[])
{

timeBeginPeriod(1);
while(1)
{
FPSTest();

Sleep(1);

}
timeEndPeriod(1);
return 0;
}


重新測試結果馬上大不相同,Sleep不再delay,原則上會逼近所要求的等待時間:

(1)
TOSHIBA Intel Core 2 Duo T550 1.83GHZ WinXP SP3
平均 FPS = 512


(2)
ACER Intel Core 2 Duo T7300 2.00GHZ Windows 7 Ultimate
平均 FPS = 1000


注意 :
使用timeBeginPeriod時要注意,原則上調動它會造成系統不必要的負擔,也會改變系統的Sleep()函數的精準度, 記得不用了馬上timeEndPeriod恢復原狀。

參考資料 :


2009年5月19日 星期二

如何隱藏win32 console application的console視窗

此種方法是利用設定編譯器的鏈結開關來實現, 所以讓我們來看一下Linker選項, 如下圖所示



這個Linker選項是告訴作業系統如何運作執行檔,
如果我們建立一個Win32 console application的話,
Linker/subsystem選項應該為Console.

我們知道用VC編寫的程式, 執行的時候是需要 C\C++執行庫支援的.
當我們執行一個C/C++程式的時候, 鏈結器會首先尋找應用程式的啟動函數.


如果你建立了一個console程式的話, Linker的鏈結開關會是下面這種形式
/subsystem:"console" /entry:"mainCRTStartup" (ANSI)
/subsystem:"console" /entry:"wmainCRTStartuup" (UNICODE)


在default情況下/subsystem/entry開關是對應的,也就是:
console 對應 mainCRTStartupwmainCRTStartup
windows 對應 WinMain或者wWinMain

但是我們也可以通過手動的方式使他們不對應,
在default情況下Linker看到/subsystem下是windows選項的時候,
它會自動尋找WinMain或者wWinMain, 但我們強制指定入口位址,
這樣執行程式的時候console視窗就會隱藏!

如下面程式碼所示:

#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) // 設置入口位址
int main(int argc, char* argv[])

{

return 0;
}

參考網址: http://forum.icst.org.tw/phpbb/viewtopic.php?f=44&t=7609&start=0

取得目前螢幕解析度

#include "windows.h"

int ScreenHeight, ScreenWidth;
ScreenHeight = GetSystemMetrics(SM_CYSCREEN); //取得高度的像素
ScreenWidth = GetSystemMetrics(SM_CXSCREEN); //取得寬度的像素

各參數的定義, 可參考此網頁 : http://tech.ddvip.com/2008-11/122655593392184.html

2009年5月17日 星期日

防止程序重複啟動的方法

主要使用到CreateMutex()函數和GetLastError()以及一個常量ERROR_ALREADY_EXISTS.


CreateMutex()函數可用來創建一個有名或無名的互斥量對象,其函數原型為:

HANDLE CreateMutex
(

LPSECURITY_ATTRIBUTES lpMutexAttributes, //指向安全屬性的pointer

BOOL bInitialOwner, //初始化互斥對象的所有者
LPCTSTR lpName //指向互斥對象名字的pointer
);



如果函數執行成功,將return一個互斥量對象的handle。 如果在CreateMutex()執行前已經存在有相同名字的互斥量,函數將返回這個已經存在互斥量的handle,並且可以利用GetLastError()得到錯誤代碼ERROR_ALREADY_EXIST可見,利用對錯誤代碼ERROR_ALREADY_EXIST的檢測可以實現CreateMutex()對程序的互斥。

下面為sample code:
HANDLE ManagerMutex = CreateMutex(NULL, FALSE, _T("OTM_Manager.exe"));

if (GetLastError( ) == ERROR_ALREADY_EXISTS)
{
MessageBox(NULL, _T("OTM_Manager is already running"), _T("Warning!"), MB_OK);
CloseHandle(ManagerMutex );

PostQuitMessage(0);
return FALSE;
}