zoukankan      html  css  js  c++  java
  • 【转】SDL与MFC的混合

    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.

    源链接: http://horseb.i.sohu.com/blog/view/221210214.htm

  • 相关阅读:
    PDF文件中的Form保存问题
    Understanding IP Fragmentation
    tcp ip guide IPsec IKE
    Windows安全事件日志中的事件编号与描述
    Cisco PIX fix up and Juniper firewall FTP ALG
    很好的IPSec介绍,详细解释了IKE协商的2个阶段的作用
    virtualbox 下运行Ubuntu 8.10的分辨率和guest additions的问题。
    Fixing the ‘Do you want to display nonsecure items’ message
    windows xp 开始菜单里面所有项目右键不起作用。
    HP backup and recovery manager
  • 原文地址:https://www.cnblogs.com/bluebbc/p/3116856.html
Copyright © 2011-2022 走看看