2014-05-15 2 views
4

여기에 기괴한 문제가 있습니다. 계층화 된 창을 사용하여 반투명 스플래시 화면 (.png 파일)을 표시합니다. 일부 컴퓨터에서는 작동하지만 다른 컴퓨터에서는 작동하지 않습니다. 작동하지 않는 컴퓨터에서 GetLastError는 317을 반환합니다 (별로 도움이되지 않습니다). 이전에 경험 한 사람이 있습니까? 다음은 관련 기능입니다. CreateAsPNG에 대한 들어오는 매개 변수는 WS_VISIBLE | WS_POPUP (dwStyle), 0 (dwExStyle) 및 부모에 대한 숨겨진 도구 창의 핸들이므로 작업 표시 줄 항목이 만들어지지 않습니다. 임베디드 PNG 리소스를 CImage에로드 할 수 있고 이미지의 크기가 올바른지 확인했습니다.Win32 : UpdateLayeredWindow가 때때로 실패합니다 (오류 317)

미리 도움을 청하십시오!

BOOL MySplashWnd::CreateAsPNG(DWORD dwStyle, DWORD dwExStyle, const CString& sTitle, HWND hWndParent) 
{ 
    ATL::CImage img; 
    CreateStreamOnResource(m_nBitmapID, img); 

    m_nWndWidth = img.GetWidth(); 
    m_nWndHeight = img.GetHeight(); 

    int nTop = 0; 
    int nLeft = 0; 
    GetTopLeft(nTop, nLeft); 

    dwExStyle |= WS_EX_LAYERED; 

    // Create the Splash Window 
    BOOL bRetVal = CWnd::CreateEx(dwExStyle, AfxRegisterWndClass(CS_CLASSDC), sTitle, 
            dwStyle, nLeft, nTop, m_nWndWidth, m_nWndHeight, hWndParent, NULL); 

    //Couldn't create the window for some unknown reason... 
    X_ASSERT(bRetVal != FALSE); 

    if (bRetVal) 
    { 
     HDC hScreenDC = ::GetDC(m_hWnd); 
     HDC hDC = ::CreateCompatibleDC(hScreenDC); 
     HBITMAP hBmp = ::CreateCompatibleBitmap(hScreenDC, m_nWndWidth, m_nWndHeight); 
     HBITMAP hBmpOld = (HBITMAP) ::SelectObject(hDC, hBmp); 

     img.Draw(hDC, 0, 0, m_nWndWidth, m_nWndHeight, 0, 0, m_nWndWidth, m_nWndHeight); 

     BLENDFUNCTION blend = { 0 }; 
     blend.BlendOp = AC_SRC_OVER; 
     blend.BlendFlags = 0; 
     blend.SourceConstantAlpha = 255; 
     blend.AlphaFormat = AC_SRC_ALPHA; 

     POINT ptPos = { nLeft, nTop }; 
     SIZE sizeWnd = { m_nWndWidth, m_nWndHeight }; 
     POINT ptSource = { 0, 0 }; 

     if (::UpdateLayeredWindow(m_hWnd, hScreenDC, &ptPos, &sizeWnd, hDC, &ptSource, 0, &blend, ULW_ALPHA)) 
     { 
     } 
     else 
     { 
      // The last error value is 317 on some Win7 machines. 
      TRACE(_T("*** Last error: %d\n"), ::GetLastError()); 
     } 

     ::SelectObject(hDC, hBmpOld); 
     ::DeleteObject(hBmp); 
     ::DeleteDC(hDC); 
     ::ReleaseDC(NULL, hScreenDC); 
    } 

    return bRetVal; 
} 

void MySplashWnd::CreateStreamOnResource(UINT nIDRes, ATL::CImage& img) 
{ 
    HINSTANCE hInstance = ::GetMUIResourceInstance(); 
    if (hInstance == NULL) 
    { 
     return; 
    } 

    HRSRC hResource = ::FindResource(hInstance, MAKEINTRESOURCE(nIDRes), "PNG"); 
    if (hResource == NULL) 
    { 
     return; 
    } 

    DWORD dwResourceSize = ::SizeofResource(hInstance, hResource); 
    if (dwResourceSize == 0) 
    { 
     return; 
    } 

    HGLOBAL hImage = ::LoadResource(hInstance, hResource); 
    if (hImage == NULL) 
    { 
     return; 
    } 

    LPVOID pvImageResourceData = ::LockResource(hImage); 
    if (pvImageResourceData == nullptr) 
    { 
     return; 
    } 

    HGLOBAL hImageData = ::GlobalAlloc(GMEM_MOVEABLE, dwResourceSize); 
    if (hImageData == NULL) 
    { 
     return; 
    } 

    LPVOID pvImageBuffer = ::GlobalLock(hImageData); 
    if (pvImageBuffer != nullptr) 
    { 
     ::CopyMemory(pvImageBuffer, pvImageResourceData, dwResourceSize); 
     ::GlobalUnlock(hImageData); 

     IStream* pStream = nullptr; 

     if (SUCCEEDED(::CreateStreamOnHGlobal(hImageData, TRUE, &pStream))) 
     { 
      img.Load(pStream); 
      pStream->Release(); 
     } 

     ::GlobalUnlock(hImageData); 
    } 

    ::GlobalFree(hImageData); 
} // CTTSplashWnd::CreateStreamOnResource 

UPDATE : 심지어 동일한 시스템에, 때로는 UpdateLayeredWindow이 성공 것을 내가 찾은 다른 시간이 실패 (그러나 항상 코드 (317)와 함께이 실패하는 경우). 또 다른 정보는이 스플래시가 별도의 UI 스레드에서 실행되고 있다는 것입니다. 그것은 항상 내 컴퓨터에서 작동하지만 ...

답변

2

나는이 같은 문제가있어서 어떤 정보도 찾을 수 없다. 대신 SetWindowAttributes 메서드를 사용하여 작동하지만 SetLayeredWindow 방법을 사용하려고합니다. MSdn이이 오류 메시지에 대한 잭 정보를 제공 한 이래 무엇이 일어나고 있는지 알아보기 위해 전체 Windows API를 통해 디버깅 할 시점까지갑니다. 유일한 차이점은 내 컴퓨터에서 작동하는 CreateCompatibleBitmap 대신 CreateDIBSection을 사용하는이 메서드를 사용하는 OpenGL 계층화 된 창 데모 예제입니다.

+0

그래, 나는 그것을 알아낼 수 없었다. UpdateLayeredWindow 호출로 실패를 감지하면 PNG 대신 비트 맵을 표시합니다. 그래도 고마워, 크리스. – Steve

1

UpdateLayeredWindow()는 Windows 7 x86_64 컴퓨터에서 완벽하게 작동합니다. 데스크톱 구성을 사용하지 않도록 설정 한 경우에만 실패합니다. 그것은

UpdateLayeredWindow (window_handle, NULL, 
        &position, &size, 
        buffer_hdc, &buffer_offset, 
        0, &blend_options, ULW_ALPHA); 

작품,

UpdateLayeredWindow (window_handle, NULL, 
        &position, NULL, 
        buffer_hdc, &buffer_offset, 
        0, &blend_options, ULW_ALPHA); 

동안 작동하지 않는 것으로 밝혀졌다 나는 내가하지 않았기 때문에 인수의 일부를 건너 뛰려고 노력했습니다 (317)

오류와 함께 실패 창 크기 또는 내용을 이동해야합니다. 데스크톱 구성이 비활성화되어 있으면이 작업은 불가능한 것으로 판명되었습니다.

원래의 문제와 어떻게 관련이 있는지 잘 모르겠지만 DC를 제공하는 경우에는 그렇지 않습니다.

관련 문제