65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 LoadResource 从 DLL 加载 JPEG 图像(托管 C++)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.10/5 (3投票s)

2007 年 3 月 13 日

CPOL

2分钟阅读

viewsIcon

65783

downloadIcon

1698

使用 LoadResource 从 DLL 加载 JPEG 图像(托管 C++)

Screenshot - screenshot.png

引言

LoadResource 函数将指定的资源加载到全局内存 (HGLOBAL) 区域。它的原型是

HGLOBAL LoadResource(HMODULE hmodule, HRSRC hResInfo) 
                        //See MSDN for more information. 

第一个参数 (hmodule) 是一个包含资源的执行模块(DLL,EXE)。如果此参数为 NULL,则假定需要在当前进程中找到该资源。当指定参数 (EXE/DLL 模块) 时,必须使用 LoadLibrary API 加载它。

HINSTANCE module = LoadLibrary(module_name); 
第二个参数 (hResInfo) 是必须找到的资源的句柄。此句柄对应于函数 FindResourceFindResourceEx 的返回值(参见 MSDN)。如果找到了所需的资源,FindResource 的返回值就是该资源的位置。
// code .....
HRSRC rsrc = FindResource(module, MAKEINTRESOURCE(resource_ID), RT_RCDATA); 

我们必须获取资源的总大小以供后续使用

//code...
DWORD Size = SizeofResource(module, rsrc);

现在我们可以加载指定的资源了

//code...
HGLOBAL MemoryHandle = LoadResource(module, rsrc);

到此为止,如果已找到并加载了指定的资源,则需要将其锁定在内存中以获取指向该资源第一个字节的指针。指针是从对 LockResource 的调用中返回的。如果资源已锁定在内存中,则 LockResource API 的 return 值是指向资源第一个字节的指针 (LPVOID),否则 LockResource 返回 NULL。到目前为止,问题是该资源已加载到全局内存区域 (HGLOBAL) 中,在 C++/CLI 中,我们无法直接访问由 Win32 API 分配的内存。解决方案分 3 个步骤

  1. 我们必须创建一个字节的 cli::array
  2. 我们必须将 LockResource 函数返回的指针从 LPVOID 转换为 char * (LockResource 指针 returns 资源的第一个字节)
  3. 我们必须使用 Marshal::Copy 方法将 char 数组(由 char * 指针指向,换句话说,非托管内存指针)复制到 cli:array(托管数组)中

//code...
cli::array ^MemPtr = gcnew Array (Size + 2);
char * lkr = (char *)(LockResource(MemoryHandle));
Marshal::Copy((IntPtr)lkr, MemPtr, 0, Size);

因此,必须在内存中创建一个流 (MemoryStream),该流必须足够大以分配内存来包含所有 cli::array。因此,我们必须在流 (MemoryStream) 中写入 cli::array 的内容,从位置 0 开始

//code...
System::IO::MemoryStream ^stream = gcnew System::IO::MemoryStream(MemPtr);
stream->Write(MemPtr, 0, Size);

写入结束后,MemoryStream 指针位于最后一个字节。因此,为了进行正确的赋值,我们必须将流的位置移回至位置 0

//code...
stream->Position = 0;

现在我们可以释放已分配的资源

//code...
FreeLibrary(module);

我们必须创建一个指向抽象类托管 C++ Image 的指针

System::Drawing::Image ^ptrJpg;
ptrJpg = System::Drawing::Image::FromStream(stream);

完整的函数

public: Image ^ getImageFromRes(long resource_ID,LPCWSTR module_name)
{
// Function getImageFromRes
// A function for loading jpeg images from resources in C++/CLI
// Copyright (C) Giuseppe Pischedda 2007

//Load the resource module:
    HINSTANCE module = LoadLibrary(module_name);
    if(module == NULL)
    {
        return nullptr;
    }

// Find the resource using the resource ID from file "resource.rh"
    HRSRC rsrc = FindResource(module, MAKEINTRESOURCE(resource_ID),RT_RCDATA);
    if(!rsrc)
    {
        return nullptr;
    }

// Load the resource and save the total size.
   DWORD Size = SizeofResource(module , rsrc);
   HGLOBAL MemoryHandle = LoadResource(module,rsrc);
   if(MemoryHandle == NULL)
   {
       return nullptr;
   }

//Create a cli::array of byte with size = total size + 2
    cli::array<BYTE> ^MemPtr = gcnew array<BYTE>(Size + 2);

//Cast from LPVOID to char *
    char *lkr = (char *)(LockResource(MemoryHandle));

//Copy from unmanaged memory to managed array
    Marshal::Copy((IntPtr)lkr,MemPtr, 0, Size);

// Create a new MemoryStream with size = MemPtr
    System::IO::MemoryStream ^stream = gcnew System::IO::MemoryStream(MemPtr);

//Write in the MemoryStream
    stream->Write(MemPtr,0,Size);

//Set the position for read the stream
    stream->Position = 0;

//Free allocated resources
    FreeLibrary(module);

//Create an Image abstract class pointer
    System::Drawing::Image ^ptrJpg;

//Assign the stream to abstract class pointer
    ptrJpg = System::Drawing::Image::FromStream(stream);
    return  ptrJpg;
}

用法

//In an event handler (a button_click for example):
System::Drawing::Image ^jpeg;

jpeg = getImageFromRes(RESOURCE_ID,L"myResources.dll");

if(jpeg != nullptr)
{
    pictureBox1->Image = jpeg;
}
else
    MessageBox::Show("Sorry... Image cannot be loaded...","Not found",
                    MessageBoxButtons::OK, MessageBoxIcon::Warning);
© . All rights reserved.