快樂(lè)蝦
http://blog.csdn.net/lights_joy/
lights@hb165.com
本文適用于
SDL-1.2.13
vs2008
Windows XP
歡迎轉(zhuǎn)載,但請(qǐng)保留作者信息
SDL的設(shè)計(jì)并沒(méi)有考慮到要和MFC相結(jié)合,但是既然它要在windows的系統(tǒng)上運(yùn)行,必然需要使用Windows提供的API。為了在MFC SDI中使用SDL,首先想到的就是替換SDL創(chuàng)建的窗口,改為使用MFC提供的窗口。
想想在Windows下要?jiǎng)?chuàng)建窗口需要使用的API必然是CreateWindow,在SDL代碼中搜,很容易發(fā)現(xiàn)了這樣一段代碼:
int DIB_CreateWindow(_THIS)
{
char *windowid = SDL_getenv("SDL_WINDOWID");
SDL_RegisterApp(NULL, 0, 0);
SDL_windowid = (windowid != NULL);
if ( SDL_windowid ) {
#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
/* wince 2.1 does not have strtol */
wchar_t *windowid_t = SDL_malloc((SDL_strlen(windowid) + 1) * sizeof(wchar_t));
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, windowid, -1, windowid_t, SDL_strlen(windowid) + 1);
SDL_Window = (HWND)wcstol(windowid_t, NULL, 0);
SDL_free(windowid_t);
#else
SDL_Window = (HWND)SDL_strtoull(windowid, NULL, 0);
#endif
if ( SDL_Window == NULL ) {
SDL_SetError("Couldn't get user specified window");
return(-1);
}
/* DJM: we want all event's for the user specified
window to be handled by SDL.
*/
userWindowProc = (WNDPROCTYPE)GetWindowLongPtr(SDL_Window, GWLP_WNDPROC);
SetWindowLongPtr(SDL_Window, GWLP_WNDPROC, (LONG_PTR)WinMessage);
} else {
SDL_Window = CreateWindow(SDL_Appname, SDL_Appname,
(WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX),
CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL, SDL_Instance, NULL);
if ( SDL_Window == NULL ) {
SDL_SetError("Couldn't create window");
return(-1);
}
ShowWindow(SDL_Window, SW_HIDE);
}
/* JC 14 Mar 2006
Flush the message loop or this can cause big problems later
Especially if the user decides to use dialog boxes or assert()!
*/
WIN_FlushMessageQueue();
return(0);
}
注意到前面的if條件判斷使用了SDL_windowid,如果這個(gè)變量不為0,那么SDL是不會(huì)創(chuàng)建新窗口的!而這個(gè)值直接來(lái)自于SDL_WINDOWID這個(gè)環(huán)境變量!以此推斷,只要在調(diào)用SDL_Init之前設(shè)置好SDL_WINDOWID這個(gè)環(huán)境變量,那么SDL將可以使用我們提供的窗口。
下面修改SDL提供的testwin示例,使之在MFC SDI環(huán)境下運(yùn)行。
1.1 工程創(chuàng)建
直接使用VS2008的向?qū)梢粋€(gè)叫sdi_sdl的MFC工程,選擇SDI類型。
1.2 拋棄SDLmain.lib
在SDL提供的測(cè)試用例中,都要使用SDLmain.lib,這個(gè)lib文件實(shí)現(xiàn)了Winmain和main這兩個(gè)入口函數(shù),在這兩個(gè)函數(shù)中進(jìn)行了一些SDL的初始化工作。而在MFC下,我們不需要自己寫WinMain,因此直接拋棄SDLmain.lib,將相關(guān)的代碼轉(zhuǎn)移到Csdi_sdlView的OnCreate函數(shù)中。之所以選擇Csdi_sdlView::OnCreate是因?yàn)榇藭r(shí)窗口已經(jīng)創(chuàng)建,可以取到這個(gè)窗口的Handle,從而可以在SDL初始化之前設(shè)置好Window id。
int Csdi_sdlView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
char variable[256];
sprintf(variable, "SDL_WINDOWID=0x%lx", this->GetSafeHwnd());
SDL_putenv(variable);
SDL_WinMain(AfxGetApp()->m_hInstance, NULL, AfxGetApp()->m_lpCmdLine, SW_MAXIMIZE);
return 0;
}
1.3 SDL_WinMain
這個(gè)函數(shù)來(lái)源于SDLmain中的WinMain函數(shù),只是刪除了一些不必要的代碼:
/* This is where execution begins [windowed apps] */
int Csdi_sdlView::SDL_WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
{
HINSTANCE handle;
char **argv;
int argc;
char *cmdline;
char *bufp;
size_t nLen;
/* Start up DDHELP.EXE before opening any files, so DDHELP doesn't
keep them open. This is a hack.. hopefully it will be fixed
someday. DDHELP.EXE starts up the first time DDRAW.DLL is loaded.
*/
handle = LoadLibrary(TEXT("DDRAW.DLL"));
if ( handle != NULL ) {
FreeLibrary(handle);
}
/* Grab the command line */
bufp = GetCommandLine();
nLen = SDL_strlen(bufp)+1;
cmdline = SDL_stack_alloc(char, nLen);
SDL_strlcpy(cmdline, bufp, nLen);
/* Parse it into argv and argc */
argc = ParseCommandLine(cmdline, NULL);
argv = SDL_stack_alloc(char*, argc+1);
ParseCommandLine(cmdline, argv);
/* Run the main program (after a little SDL initialization) */
SDL_PreMain(argc, argv);
/* Hush little compiler, don't you cry... */
return 0;
}
1.4 SDL_PreMain
這個(gè)函數(shù)來(lái)源于sdlmain.lib中的main函數(shù):
/* This is where execution begins [console apps] */
int Csdi_sdlView::SDL_PreMain(int argc, char *argv[])
{
size_t n;
char *bufp, *appname;
int status;
/* Get the class name from argv[0] */
appname = argv[0];
if ( (bufp=SDL_strrchr(argv[0], '\\')) != NULL ) {
appname = bufp+1;
} else
if ( (bufp=SDL_strrchr(argv[0], '/')) != NULL ) {
appname = bufp+1;
}
if ( (bufp=SDL_strrchr(appname, '.')) == NULL )
n = SDL_strlen(appname);
else
n = (bufp-appname);
bufp = SDL_stack_alloc(char, n+1);
SDL_strlcpy(bufp, appname, n+1);
appname = bufp;
///* Load SDL dynamic link library */
//if ( SDL_Init(SDL_INIT_NOPARACHUTE) < 0 ) {
// ShowError("WinMain() error", SDL_GetError());
// return(FALSE);
//}
/* Sam:
We still need to pass in the application handle so that
DirectInput will initialize properly when SDL_RegisterApp()
is called later in the video initialization.
*/
SDL_SetModuleHandle(GetModuleHandle(NULL));
/* Run the application main() code */
status = SDL_main(argc, argv);
/* Hush little compiler, don't you cry... */
return 0;
}
1.5 SDL_main
這個(gè)函數(shù)來(lái)自于testwin示例中的main函數(shù),只是在末尾刪除了SDL_Quit這樣的退出語(yǔ)句。
int Csdi_sdlView::SDL_main(int argc, char *argv[])
{
SDL_Surface *screen;
/* Options */
int speedy, flip, nofade;
int delay;
int w, h;
int desired_bpp;
Uint32 video_flags;
/* Set default options and check command-line */
speedy = 0;
flip = 0;
nofade = 0;
delay = 1;
RECT rc;
this->GetWindowRect(&rc);
w = rc.right;
h = rc.bottom;
desired_bpp = 0;
video_flags = 0;
if ( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) < 0 ) {
ShowError("Couldn't initialize SDL", SDL_GetError());
return(1);
}
/* Initialize the display */
screen = SDL_SetVideoMode(w, h, desired_bpp, video_flags);
if ( screen == NULL ) {
ShowError("Couldn't set %dx%dx%d video mode: %s\n", "");
return (1);
}
DrawPict(screen, argv[1], speedy, flip, nofade);
// SDL_Delay(delay*1000);
// SDL_Quit();
return(0);
}
至此,這個(gè)程序就可以正常運(yùn)行了,但是它的大小還不能隨主窗口的變化而變化。為此還需要響應(yīng)WM_SIZE:
void Csdi_sdlView::OnSize(UINT nType, int cx, int cy)
{
SDL_Surface *screen;
screen = SDL_SetVideoMode(cx, cy, 0, 0);
DrawPict(screen, NULL, 0, 0, 0);
}
1.6 SDL_Quit
在程序退出的時(shí)候,需要調(diào)用SDL_Quit進(jìn)行一些清理的工作,原來(lái)想將這個(gè)工作放在Cview::OnDestroy中完成,但是發(fā)現(xiàn)這樣有很多的內(nèi)存泄漏。最后將其放在Csdi_sdlApp:ExitInstance中完成:
BOOL Csdi_sdlApp::ExitInstance()
{
SDL_Quit();
return TRUE;
}
即便是這樣,仍然有一處內(nèi)存泄漏,原因不明:
Detected memory leaks!
Dumping objects ->
{98} normal block at 0x003D37C0, 21 bytes long.
Data: <0x40784 OWID 0x4> 30 78 34 30 37 38 34 00 4F 57 49 44 00 30 78 34
Object dump complete.
本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/lights_joy/archive/2009/04/04/4049123.aspx
---------------------------------------------------------
專注移動(dòng)開發(fā)
Android, Windows Mobile, iPhone, J2ME, BlackBerry, Symbian
posted on 2010-03-27 15:26
TiGERTiAN 閱讀(1280)
評(píng)論(0) 編輯 收藏 所屬分類:
Other technique