2012-07-31 157 views
7

我想從內存中加載以.ani格式存儲的動畫光標,該格式被描述爲RIFF存檔/容器,無需將內存寫入臨時文件。到目前爲止我能夠解析.ANI文件結構,並用CreateIconFromResourceExLookupIconIdFromDirectoryEx在運行時從內存加載動畫光標

之一即樣張困難是這些幀和動畫數據的實際組合物中的問題的輔助加載各個幀作爲正常圖標( jiffy-rate等),因爲在Windows API中似乎沒有條目可以這樣做。關於主題的文檔或書面知識似乎僅限於從內存中加載非動畫圖標/光標。

類似的問題,如'Load an embedded animated Cursor from the Resource'表示希望從可嵌入的資源加載動畫光標。但是,我無法從中重現可行的解決方案。部分原因在於2010年的Visual Studio 2008中的資源編譯器不支持.ani(僅ico和cur)文件,因此嵌入它只會導致1:1字節副本與原始文件中的字節相反。 cur和.ico文件,它們被分解爲多個資源。隨後對兩個答案中顯示的CreateIconFromResource的調用不起作用,因爲它期望的數據是圖標存檔中單個指令的圖標/光標數據,而不是基於RIFF的文件結構。

總結我對任何有關動畫遊標結構(內存)或其他相關指針的信息感興趣,這些指針可以幫助我實現我的目標。

回答

5

重新評估從嵌入的資源加載動畫光標通過MFC指出,我已經找到了解決方案,使我從一個任意的存儲器地址加載光標後。

來自嵌入式資源的數據和從文件讀入內存的數據完全相同。因此,它表明CreateIconFromResource 以及正常的常規內存。但是有一個根本的區別。可嵌入資源的內存駐留在可執行文件中的特殊部分,通常填充到最近的4096字節邊界。運行時分配的內存包含垃圾值。

現在我發現的解決方案通過簡單地分配一個零填充字節的保護帶來利用這一點。在我自己的測試案例中,我發現8是最小值,也是碰巧容器中塊的大小。巧合?我懷疑這是一個錯誤,並且該算法恰好適用於可嵌入資源,因爲它在dll/executable中是對齊限制的。

const int guardbandSize = 8; 
FILE* fs = fopen("action.ani", "rb"); 
fseek(fs, 0,SEEK_END); int dwSize = ftell(fs); fseek(fs, 0,SEEK_SET); 
char* memory = new char[dwSize + guardbandSize]; 
fread(memory, 1, dwSize, fs); memset(memory + dwSize, 0, guardbandSize); 
fclose(fs); 
cursor = (HCURSOR)CreateIconFromResource((PBYTE)memory,dwSize,FALSE,0x00030000);   
delete memory; 

下面是加載動畫光標的各種方法的概述。

#include <Windows.h> 
#include <stdio.h> 
#include "resource2.h" 

void* hWnd; 
bool visible = true; 
bool running = true; 
LRESULT CALLBACK WndProcInternal( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) ; 
HCURSOR cursor = 0; 

void main() 
{ 
    //Setup configuration 
    const int Width = 640, Height = 480; 
    const int Method = 4; 

    //Setup window class 
    WNDCLASS wcd; 
    wcd.style   = CS_PARENTDC | CS_HREDRAW | CS_VREDRAW | CS_OWNDC; 
    wcd.lpfnWndProc  = (WNDPROC)WndProcInternal;   
    wcd.cbClsExtra  = 0;         
    wcd.cbWndExtra  = 0;         
    wcd.hInstance  = GetModuleHandle(NULL);    
    wcd.hIcon   = LoadIcon(NULL, IDI_WINLOGO);  
    wcd.hCursor   = LoadCursor(NULL, IDC_ARROW);  
    wcd.hbrBackground = (HBRUSH)COLOR_BACKGROUND;        
    wcd.lpszMenuName = NULL;        
    wcd.lpszClassName = TEXT("AnimatedIcon");    

    //Register the window class 
    if(!RegisterClass(&wcd)) 
    { 
     MessageBox(NULL, TEXT("Window Registration Failed!"), TEXT("Error!"),MB_ICONEXCLAMATION | MB_OK); 
     FatalExit(-1); 
    } 

    //Create a window 
    if (!(hWnd=CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("AnimatedIcon"), TEXT("AnimatedIcon"), 
     WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_SYSMENU, 
     0, 0, Width, Height, NULL, NULL, NULL, NULL)))       
    { 
     MessageBoxA(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION); 
     FatalExit(-1); 
    } 

    if(Method == 1) 
    { 
     //Method 1: Load cursor directly from a file 
     cursor = LoadCursorFromFileA("action.ani"); 
    } 
    if(Method == 2) 
    { 
     //Method 2: Load cursor from an resource section in the executable. 
     cursor = LoadCursor(0, MAKEINTRESOURCE(IDR_ANICURSORS1)); 
    } 
    if(Method == 3) 
    { 
     //Method 3: Manually locate the resource section in the executable & create the cursor from the memory. 
     HINSTANCE hInst=GetModuleHandle(0); 
     HRSRC hRes=FindResourceA(hInst,MAKEINTRESOURCEA(IDR_ANICURSORS1),"ANICURSORS"); 
     DWORD dwSize=SizeofResource(hInst,hRes); 
     HGLOBAL hGlob=LoadResource(hInst,hRes); 
     LPBYTE pBytes=(LPBYTE)LockResource(hGlob); 
     cursor = (HCURSOR)CreateIconFromResource(pBytes,dwSize,FALSE,0x00030000); 
    } 
    if(Method == 4) 
    { 
     //Method 4: Load the cursor from a file into memory & create the cursor from the memory. 
     const int guardbandSize = 8; 
     FILE* fs = fopen("action.ani", "rb"); 
     fseek(fs, 0,SEEK_END); int dwSize = ftell(fs); fseek(fs, 0,SEEK_SET); 
     char* memory = new char[dwSize + guardbandSize]; 
     fread(memory, 1, dwSize, fs); memset(memory + dwSize, 0, guardbandSize); 
     fclose(fs); 
     cursor = (HCURSOR)CreateIconFromResource((PBYTE)memory,dwSize,FALSE,0x00030000);   
     delete memory; 
    } 

    //Set the cursor for the window and display it. 
    SetClassLong((HWND)hWnd, GCL_HCURSOR, (LONG)cursor);   
    while (running)  
    { 
     MSG wmsg; 
     if (PeekMessage(&wmsg, (HWND)hWnd, 0, 0, PM_REMOVE)) 
     { 
      TranslateMessage(&wmsg); 
      DispatchMessage(&wmsg); 
     }   
    } 
} 

LRESULT CALLBACK WndProcInternal( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    if(uMsg == WM_DESTROY) 
    { 
     PostQuitMessage(1); 
     running = false; 
    } 

    return (long)DefWindowProc((HWND)hWnd,uMsg,(WPARAM)wParam,(LPARAM)lParam); 
} 
1

將您的動畫光標導入爲自定義資源。 給它一個文本名稱,例如「MyType」。 然後加載光標:

HCURSOR hCursor = LoadAnimatedCursor(IDR_MYTYPE1, _T("MyType")); 

/* ======================================================== */ 
HCURSOR LoadAnimatedCursor(UINT nID, LPCTSTR pszResouceType) 
{ 
    HCURSOR hCursor = NULL; 
    HINSTANCE hInstance = AfxGetInstanceHandle(); 
    if (hInstance) 
    { HRSRC hResource = FindResource(hInstance, MAKEINTRESOURCE(nID), pszResouceType); 
     DWORD dwResourceSize = SizeofResource(hInstance, hResource); 
     if (dwResourceSize>0) 
     { HGLOBAL hRsrcGlobal = LoadResource(hInstance, hResource); 
      if (hRsrcGlobal) 
      { LPBYTE pResource = (LPBYTE)LockResource(hRsrcGlobal); 
       if (pResource) 
       { hCursor = (HCURSOR)CreateIconFromResource(pResource, dwResourceSize, FALSE, 0x00030000); 
        UnlockResource(pResource); 
       } 
       FreeResource(hRsrcGlobal); 
      } 
     } 
    } 
    return hCursor; 
} 
+0

這是一個解決方案,我相信對大多數人都有效。但它仍然是我真正想要的選擇。這個問題的基本部分是從任意內存加載它的能力。 – 2012-07-31 22:06:00