CreateILockBytesOnHGlobal 函数 (coml2api.h)

CreateILockBytesOnHGlobal 函数创建一个字节数组对象,该对象使用 HGLOBAL 内存句柄来存储用于复合文件的内存中存储的字节。 此对象是 ILockBytes 接口的 OLE 提供的实现。

返回的字节数组对象支持读取和写入,但不支持区域锁定 。 对象调用 GlobalReAlloc 函数以根据需要增加内存块。

语法

HRESULT CreateILockBytesOnHGlobal(
  [in]  HGLOBAL     hGlobal,
  [in]  BOOL        fDeleteOnRelease,
  [out] LPLOCKBYTES *pplkbyt
);

参数

[in] hGlobal

由 GlobalAlloc 函数分配的内存句柄,如果为 NULL,则改为分配新句柄。 必须将句柄分配为可移动和不可存储。

[in] fDeleteOnRelease

一个标志,指定释放对象时是否应自动释放此字节数组对象的基础句柄。 如果设置为 FALSE,则调用方必须在最终发布后释放 hGlobal 。 如果设置为 TRUE,则最终版本将自动释放 hGlobal 参数。

[out] pplkbyt

接收指向新字节数组对象的接口指针的 ILockBytes 指针变量的地址。

返回值

此函数支持标准返回值 E_INVALIDARGE_OUTOFMEMORY,以及以下值:

注解

如果 hGlobalNULL则 CreateILockBytesOnHGlobal 会分配一个新的内存句柄,并且字节数组最初为空。

如果 hGlobal 不为 NULL,则字节数组对象的初始内容是内存块的当前内容。 因此,此函数可用于打开内存中的现有字节数组,例如重新加载以前由 StgCreateDocfileOnILockBytes 函数创建的存储对象。 内存句柄及其内容不受创建新字节数组对象的干扰。

字节数组的初始大小是 GlobalSize 函数返回的 hGlobal 大小。 这不一定与由于舍入而最初为句柄分配的大小相同。 如果字节数组的逻辑大小很重要,请按照调用 CreateILockBytesOnHGlobal 并调用 ILockBytes::SetSize

使用 CreateStreamOnHGlobal 创建字节数组对象后, StgCreateDocfileOnILockBytes 可用于在内存中创建新的存储对象,或者 StgOpenStorageOnILockBytes 可用于重新打开内存块中已包含的以前存在的存储对象。 可以调用 GetHGlobalFromILockBytes 来检索与字节数组对象关联的内存句柄。

如果将内存句柄传递给 CreateILockBytesOnHGlobal ,或者调用 GetHGlobalFromILockBytes ,则调用方可以直接访问此函数的内存句柄,而字节数组对象仍在使用该函数。 在使用此功能及其影响时,应适当谨慎:

  • 请勿在字节数组对象的生存期内释放 hGlobal 内存句柄。 在释放内存句柄之前,必须调用 ILockBytes::Release
  • 请勿在字节数组对象的生存期内调用 GlobalReAlloc 来更改内存句柄的大小。 这可能会导致应用程序崩溃或内存损坏。 避免在同一内存句柄上创建多个字节数组对象,因为 ILockBytes::WriteAtILockBytes::SetSize 方法可能在内部调用 GlobalReAlloc
  • 如果可能,请避免在字节数组对象的生存期内访问内存块,因为该对象可能在内部调用 GlobalReAlloc ,并且不会对其大小和位置做出假设。 如果必须访问内存块,则内存访问调用应围绕对 GlobalLockGlobalUnLock 的调用。
  • 避免在使用 GlobalLock 锁定内存句柄时调用 对象的 方法。 这可能会导致方法调用不可预测的失败。
如果调用方将 fDeleteOnRelease 参数设置为 FALSE,则调用方还必须在最终发布后释放 hGlobal 。 如果调用方将 fDeleteOnRelease 参数设置为 TRUE,则最终版本将自动释放 hGlobal。 作为 hGlobal 参数传递的内存句柄必须分配为可移动和不可显示,如以下示例所示:
HGLOBAL	hMem = ::GlobalAlloc(GMEM_MOVEABLE,iSize);
if (!hMem)
    AfxThrowMemoryException();

LPVOID pCompoundFile = ::GlobalLock(hMem);
... // Fill memory
::GlobalUnlock(hMem);

CComPtr<ILockBytes> spLockBytes;
HRESULT hr = ::CreateILockBytesOnHGlobal(hMem,FALSE,&spLockBytes);


CreateILockBytesOnHGlobal 将接受 使用 GMEM_FIXED 分配的内存,但不建议使用此用法。 使用 GMEM_FIXED 分配的 HGLOBALs 不是真正的句柄,其值在重新分配时可能会更改。 如果使用 GMEM_FIXED 分配内存句柄,并且 fDeleteOnReleaseFALSE,则调用方必须调用 GetHGlobalFromILockBytes 以获取正确的 HGLOBAL 值才能释放句柄。

ILockBytes 的此实现不支持区域锁定。 将此实现与 StgCreateDocfileOnILockBytesStgOpenStorageOnILockBytes 函数配合使用的应用程序应避免在同一 ILockBytes 对象上打开多个并发实例。

在 Windows 7 和 Windows Server 2008 R2 之前,此实现在调用 GlobalReAlloc 以增加内存块时不会为零内存。 使用 ILockBytes::SetSize 增加字节数组的大小,或者通过写入字节数组当前末尾后的位置来增加字节数组的大小,将使新分配的内存的任何未写入部分未初始化。 StgCreateDocfileOnILockBytesStgOpenStorageOnILockBytes 返回的存储对象可能会增加字节数组的大小,而无需初始化所有新分配的空间。

内存中的复合文件通常用作暂存空间或与需要存储对象的 API 一起使用,在这些情况下,未初始化的内存通常不是问题。 但是,如果将内存块的内容写入文件,请考虑以下替代方法以避免潜在的信息泄露:

  • 使用 IStorage::CopyTo 方法将内存中复合文件的逻辑内容复制到目标文件,而不是直接写入内存块的内容。
  • 通过使用 pwcsName 参数的 NULL 值调用 StgCreateStorageEx 来创建临时文件,而不是内存中的复合文件。 当需要写入目标文件时,请使用 IRootStorage::SwitchToFile 方法。
  • 实现 ILockBytes 接口,使内存重新分配归零 (例如 HeapReAlloc) 中的HEAP_ZERO_MEMORY标志。 然后,可以将此字节数组的内存内容写入文件。

要求

要求
最低受支持的客户端 Windows 2000 专业版 [桌面应用 |UWP 应用]
最低受支持的服务器 Windows 2000 Server [桌面应用 |UWP 应用]
目标平台 Windows
标头 coml2api.h (包括 Ole2.h)
Library Ole32.lib
DLL Ole32.dll

另请参阅

GetHGlobalFromILockBytes

ILockBytes

StgOpenStorageOnILockBytes