【问题标题】:Load an animated cursor at runtime from memory在运行时从内存加载动画光标
【发布时间】:2012-07-29 13:24:08
【问题描述】:

我想从内存中加载以 .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 的文件结构。

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

【问题讨论】:

    标签: c++ windows animation winapi mouse-cursor


    【解决方案1】:

    在重新评估从 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);
    }
    

    【讨论】:

      【解决方案2】:

      将您的动画光标导入为自定义资源。 给它一个文本名称,例如“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;
      }
      

      【讨论】:

      • 这是一个我确信适用于大多数人的解决方案。但是,它仍然是我真正想要的替代品。这个问题的一个基本部分是能够从任意内存中加载它。
      猜你喜欢
      • 1970-01-01
      • 2011-03-30
      • 1970-01-01
      • 1970-01-01
      • 2020-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多