BITMAP图片无法从文件“INVALID HANDLE”加载

时间:2015-05-29 01:18:39

标签: winapi bitmap

这是基本的,因此只需要一个来自绘图功能的代码片段,因为它具有必要的信息

void draw()
{

RECT rect;
GetClientRect(hwnd, &rect);
    HBITMAP FRAME1ANIMDASH = NULL;
            FRAME1ANIMDASH = (HBITMAP) LoadImage(NULL, "Hidden but correct pathname that won't be shown here", 0, LR_DEFAULTSIZE, LR_DEFAULTSIZE, LR_CREATEDIBSECTION);
            if(FRAME1ANIMDASH == NULL)
            {
                MessageBox(NULL, "CANNOT LOAD", "CANNOT LOAD", MB_OK);
            }
            HDC device;
            PAINTSTRUCT ps;
            BITMAP bm;
    GetObject(FRAME1ANIMDASH,sizeof(BITMAP),&bm);
    HDC hdcdevice=CreateCompatibleDC(device);
    SelectObject(hdcdevice,FRAME1ANIMDASH);
    BitBlt(device,0,0,0,0,hdcdevice,0,0,SRCCOPY);
    UpdateWindow(hwnd);
    device=GetDC(hwnd);
    DeleteDC(hdcdevice);
    DeleteObject((HBITMAP) FRAME1ANIMDASH);
        DWORD lastError = GetLastError();
        cout << GetLastError();
    }

获取上一个错误显示错误6,这是一个无效的文件句柄。消息框显示,这意味着图像从未加载和失败,所以其后的代码不是主要关注点。

我正在尝试加载位图并将其放在我创建的Win32窗口上。

不需要其他代码,因为没有任何其他代码可以导致整体可能的答案。告诉我如何才能成功加载图像。

1 个答案:

答案 0 :(得分:5)

你打电话给GetLastError()太晚了。此时错误代码毫无意义,因为它可能会被您调用的任何其他函数覆盖。在GetLastError()失败后,您必须立即致电LoadImage()

HBITMAP FRAME1ANIMDASH = (HBITMAP) LoadImage(...);
if (FRAME1ANIMDASH == NULL)
{
    DWORD lastError = GetLastError();
    cout << "CANNOT LOAD IMAGE, ERROR " << lastError;
    MessageBox(NULL, "CANNOT LOAD IMAGE", "CANNOT LOAD IMAGE", MB_OK);
    return; // <-- add this, too!
}

LoadImage()失败的原因是因为您未按照LoadImage() documentation指定LR_LOADFROMFILE标记,而没有正确请求图像大小:

  

lpszName [in]
  ...
  如果hinst参数为NULL并且fuLoad参数省略了LR_LOADFROMFILE值,则lpszName指定要加载的OEM映像。 OEM映像标识符在Winuser.h中定义并具有以下前缀。
  ...
  如果fuLoad参数包含LR_LOADFROMFILE值,则lpszName是包含独立资源(图标,光标或位图文件)的文件名。因此,将hinst设置为NULL。

     

...

     

cxDesired [in]
  ...
  ... 如果此参数为零且未使用LR_DEFAULTSIZE,则该函数使用实际资源宽度。

     

...

     

cyDesired [in]
  ...
  ... 如果此参数为零且未使用LR_DEFAULTSIZE,则该函数使用实际资源高度。

     

...

     

fuLoad [in]
  ...
  LR_DEFAULTSIZE
  ... 如果未指定此标志且cxDesired和cyDesired设置为零,则该函数使用实际资源大小。
  ......   LR_LOADFROMFILE
  ...从lpszName 指定的文件(图标,光标或位图文件)加载独立图像。

所以看起来应该更像这样:

HBITMAP FRAME1ANIMDASH = (HBITMAP) LoadImage(NULL, "pathname", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);

修复后,代码还有其他问题。

您正在使用未初始化的 CreateCompatibleDC()变量来调用HDC,而不是检查CreateCompatibleDC()的失败结果。您对GetDC()的来电位置错误,需要将其移至CreateCompatibleDC()以上。而且,如果您HDC返回GetDC(),则需要致电ReleaseDC()以释放它。

您还告诉BitBlt()复制一个0x0的像素矩形,而不是使用BITMAP结构中的位图的真实尺寸,甚至是您使用的RECT窗口从GetClientRect()检索。

尝试更像这样的东西:

void draw()
{
    HBITMAP FRAME1ANIMDASH = (HBITMAP) LoadImage(NULL, "pathname", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
    if (FRAME1ANIMDASH == NULL)
    {
        DWORD lastError = GetLastError();
        cout << "CANNOT LOAD IMAGE, ERROR " << lastError;
        MessageBox(NULL, "CANNOT LOAD IMAGE", "CANNOT LOAD IMAGE", MB_OK);
        return;
    }

    HDC hdcWnd = GetDC(hwnd);
    if (hdcWnd === NULL)
    {
        DeleteObject(FRAME1ANIMDASH);
        cout << "CANNOT GET WINDOW DC";
        MessageBox(NULL, "CANNOT GET WINDOW DC", "CANNOT GET DC", MB_OK);
        return;
    }

    HDC hdcMem = CreateCompatibleDC(hdcWnd);
    if (hdcMem == NULL)
    {
        ReleaseDC(hwnd, hdcWnd);
        DeleteObject(FRAME1ANIMDASH);
        cout << "CANNOT CREATE COMPATIBLE DC";
        MessageBox(NULL, "CANNOT CREATE COMPATIBLE DC", "CANNOT CREATE DC", MB_OK);
        return;
    }

    BITMAP bm;
    GetObject(FRAME1ANIMDASH, sizeof(BITMAP), &bm);

    HBITMAP oldBm = (HBITMAP) SelectObject(hdcMem, FRAME1ANIMDASH);
    BitBlt(hdcWnd, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
    SelectObject(hdcMem, oldBm);

    DeleteDC(hdcMem);
    ReleaseDC(hwnd, hdcWnd);
    DeleteObject(FRAME1ANIMDASH);

    UpdateWindow(hwnd);
}

话虽如此,PAINTSTRUCT变量意味着您的代码正在WM_PAINT消息处理程序中使用。如果确实如此,您应该使用BeginPaint()代替GetDC()来获取目标HDC

case WM_PAINT:
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);
    draw(hdc);
    EndPaint(hwnd, &ps);
    break;
};

void draw(HDC hdcTarget)
{
    HBITMAP FRAME1ANIMDASH = (HBITMAP) LoadImage(NULL, "pathname", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
    if (FRAME1ANIMDASH == NULL)
    {
        DWORD lastError = GetLastError();
        cout << "CANNOT LOAD IMAGE, ERROR " << lastError;
        // DO NOT use MessageBox() in a WM_PAINT handler,
        // You will trigger an endless re-paint loop!
        return;
    }

    HDC hdcMem = CreateCompatibleDC(hdcTarget);
    if (hdcMem == NULL)
    {
        DeleteObject(FRAME1ANIMDASH);
        cout << "CANNOT CREATE COMPATIBLE DC";
        return;
    }

    BITMAP bm;
    GetObject(FRAME1ANIMDASH, sizeof(BITMAP), &bm);

    HBITMAP oldBm = (HBITMAP) SelectObject(hdcMem, FRAME1ANIMDASH);
    BitBlt(hdcWnd, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
    SelectObject(hdcMem, oldBm);

    DeleteDC(hdcMem);
    DeleteObject(FRAME1ANIMDASH);
}

否则,如果您使用WM_PAINT之外的代码,则代码几乎无用,因为UpdateWindow()将触发重绘以消除您的绘图。必须使用WM_PAINT完成窗口上的持久性绘图(除非您使用UpdateLayeredWindow()并使用WS_EX_LAYERED窗口。)