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






4.10/5 (3投票s)
使用 LoadResource 从 DLL 加载 JPEG 图像(托管 C++)
引言
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
) 是必须找到的资源的句柄。此句柄对应于函数 FindResource
或 FindResourceEx
的返回值(参见 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 个步骤
- 我们必须创建一个字节的
cli::array
- 我们必须将
LockResource
函数返回的指针从LPVOID
转换为char *
(LockResource
指针return
s 资源的第一个字节) - 我们必须使用
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);