9

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

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

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

总而言之,我对有关动画光标(在内存中)的结构或其他相关指针的任何信息感兴趣,这些信息可以帮助我实现我的目标。

4

2 回答 2

7

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

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

现在,我发现可行的解决方案通过简单地分配零填充字节的保护带来利用这一点。在我自己的测试用例中,我发现 8 是最小值,它也恰好是 riff 容器中块的大小。巧合?我怀疑这是一个错误,由于它在 dll/可执行文件中的对齐限制,该算法恰好适用于可嵌入资源。

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);
}
于 2012-08-01T00:28:01.493 回答
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;
}
于 2012-07-31T21:32:15.223 回答