Http://xiaoer-1982.iteye.com/blog/502231
The SDL design does not take into account the need to be combined with MFC, but since it needs to run on a Windows system, it must use the APIS provided by windows. To Use SDL in mfc sdi, replace the window created by SDL with the window provided by MFC.
In Windows, the API used to create a window must be createwindow. You can search the SDL code to easily find the code:
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)
/* Windows2.1 does not have strtol */
Wchar_t * extends wid_t = sdl_malloc (sdl_strlen (windowid) + 1) * sizeof (wchar_t ));
Multibytetowidechar (cp_acp, mb_precomposed, windowid,-1, incluwid_t, sdl_strlen (windowid) + 1 );
Sdl_window = (hwnd) wcstol (rows wid_t, null, 0); sdl_free (rows wid_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 );
}
Note that the previous if condition uses sdl_windowid. If this variable is not 0, SDL will not create a new window! This value is directly from the sdl_windowid environment variable! We can infer that as long as the environment variable sdl_windowid is set before sdl_init is called, SDL can use the window we provide.
Next, modify the testwin example provided by SDL to run it in the mfc sdi environment.
1.1 Project Creation
Directly use the vs2008 Wizard to generate an MFC project named sdi_sdl and select the SDI type.
1.2 discard sdlmain. Lib
Sdlmain must be used in all test cases provided by SDL. lib, this lib file implements the winmain and main entry functions, and some SDL initialization work is carried out in these two functions. In MFC, we do not need to write winmain by ourselves, so we directly discard sdlmain. lib and transfer the relevant code to the oncreate function of csdi_sdlview. Csdi_sdlview: oncreate is selected because the window has been created. You can obtain the handle of the window and set the window ID before SDL initialization.
Int csdi_sdlview: oncreate (maid)
{
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
This function is derived from the winmain function in sdlmain, but some unnecessary code is deleted:
/* This is where execution begins [using wed apps] */
Int csdi_sdlview: sdl_winmain (hinstance hinst, hinstance hprev, lpstr sz1_line, int SW)
{
Hinstance handle;
Char ** argv; int argc;
Char * character line;
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;
Using line = sdl_stack_alloc (char, nlen );
Sdl_strlcpy (using line, bufp, nlen );
/* Parse it into argv and argc */
Argc = parsecommandline (optional line, 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
This function is derived from the main function in sdlmain. Lib:
/* 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
This function is derived from the main function in the testwin example. It only deletes exit statements such as sdl_quit at the end.
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 % d video mode: % s/n ","");
Return (1 );
}
Drawpict (screen, argv [1], speedy, flip, nofade );
// Sdl_delay (delay * 1000 );
// Sdl_quit ();
Return (0 );
}
So far, this program can run normally, but its size cannot change with the change of the main window. To solve this problem, you also need to respond to 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
When the program exits, you need to call sdl_quit for some cleaning work. I originally wanted to put this work in cview: ondestroy, but I found a lot of memory leaks. Finally, put it in csdi_sdlapp: exitinstance to complete:
Bool csdi_sdlapp: exitinstance ()
{
Sdl_quit ();
Return true;
}
Even so, there is still a memory leak for unknown reasons: 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.