windows ce : crash when destroying a fullscreen window

Started by
4 comments, last by Vincent Torri 15 years, 10 months ago
Hey, I'm writing a program that draws in fullscreen some images on a Windows CE device. I write on linux and I cross compile with cegcc. The program raises an exception. Here is a sample code to reproduce the error:

// arm-wince-cegcc-gcc -g -Wall -o winmo2.exe winmo2.c -laygshell -Wl,--enable-auto-import

#include <stdio.h>

#include <windows.h>

// GAPI

#define LINK(type,name,import)   name = (fct_##type)GetProcAddress (GX_lib, import)

#define GX_FULLSCREEN 0x01
#define GX_NORMALKEYS 0x02

#define kfDirect555   0x40
#define kfDirect565   0x80

typedef struct _GXDisplayProperties
{
  DWORD cxWidth;
  DWORD cyHeight;
  LONG  cbxPitch;
  LONG  cbyPitch;
  LONG  cBPP;
  DWORD ffFormat;
} GXDisplayProperties;

typedef struct _GXKeyList {
  short vkUp;             // key for up
  POINT ptUp;             // x,y position of key/button.  Not on screen but in screen coordinates.
  short vkDown;
  POINT ptDown;
  short vkLeft;
  POINT ptLeft;
  short vkRight;
  POINT ptRight;
  short vkA;
  POINT ptA;
  short vkB;
  POINT ptB;
  short vkC;
  POINT ptC;
  short vkStart;
  POINT ptStart;
} GXKeyList;

typedef int   (*fct_GXOpenDisplay)(HWND hWnd, DWORD dwFlags);
typedef int   (*fct_GXCloseDisplay)();
typedef GXDisplayProperties (*fct_GXGetDisplayProperties)();
typedef void* (*fct_GXBeginDraw)();
typedef int   (*fct_GXEndDraw)();
typedef int   (*fct_GXOpenInput)();
typedef int   (*fct_GXCloseInput)();
typedef  GXKeyList (*fct_GXGetDefaultKeys)(int iOptions);
typedef int   (*fct_GXSuspend)();
typedef int   (*fct_GXResume)();

HMODULE GX_lib = NULL;

fct_GXOpenDisplay GXOpenDisplay = NULL;
fct_GXCloseDisplay GXCloseDisplay = NULL;
fct_GXGetDisplayProperties GXGetDisplayProperties = NULL;
fct_GXBeginDraw GXBeginDraw = NULL;
fct_GXEndDraw GXEndDraw = NULL;
fct_GXOpenInput GXOpenInput = NULL;
fct_GXCloseInput GXCloseInput = NULL;
fct_GXGetDefaultKeys GXGetDefaultKeys = NULL;
fct_GXSuspend GXSuspend = NULL;
fct_GXResume GXResume = NULL;

GXKeyList gx_keylist;


// global

HWND window;

int fb_width = 0;
int fb_height = 0;
int fb_stride_x = 0;
int fb_stride_y = 0;
int fb_bpp = 0;
void *fb_data = NULL;


static int result = 1;


static LRESULT CALLBACK
window_procedure(HWND window,
		 UINT msg,
		 WPARAM wparam,
		 LPARAM lparam)
{
  switch (msg) {
  case WM_KEYDOWN:
    {
      if (wparam == (unsigned int)gx_keylist.vkDown) {
	result = 0;
	break;
      }
      return 0;
    }
  case WM_DESTROY:
    result = 0;
    break;
  case WM_KILLFOCUS:
    if (GXSuspend)
      GXSuspend ();
    break;
  case WM_SETFOCUS:
    if (GXResume)
      GXResume ();
    break;
  default:
    return DefWindowProc(window, msg, wparam, lparam);
  }

  return 0;
}

int
window_create ()
{
  WNDCLASS wc;
  RECT     rect;

  memset (&wc, 0, sizeof (wc));
  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc = window_procedure;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hInstance = GetModuleHandle(NULL);
  wc.hIcon = NULL;
  wc.hCursor = LoadCursor (NULL, IDC_ARROW);
  wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
  wc.lpszMenuName =  NULL;
  wc.lpszClassName = L"class name";

  RegisterClass(&wc);

  //resize window to cover screen
  SetRect(&rect, 0, 0,
          GetSystemMetrics(SM_CXSCREEN),
          GetSystemMetrics(SM_CYSCREEN));

  window = CreateWindowEx (WS_EX_TOPMOST,
                           L"class name", L"",
                           WS_VISIBLE | WS_POPUP,
                           rect.left, rect.top,
                           rect.right - rect.left,
                           rect.bottom - rect.top,
                           NULL,
                           NULL,
                           GetModuleHandle(NULL),
                           NULL);
  if (!window) {
    printf ("error : CreateWindowEx\n");
    return 0;
  }

  // hide task bar, start icon and sip button
  SHFullScreen(window,
               SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_HIDESIPBUTTON);

  return 1;
}

void
window_destroy ()
{
  printf ("10\n");
  if (window)
    DestroyWindow (window);
  printf ("11\n");
}

int
gapi_init (void)
{
  GXDisplayProperties prop;

  GX_lib = LoadLibrary(L"\\Windows\\gx.dll");
  if (!GX_lib) {
    GX_lib = LoadLibrary(L"gx.dll");
    if (!GX_lib) {
      printf ("error : LoadLibrary\n");
      return 0;
    }
  }

  printf ("load lib success\n");

  LINK(GXOpenDisplay, GXOpenDisplay, L"?GXOpenDisplay@@YAHPAUHWND__@@K@Z");
  LINK(GXCloseDisplay, GXCloseDisplay, L"?GXCloseDisplay@@YAHXZ");
  LINK(GXGetDisplayProperties, GXGetDisplayProperties, L"?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ");
  LINK(GXBeginDraw, GXBeginDraw, L"?GXBeginDraw@@YAPAXXZ");
  LINK(GXEndDraw, GXEndDraw, L"?GXEndDraw@@YAHXZ");
  LINK(GXOpenInput, GXOpenInput, L"?GXOpenInput@@YAHXZ" );
  LINK(GXCloseInput, GXCloseInput, L"?GXCloseInput@@YAHXZ" );
  LINK(GXGetDefaultKeys, GXGetDefaultKeys, L"?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z");
  LINK(GXSuspend, GXSuspend, L"?GXSuspend@@YAHXZ" );
  LINK(GXResume, GXResume, L"?GXResume@@YAHXZ" );

  printf ("link lib success\n");

  if (!GXOpenDisplay ||
      !GXCloseDisplay ||
      !GXGetDisplayProperties ||
      !GXBeginDraw ||
      !GXEndDraw ||
      !GXOpenInput ||
      !GXCloseInput ||
      !GXGetDefaultKeys ||
      !GXSuspend ||
      !GXResume) {
    printf ("error : no valid symbols\n");
    FreeLibrary (GX_lib);
    return 0;
  }
  printf ("link lib success2\n");

  if (!GXOpenDisplay (window, GX_FULLSCREEN)) {
    printf ("error : GXOpenDisplay\n");
    FreeLibrary (GX_lib);
    return 0;
  }
  printf ("open disp success\n");

  prop = GXGetDisplayProperties();

  // verify pixel format
  if(!(prop.ffFormat & kfDirect565)) {
    printf ("error : GAPI format mismatch\n");
    GXCloseDisplay ();
    FreeLibrary (GX_lib);
    return 0;
  }

  // verify we have a vga device
  if ((GetSystemMetrics(SM_CXSCREEN) != (int)prop.cxWidth) ||
      (GetSystemMetrics(SM_CYSCREEN) != (int)prop.cyHeight)) {
    printf ("error : GAPI format mismatch\n");
    GXCloseDisplay ();
    FreeLibrary (GX_lib);
    return 0;
  }

  if (!GXOpenInput ()) {
    printf ("error : GXOpenInput\n");
    GXCloseDisplay ();
    FreeLibrary (GX_lib);
    return 0;
  }

  fb_width = prop.cxWidth;
  fb_height = prop.cyHeight;
  fb_stride_x = prop.cbxPitch;
  fb_stride_y = prop.cbyPitch;
  fb_bpp = prop.cBPP;

  gx_keylist = GXGetDefaultKeys (GX_NORMALKEYS);

  printf ("init bon\n");

  return 1;
}

void
gapi_shutdown (void)
{
  GXCloseInput();
  GXCloseDisplay ();
  FreeLibrary (GX_lib);
  GX_lib = NULL;
}

int
gapi_rect_draw (int x, int y, int w, int h)
{
  unsigned short *buffer;
  unsigned short *tmp;
  int i;
  int j;

  buffer = (unsigned short *)GXBeginDraw ();
  if (!buffer) {
    printf ("error : GXBeginDraw\n");
    return 0;
  }

  memset (buffer, 0, fb_stride_y * fb_height);

  tmp = buffer + y * (fb_stride_y / 2) + x;
  for (j = 0; j < h; ++j, tmp += (fb_stride_y / 2)) {
    for (i = 0; i < w; i++) {
      tmp = (31 << 11) + (0 << 5) + (0 << 0);
    }
  }

  GXEndDraw();

  return 1;
}

int main ()
{
  if (!window_create ()) {
    printf ("error window_create\n");
    return -1;
  }

  if (!gapi_init ()) {
    printf ("error backend_init\n");
    window_destroy ();
    return -1;
  }

  ShowWindow(window, SW_SHOWNORMAL);
  UpdateWindow(window);

/*   while (result) { */
/*     MSG msg; */

/*     if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { */
/*       TranslateMessage (&msg); */
/*       DispatchMessage (&msg); */
/*     } */
/*     rect_draw (backend, 10, 10, 30, 30); */
/*   } */

  gapi_shutdown ();
  window_destroy ();

  return 0;
}

I have a Win CE exception : Access violation (code 0xc0000005) during the window_destroy() function ('10' is displayed, but not '11', which means that DestroyWindow sends that exception). Des someone know why ? thank you
Advertisement
i've found the solution : when DestroyWindow is called, the WM_KILLFOCUS message is called, hence GXSuspend is called, but GAPI has been shudown. I just need to set GXSuspend (and GXResume) to NULL when i shutdown GAPI
For what its worth, you are aware that GAPI is deprecated, right? You might want to reconsider your back-end in the near future unless you're content to only support legacy devices.

throw table_exception("(? ???)? ? ???");

i am aware of that. But some devices have no directdraw and do not support raw framebuffer. I have an Ipaq H3970, with only GAPI on it.

Actually, I'm porting a canvas library to windows ce devices. I want to support raw framebuffer, gapi and directdraw. Maybe direct3d if I have a device that supports it.
GETRAWFRAMEBUFFER support is also going away, due to hardware limitations (specifically, newer generations of mobile LCD screens), so the major path from this point on will be DirectDraw.

In exclusive mode, you'll basically get the same performance as in GAPI by creating a primary surface and then doing lock/unlock on it. In fact, it should be pretty easy to write a middle layer that uses DDraw when available, and falls back on GAPI when it's not.

Unfortunately, the capabilities of devices are going to be fragmented. GAPI is deprecated, and DirectDraw doesn't exist on many earlier devices. I'm pretty sure all Windows Mobile 6 (and up) devices have DDraw standard.

I suggest: don't ever use GETRAWFRAMEBUFFER. Use DDraw wherever possible (preferably use Fullscreen Exclusive mode, because you're guaranteed to get the best performance), and only fall back on GAPI when you must.
Quote:Original post by Drilian
I suggest: don't ever use GETRAWFRAMEBUFFER. Use DDraw wherever possible (preferably use Fullscreen Exclusive mode, because you're guaranteed to get the best performance), and only fall back on GAPI when you must.


i have to use GETRAWFRAMEBUFFER, (actually GETGXINFO) because Ipaq H3970 devices do not have directdraw and gapi is not working at all, because of the driver which is broken as hell. That's something that I have found recently. So my previous post is not really correct

All the advices use that if **, then use that if **, then use that can't be followed. Because all the devices have specific features, problems, etc... When you code for that OS, you almost have to do something specific for each pda. It's really NOT so simple.

This topic is closed to new replies.

Advertisement