Thread: CreateWindowEx() failing with 64-bit

  1. #1
    Registered User
    Join Date
    Jun 2009
    Posts
    5

    Question CreateWindowEx() failing with 64-bit

    Hi guys,

    I'm new to this forum and fairly new to Windows programming as well. Anyway, I inherited some code from a previous engineer that works fine in 32-bit, but fails in 64-bit. In 64-bit, CreateWindowEx() fails, and GetLastError() returns code 1413, which is "invalid index". I haven't been able to find anything online mentioning any problem with CreateWindowEx() in 64-bit environments.

    Any help is appreciated:

    Code:
    //call this function to creat the actual window.
    bool CPrintWindow::Create(char*     szWindowName, 
                              DWORD     dwStyle, 
                              const     RECT& rect,   
                              HWND      hParentWnd, 
                              HINSTANCE hInst,
                              char*     szClassName, 
                              bool      registerClass)
    {
      //TraceFunc("CPrintWindow::Create()");  
    
      if(registerClass) //local register requested
      {
        if(!szClassName) szClassName = "DefaultCPrintWindowName"; //if no name specified
        m_wndClass.lpszClassName     = szClassName;
        m_wndClass.hInstance         = hInst;
        
        if(!GetClassInfo(hInst, szClassName, &m_wndClass))
        {
          //not yet registered, must register
          m_classAtom = RegisterClass(&m_wndClass);
        }
      }
      else if(!szClassName) 
        return false; //error, must have a WNDCLASS
    
      m_hInstance = hInst;
    
      //set the static variable to point to this instance so that
      //the message loop can find it when it starts up
      m_lastCPrintWindow = this;
    
      m_hWndMain = CreateWindowEx(m_exStyle,
                                  szClassName,	
                                  szWindowName,	
                                  dwStyle,
                                  rect.left,
                                  rect.top,
                                  rect.right  - rect.left,
                                  rect.bottom - rect.top,
                                  hParentWnd,
                                  NULL,
                                  m_hInstance,
                                  NULL);
      
      if(m_hWndMain) 
        return true; //success
    
      //Failed! - Give a detailed error message to show what went wrong
      char szMessage[256];
      DWORD result = GetLastError();
      FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, result, 0, szMessage, 256, 0);
      MessageBox(NULL, szMessage, "Error", MB_OK);
    
      return false;
    }
    I'm not sure if it matters, but there is a thread created off the main thread, which then calls the Create() function above. I can post the code for that if you think it might be a problem.

    Thanks,
    Kenneth

  2. #2
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    Do you have any calls to GetWindowLongPtr/GetClassLongPtr or their Set equivalents in the relevant WndProc for WM_NCCREATE or WM_CREATE? That'd be my bet. You should also check that RegisterClass is succeeding, though that would probably give a different error.

    The use of FormatMessage seems a bit dubious too, FORMAT_MESSAGE_IGNORE_INSERTS should also be passed so that it doesn't try and do parameter substitution in messages that require it. FormatMessage will fail if you pass NULL/0 for the last parameter and the string contains inserts, causing your MessageBox to potentally display garbage.

  3. #3
    Registered User
    Join Date
    Jun 2009
    Posts
    5
    Here's the wndproc:

    Code:
    		static __declspec(dllexport) 
    		LRESULT CALLBACK WndProcedure(HWND   hWnd,   UINT wMessage, 
    									  WPARAM wParam, LPARAM lParam)
    		{
    			//retrieve the pointer to the class stored in the HWND
    #ifdef _WIN64
    			CPrintWindow* pWnd = (CPrintWindow*)GetWindowLongPtr(hWnd, 0);
    #else
    			CPrintWindow* pWnd = (CPrintWindow*)GetWindowLong(hWnd, 0);
    #endif	    
    		    if (pWnd == NULL)  //this must be the first time here 
    			{
    				//store the class instance
    #ifdef _WIN64
    				SetWindowLongPtr(hWnd, 0, (ULONG_PTR)m_lastCPrintWindow);
    				//Set pWnd to point to the class instance
    				pWnd = (CPrintWindow*)GetWindowLongPtr(hWnd, 0);   
    #else
    				SetWindowLong(hWnd, 0, (LONG)m_lastCPrintWindow); 
    				//Set pWnd to point to the class instance
    				pWnd = (CPrintWindow*)GetWindowLong(hWnd, 0);   
    #endif
    
    			}
    			return pWnd->OnMainMessage(hWnd, wMessage, wParam, lParam);
    		}
    Here's OnMainMessage():

    Code:
    //this is the main message loop.
    //handles most used messages here
    LRESULT CPrintWindow::OnMainMessage(HWND hWnd, UINT wMessage, 
                                        WPARAM wParam, LPARAM lParam)
    {
      //TraceFunc("CPrintWindow::OnMainMessage()");  
    
      LRESULT result = 0;
      m_hWndMain     = hWnd;
      
      if (wMessage == WM_DESTROY)
      {
        result = 0;
        SendMessage(m_hWndMain, WM_QUIT, 0, 0);
      }
      
      //first see if this message is handled by any other handler
      if (OnMessage(hWnd, wMessage, wParam, lParam, &result)) 
        return result;
      
      //see if the message is one of the basic handled ones, 
      //and call the correct handler if it is
      switch (wMessage)
      {
      case WM_PAINT:
        {
          PAINTSTRUCT psPaint;
          HDC hDC = BeginPaint(hWnd, &psPaint);
          OnPaint(hDC, &psPaint);
          EndPaint(hWnd, &psPaint);
        }
        break;
    
      case WM_ERASEBKGND:
        {
          HDC hDC = (HDC) wParam;
          if (OnEraseBkGnd(hDC)) 
            return true; //handled, so return
          else 
            return DefWindowProc(hWnd, wMessage, wParam, lParam);
        }
        //break;
    
      case WM_COMMAND:
        if(!OnCommand(wParam, lParam))
          return DefWindowProc(hWnd, wMessage, wParam, lParam); //return if handled
        break;
      
      default:
        //seems like this message was not processed by any handler, so
        //let's send it to the default handler
        return DefWindowProc(hWnd, wMessage, wParam, lParam);
        //break;
      }
      return 0;
    }
    I wasn't able to find "WM_NCCREATE" or "WM_CREATE" anywhere in the code...

  4. #4
    Registered User
    Join Date
    Jun 2009
    Posts
    5
    Okay, I just traced through WndProcedure() and found that this line,

    Code:
    CPrintWindow* pWnd = (CPrintWindow*)GetWindowLongPtr(hWnd, 0);
    and this line,

    Code:
    pWnd = (CPrintWindow*)GetWindowLongPtr(hWnd, 0);
    return null. hWnd seems to be correct, though:

    Intellisense:
    Code:
    hWnd = 0x00000000012e0114 {unused=??? }

  5. #5
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    What is m_wndClass.cbWndExtra set to? It should be sizeof(CPrintWindow*) or at least greater than or equal to 4 or 8 if it's in an #ifdef _WIN64 block.

  6. #6
    Registered User
    Join Date
    Jun 2009
    Posts
    5
    Yes, thank you. It used to be 4, actually, but I changed it to sizeof(CPrintWindow *) and now the window displays.

    However, the contents of the window doesn't show up. It is painted using bitblt(). You can see the handling for WM_PAINT in OnMainMessage() above. BeginPaint() results in:

    Intellisense:
    Code:
    hDC = 0xfffffffff9010287 {unused=??? }
    Intellisense:
    Code:
    psPaint = {hdc=0xfffffffff9010287 fErase=0 rcPaint={...} ...}
    Both point to the same address and look wrong...This causes OnPaint(), which is overridden in my code, to fail:

    Code:
    void CPrintWindow::OnPaint(HDC hDC, PAINTSTRUCT* pPS)
    {
      //TraceFunc("CPrintWindow::OnPaint()");  
    
      RECT rectBmUpdate;
      IntersectRect(&rectBmUpdate, &m_rectBitmap, &pPS->rcPaint);
    
      if(!IsRectEmpty(&rectBmUpdate))
      {
        BitBlt(hDC, 
               rectBmUpdate.left, 
               rectBmUpdate.top, 
               rectBmUpdate.right  - rectBmUpdate.left,
               rectBmUpdate.bottom - rectBmUpdate.top, 
               m_hMemDC, 
               rectBmUpdate.left - PAGE_BORDER, 
               rectBmUpdate.top  - PAGE_BORDER, 
               SRCCOPY);
      }
    }
    IsRectEmpty(&rectBmUpdate) is true, so the bitblt is skipped.

    Thanks,
    Kenneth

  7. #7
    Registered User
    Join Date
    Jun 2009
    Posts
    5
    Hi, I found this thread:

    how splwow64 works - Windows Device Drivers

    which says that a printer driver plugin running in the context of splwow64 (which mine is) should not call CreateDC() because it will fail. My code calls CreateCompatibleDC(), and this does indeed return null. This is probably related to the problem described in my previous post.

    Perhaps I have to use an alternative to HDCs? Is there an alternative?

    Thanks,
    Kenneth

  8. #8
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    There isn't any alternative as far as GDI is concerned, though what you can do about it I've no idea. I tend to stay away from all things printer related. Posting what GetLastError() returns after CreateCompatibleDC fails might help any other potential helpers provide a course of action.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. A few questions about 64 bit and Windows...
    By yaya in forum Tech Board
    Replies: 9
    Last Post: 08-28-2008, 08:49 AM
  2. Replies: 16
    Last Post: 11-23-2007, 01:48 PM
  3. File IO
    By Jack1982 in forum C++ Programming
    Replies: 9
    Last Post: 10-15-2007, 01:14 AM
  4. bit patterns of negtive numbers?
    By chunlee in forum C Programming
    Replies: 4
    Last Post: 11-08-2004, 08:20 AM
  5. Array of boolean
    By DMaxJ in forum C++ Programming
    Replies: 11
    Last Post: 10-25-2001, 11:45 PM