从内存中加载运行时的动画光标

时间:2012-07-31 17:34:34

标签: c++ windows winapi animation cursor

我想从内存中加载以.ani格式存储的动画光标,该格式被描述为RIFF存档/容器,而不将内存写入临时文件。到目前为止,我能够解析.ani文件结构,并借助CreateIconFromResourceEx LookupIconIdFromDirectoryEx

将各个帧加载为普通图标

证明困难的问题之一是这些帧的实际构成和动画数据(jiffy-rate等),因为在Windows API中似乎没有条目这样做。关于主题的文档或书面知识似乎仅限于从内存中加载非动画图标/光标。

类似问题,例如'Load an embedded animated Cursor from the Resource'表达了从可嵌入资源加载动画光标的愿望。但是,我也无法从中重现可行的解决方案。部分原因是因为Visual Studio 2008中的资源编译器和2010年不支持.ani(仅限ico和cur)文件,因此嵌入它只会导致原始文件中的1:1字节副本,而不是.cur和.ico文件会被分解为多个资源。随后对两个答案中显示的CreateIconFromResource的调用都不起作用,因为它所需的数据是图标存档中单个指令的图标/光标数据,而不是基于RIFF的文件结构。

总结一下,我对任何有关动画游标结构(内存中)或其他有助于我追求目标的相关指针感兴趣。

2 个答案:

答案 0 :(得分:5)

重新评估从mfc指出的可嵌入资源加载动画光标后,我找到了一个允许我从任意内存地址加载游标的解决方案。

来自可嵌入资源的数据和从文件读入内存的数据完全相同。因此,它表明CreateIconFromResource 也应在正常的常规内存上工作。然而,有一个根本区别。可嵌入资源的内存驻留在可执行文件的特殊部分中,这些部分通常填充到最近的4096字节边界。在运行时分配的内存包含垃圾值。

现在我发现的解决方案通过简单地分配一个零填充字节的保护带来利用它。在我自己的测试用例中,我发现8是最小值,也恰好是riff容器中块的大小。巧合?我怀疑这是一个错误,并且算法恰好适用于可嵌入资源,因为它在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 :(得分: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;
}