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

  • 相关阅读:
    web在线调试
    BAPI 注意事项
    HR 删除工资数据
    Python 量化交易安装步骤
    日期金额格式问题
    SD_BAPI
    BAPI
    7.6 yum更换国内源 7.7 yum下载rpm包 7.8/7.9 源码包安装
    安装软件包的三种方法 rpm包介绍 rpm工具用法 yum工具用法 yum搭建本地仓库(
    zip压缩工具 tar打包 打包并压缩
  • 原文地址:https://www.cnblogs.com/bluebbc/p/3116856.html
Copyright © 2011-2022 走看看