隨筆-348  評論-598  文章-0  trackbacks-0

          快樂蝦

          http://blog.csdn.net/lights_joy/

          lights@hb165.com

           

          本文適用于

          SDL-1.2.13

          vs2008

          Windows XP

           

          歡迎轉載,但請保留作者信息


          SDL的設計并沒有考慮到要和MFC相結合,但是既然它要在windows的系統上運行,必然需要使用Windows提供的API。為了在MFC SDI中使用SDL,首先想到的就是替換SDL創建的窗口,改為使用MFC提供的窗口。

          想想在Windows下要創建窗口需要使用的API必然是CreateWindow,在SDL代碼中搜,很容易發現了這樣一段代碼:

          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,如果這個變量不為0,那么SDL是不會創建新窗口的!而這個值直接來自于SDL_WINDOWID這個環境變量!以此推斷,只要在調用SDL_Init之前設置好SDL_WINDOWID這個環境變量,那么SDL將可以使用我們提供的窗口。

          下面修改SDL提供的testwin示例,使之在MFC SDI環境下運行。

          1.1    工程創建
          直接使用VS2008的向導生成一個叫sdi_sdl的MFC工程,選擇SDI類型。

          1.2    拋棄SDLmain.lib
          在SDL提供的測試用例中,都要使用SDLmain.lib,這個lib文件實現了Winmain和main這兩個入口函數,在這兩個函數中進行了一些SDL的初始化工作。而在MFC下,我們不需要自己寫WinMain,因此直接拋棄SDLmain.lib,將相關的代碼轉移到Csdi_sdlView的OnCreate函數中。之所以選擇Csdi_sdlView::OnCreate是因為此時窗口已經創建,可以取到這個窗口的Handle,從而可以在SDL初始化之前設置好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
          這個函數來源于SDLmain中的WinMain函數,只是刪除了一些不必要的代碼:

          /* 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
          這個函數來源于sdlmain.lib中的main函數:

          /* 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
          這個函數來自于testwin示例中的main函數,只是在末尾刪除了SDL_Quit這樣的退出語句。

          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);

          }

          至此,這個程序就可以正常運行了,但是它的大小還不能隨主窗口的變化而變化。為此還需要響應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
          在程序退出的時候,需要調用SDL_Quit進行一些清理的工作,原來想將這個工作放在Cview::OnDestroy中完成,但是發現這樣有很多的內存泄漏。最后將其放在Csdi_sdlApp:ExitInstance中完成:

          BOOL Csdi_sdlApp::ExitInstance()

          {

               SDL_Quit();

               return TRUE;

          }

          即便是這樣,仍然有一處內存泄漏,原因不明:

          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.

           

          本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/lights_joy/archive/2009/04/04/4049123.aspx



          ---------------------------------------------------------
          專注移動開發

          Android, Windows Mobile, iPhone, J2ME, BlackBerry, Symbian
          posted on 2010-03-27 15:26 TiGERTiAN 閱讀(1276) 評論(0)  編輯  收藏 所屬分類: Other technique
          主站蜘蛛池模板: 镇远县| 苍溪县| 永宁县| 淮阳县| 建宁县| 平山县| 怀化市| 夹江县| 定州市| 馆陶县| 大连市| 葫芦岛市| 志丹县| 西和县| 新沂市| 报价| 临泽县| 民乐县| 志丹县| 织金县| 榕江县| 百色市| 苍山县| 兖州市| 浏阳市| 建始县| 南城县| 平凉市| 临澧县| 邯郸县| 武穴市| 兴化市| 涪陵区| 交城县| 夏邑县| 山丹县| 历史| 青龙| 多伦县| 金溪县| 黄石市|