Advertisement

Illegal operation

Started by April 06, 2002 08:31 PM
5 comments, last by Magriep 22 years, 8 months ago
The engine I''m making so far can draw a window and has the code to initialize D3D. Now the code compiles fine, but when I run the program, the program draws the window and then I get an illegal operation. Any suggestions or solutions would be helpful. Here is the code I''m using:
  
// include files ////////////////////////////////////////////////////////////


#include <windows.h> // needed for windows 
#include <d3d8.h>    // needed for direct 3d


class CEngine {
	// declare data members

private:
	char *g_strAppName;
	LPDIRECT3D8 g_pD3D;
	LPDIRECT3DDEVICE8 g_pd3dDevice;
	HWND              g_hWnd;

public:
	char* GetAppName();
	CEngine();
	void InitD3D();	
	void UnInitD3D();
	void PaintWindow(HDC hdc);
};
CEngine::CEngine() {	
	g_strAppName = "Dark Age: Rise of The Underworld";	
	g_pD3D = NULL;
	g_pd3dDevice = NULL;
	g_hWnd = NULL;
}
void CEngine::InitD3D() {
// create a Direct3D device

  g_pD3D = Direct3DCreate8( D3D_SDK_VERSION );
  if(g_pD3D == NULL) {
    throw("Direct3DCreate8 failed.");
  }

  // Get the current desktop display mode

  D3DDISPLAYMODE d3ddm;
  if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm))) {
    throw("GetAdapterDisplayMode failed.");
  }
  
  D3DPRESENT_PARAMETERS d3dpp; 
  ZeroMemory( &d3dpp, sizeof(d3dpp) ); // this will set all members to zero

  
  // setting zero for width and height will tell windows to use window

  // dimensions for backbuffer dimensions.

  d3dpp.BackBufferWidth = 0;
  d3dpp.BackBufferHeight = 0;

  // request a back buffer format that matches the current desktop display 

  // format.

  d3dpp.BackBufferFormat = d3ddm.Format;

  // we want 1 back buffer

  d3dpp.BackBufferCount = 1;

  // no multisampling

  d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;

  // "discard" swap effect.  This means that we should never care about

  // the contents of the front buffer - we should always re-render the

  // entire screen on the back buffer each frame.  This is the most

  // efficient method of presenting the back buffer.

  d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

  // use our window as the device window

  d3dpp.hDeviceWindow = g_hWnd;

  // we want to do D3D in a window

  d3dpp.Windowed = TRUE; 

  // we don''t want Direct3D to manage depth buffers for us

  // (that''s because we don''t use any right now)

  d3dpp.EnableAutoDepthStencil = false;
  d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN;

  // no special flags

  d3dpp.Flags = 0;

  // default refresh rate

  d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;

  // default presentation interval (we must use this because we''re in

  // a window)

  d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
  
  // Create the Direct3D device. 

  if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, 
                                 D3DDEVTYPE_HAL, g_hWnd,
                                 D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                 &d3dpp, &g_pd3dDevice)))
  {
    throw("CreateDevice failed.");
  }
}
void CEngine::UnInitD3D(void) {
  // first, release any devices we''ve created.

  if(g_pd3dDevice != NULL) {
    g_pd3dDevice->Release();
    g_pd3dDevice = NULL; // just to be safe

  }

  // next, release the direct3d interface.

  if(g_pD3D != NULL) {
    g_pD3D->Release();
    g_pD3D = NULL; // just to be safe

  }
}

void CEngine::PaintWindow(HDC hdc) {
  // most directX games don''t really use WM_PAINT.

  // instead, they run their own animation loop, and flip (aka "present") 

  // their backbuffers several times per second.


  // the following code clears the backbuffer black, then displays it.

  g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, 
    D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
    
  // Present the backbuffer contents to the display

  g_pd3dDevice->Present( NULL, NULL, NULL, NULL );

}
char *CEngine::GetAppName() {  
	return g_strAppName;
}

CEngine* g_MyEngine;
LRESULT CALLBACK WindowProc(
  HWND hwnd,      // handle to window

  UINT uMsg,      // message identifier

  WPARAM wParam,  // first message parameter

  LPARAM lParam   // second message parameter

) 
{
    switch(uMsg) {	
	case WM_PAINT:
      {
	  PAINTSTRUCT ps;

      // get the DC we''re supposed to use from Windows

      BeginPaint(hwnd, &ps);
      HDC hdc = ps.hdc;
      
      // paint our window (function is defined above)

      g_MyEngine->PaintWindow(hdc);
      
      // tell Windows we''re done painting.

      EndPaint(hwnd, &ps);
	  }
    // we processed the message, so return 0.

    return(0);

    case WM_DESTROY: // our window is being destroyed!  quit!

		g_MyEngine->UnInitD3D();
    	PostQuitMessage(0);
        return(0);
	}


  // all the other messages, we don''t care about, so we let DefWindowProc

  // handle them.

  return(DefWindowProc(hwnd, uMsg, wParam, lParam));
}
   int WINAPI WinMain(HINSTANCE g_hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
   {
	   //Allocate memory for engine (IMPORTANT)  

	   g_MyEngine = new CEngine;
	   // set up and register window class	

	   HWND hwnd;
	   WNDCLASSEX wc;	
	   memset(&wc, 0, sizeof(wc)); // clear everything	

	   wc.cbSize = sizeof(wc);
	   wc.style = CS_HREDRAW | CS_VREDRAW;	
	   wc.lpfnWndProc = WindowProc;	
	   wc.cbClsExtra = 0;
	   wc.cbWndExtra = 0;
	   wc.hInstance = g_hInstance;	
	   wc.hIcon = NULL;
	   wc.hIconSm = NULL;
	   wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	   wc.hbrBackground = NULL;
	   wc.lpszMenuName = NULL;
	   wc.lpszClassName = "GameMainWindow";
	   RegisterClassEx(&wc);
	   
	   // create a window with a width of 640 pixels wide and a height of 480 pixels

	   hwnd = CreateWindowEx(0, "GameMainWindow", g_MyEngine->GetAppName(), 
		   WS_OVERLAPPEDWINDOW, 10, 10, 640, 480, NULL, NULL, g_hInstance, NULL);
	   if (!hwnd)    {
		   ::MessageBox(NULL, "Create window failed!", g_MyEngine->GetAppName(), MB_ICONSTOP);
	   }	//After you get a handle to your window then I would create

	   //an instance of your CEngine classg_MyEngine = new CEngine();

	   //Now you can use this object in your wndproc function

	   ShowWindow(hwnd,SW_SHOW);
	   try {
	   g_MyEngine->InitD3D();
	   } catch(const char *errmsg) {

    // if we threw any const char *''s, catch them here, display the error,

    // then exit.

    MessageBox(hwnd, errmsg, g_MyEngine->GetAppName(), 0);
  }
  catch(...) {
    // catch unhandled exceptions.

    MessageBox(hwnd, "An unknown error occurred.", g_MyEngine->GetAppName(), 0);
  }
       // message pump	

	   // message pump

  while (1) {
    MSG msg;
    if (PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE))
    {
      int result = GetMessage(&msg, 0, 0, 0);
      if (!result) return(msg.wParam);

      TranslateMessage(&msg); 
      DispatchMessage(&msg);
    }
  }

	   //delete the Engine object  

	   delete g_MyEngine;
	   return 0;
   }  
I don't know nothing about D3D, but as far as strings are concerned, u should not do this
g_strAppName = "Dark Age: Rise of The Underworld";
but you should allocate enough memory for your string or just create it as an array of chars and then
strcpy(g_strAppName,"Dark Age:Rise of the Underworld");
And you may need to #include <string.h> for strcpy();

Hope it helps


[edited by - remi on April 6, 2002 9:56:25 PM]

[edited by - remi on April 6, 2002 9:57:10 PM]
"...and we all know what "undefined" means: it means it works during development, it works during testing, and it blows up in your most important customers' faces."----------Scott Meyers, "Effective C++"
Advertisement
Assigning a string literal to a character pointer is perfectly legal, as C statically allocates memory for it before execution.
ah yes, I forgot about the strcpy function, but I''m still getting the illegal operation? Anyone know what''s wrong?
I can guess...

1. the second catch in WinMain looks suscipicious - I assume the unhandled exception falls through?

2. In WM_PAINT you can get the HDC like this as well

HDC hdc = BeginPaint(hwnd, &ps);

3. I think this is it - you''re calling g_MyEngine->InitD3D() before setting g_hWnd equal to hwnd, so you end up crashing when you call g_pD3D->CreateDevice(...) - that would do it - the call to ShowWindow succeed and then the InitD3D fails because of an invalid hwnd parameter in the call to CreateDevice.
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
I''m sorry, I don''t exactly understand what you mean. The only place where it uses CreateDevice is here:
if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,                                  D3DDEVTYPE_HAL, g_hWnd,                                 D3DCREATE_SOFTWARE_VERTEXPROCESSING,                                 &d3dpp, &g_pd3dDevice))) 

and g_hWnd is set to NULL, which is what the book I''m using told me to do.
Advertisement
Yes, and here you say...

// use our window as the device window
d3dpp.hDeviceWindow = g_hWnd;

So this suggested to me that g_hWnd shouldn''t be null, but should be a handle to the window created in WinMain. The MS docs say that parameter should be the "Window handle to which focus belongs for this Microsoft® Direct3D® device."

Your other comments also suggest that g_hWnd should be set equal to hwnd as well

// we want to do D3D in a window
d3dpp.Windowed = TRUE;

// default presentation interval (we must use this because we''re in
// a window)
d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;

Otherwise, how do you attach the window to the d3d device? At any rate, it''s worth a shot.

Also - this doesn''t have any thing to do with the error you''re getting, but prefixing member variables with g_ suggests that they are global variables. You might consider using m_ to prefix member vars and use g_ to prefix global vars (like g_MyEngine).

"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man

This topic is closed to new replies.

Advertisement