已分配一块内存,得到这块内存的首地址,和这块内存的大小.怎么创建一个IStream类型呀?????
即: char * buf = new char[len];
再如何将这块内存变为IStream呢?有这样的问题主要是因为在使用GDI+时.创建Image时使用的函数Image::FromStream(IStream *, BOOL);是IStream接口的.
可我已经分配了一块内存,不想再用 GlobalAlloc(); 加 CreateStreamOnHGlobal(); 多分配内存了.
即: char * buf = new char[len];
再如何将这块内存变为IStream呢?有这样的问题主要是因为在使用GDI+时.创建Image时使用的函数Image::FromStream(IStream *, BOOL);是IStream接口的.
可我已经分配了一块内存,不想再用 GlobalAlloc(); 加 CreateStreamOnHGlobal(); 多分配内存了.
解决方案 »
- QT好的学习资料
- 关于HTTP格式的问题 高分
- 我要做一个解压缩的程序,点击菜单栏中的解压缩按钮,弹出压缩对话框,选择压缩的.zip文件,浏览文件夹,选择压缩后存放的路径.解压缩过程调用静态链接库.望大侠们帮忙
- 在两个视图中怎么实现按F5切换视图的消息映射。(F5为刷新键)
- 急问 :怎么使用在线msdn,在哪里,比如想查某些函数的用法,是不是跟安装的内容一样?(解决给分100)
- 请教高手:能否修改.exe文件以增加菜单并且点击该菜单可以弹出新的窗口?
- 如何改变disabled的edit框的字体颜色?
- 整体转让彩票软件源码(含知识产权,配套服务网站),开发平台vc6. 内详.
- 请问怎么监控WIN32 API,是用HOOK吗?
- 想问几个SOCKET封包传输的问题
- 能否用sql语句直接操作文本文件
- 调色板动画(Palette animation)问题
CreateStreamOnHGlobal
函数进行创建。。
譬如:IStream* ps;
CreateStreamOnHGlobal((HGLOBAL)buf,FALSE,&ps);以上,没有经过测试,不过LZ可以试一下
new是c++的标准函数,在windows的vc++编译器中,new在申请内存最终调用的是GlabalAllock
所以,有上面的猜测LZ可以一试
待高手确认!!
查了一下网上的资料.
HGLOBAL是内存句柄,可能是指针的指针,并不是内存的首地址.强制转换可能没有意义.
没有什么好方法,一般来说,都是重新创建一个,然后拷贝过去。
不过直接使用原来的内存也不是绝对不行,因为IStream是一个接口类,它的所有成员函数都是虚函数,我们可以自己继承一个IStream,然后实现它的所有成员函数,这样就可以利用已经存在的内存了。不过这绝对是一件体力活,因为比较懒,想捡现成的,不过就是没找到,后来还是直接用GlobalAlloc+CreateStreamOnHGlobal。
如果LZ自己有兴趣实现一个,并且成功了,希望可以分享一下……
如下:HGLOBAL temp = GlobalHandle(buf);
CreateStreamOnHGlobal(temp,FALSE,&ps);我查到 GlobalHandle API可以转成 HGLOBAL
我也不理解,同样是指针,为什么它的参数必须是由 LPVOID GlobalLock(HGLOBAL hMem); 得到的指针才行.
看来内存句柄HGLOBAL在操作系统内部是有特殊管理的.
很郁闷,为什么从内存句柄 HGLOBAL 可以得到指针, 从指针却好像不能得到内存句柄, 可能操作系统不希望用户直接使用指针.
五楼说到的继承一个IStream可以实现直接使用原来的内存,好像可行,期待高手.
/**
* \brief 描述: 读到IStream中.
*/
IStream *pStm;
CFileStatus fstatus;
CFile file;
LONG cb;
if (file.Open(m_Path,CFile::modeRead)&&file.GetStatus(m_Path,fstatus)&&((cb = fstatus.m_size) != -1))
{
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, cb);
LPVOID pvData = NULL;
if (hGlobal != NULL)
{
if ((pvData = GlobalLock(hGlobal)) != NULL)
{
file.Read(pvData,cb);
GlobalUnlock(hGlobal);
CreateStreamOnHGlobal(hGlobal, TRUE, &pStm);
}
}
}
我的意思是不使用 CreateStreamOnHGlobal() 如何创建一个IStream
因为在我的应用中,已经用 new 分配了一块内存了, 想就用这块内存创建 IStream , 不想 GlobalAlloc() 分配新的内存.
注意,我只跟踪调试过Image::FromStream,把它会调用到的几个虚函数实现了一下,这对于Image::FromStream应该已经够用了,但是如果LZ要实现Image::Save,那么LZ你自己把Write等几个其他相关的虚函数也实现好了,我这里只是抛砖引玉一下。
另外,Seek和Read我没有做多线程互斥,而实际上应该是要互斥的,反正Image::FromStream用不到,我也偷懒了。#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <gdiplus.h>#pragma comment(lib, "gdiplus.lib")class IStreamEx : public IStream
{
protected:
IStreamEx(LPVOID lpData, ULARGE_INTEGER uSize, BOOL bDeleteOnRelease)
: m_uCount(1)
, m_lpData(lpData)
, m_uSize(uSize)
, m_bDeleteOnRelease(bDeleteOnRelease)
{
m_uCurrent.QuadPart = 0;
}
~IStreamEx()
{
if ((m_bDeleteOnRelease) && (m_lpData))
free(m_lpData);
};
IStreamEx(const IStreamEx&) {};
IStreamEx& operator=(const IStreamEx&)
{
return (*this);
}
public:
static IStreamEx* CreateIStream(LPVOID lpData, DWORD dwSize, BOOL bDeleteOnRelease = FALSE)
{
ULARGE_INTEGER uSize = {dwSize, 0};
return new IStreamEx(lpData, uSize, bDeleteOnRelease);
}
public:
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
{
return E_NOINTERFACE;
}
virtual ULONG STDMETHODCALLTYPE AddRef()
{
return InterlockedIncrement((LONG*)&m_uCount);
}
virtual ULONG STDMETHODCALLTYPE Release()
{
ULONG ret = InterlockedDecrement((LONG*)&m_uCount);
if (ret == 0)
delete this;
return ret;
}
virtual HRESULT STDMETHODCALLTYPE Read(void *pv, ULONG cb, ULONG *pcbRead)
{
ULONG cbr = (ULONG)(m_uSize.QuadPart - m_uCurrent.QuadPart);
if (cbr > cb) cbr = cb;
memcpy(pv, ((UCHAR*)m_lpData) + m_uCurrent.LowPart, cbr);
m_uCurrent.QuadPart += cbr;
if (pcbRead)
*pcbRead = cbr;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE Write(const void *pv, ULONG cb, ULONG *pcbWritten)
{
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
{
HRESULT ret = S_OK;
LONGLONG lOffset = 0;
switch (dwOrigin)
{
case STREAM_SEEK_SET:
lOffset = dlibMove.QuadPart;
break;
case STREAM_SEEK_CUR:
lOffset = dlibMove.QuadPart + m_uCurrent.QuadPart;
break;
case STREAM_SEEK_END:
lOffset = dlibMove.QuadPart + m_uSize.QuadPart;
break;
default:
ret = STG_E_INVALIDFUNCTION;
break;
}
if (ret == S_OK)
{
if (lOffset < 0LL)
lOffset = 0LL;
if ((ULONGLONG)lOffset > m_uSize.QuadPart)
lOffset = m_uSize.QuadPart;
m_uCurrent.QuadPart = lOffset;
if (plibNewPosition)
plibNewPosition->QuadPart = lOffset;
}
return ret;
}
virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize)
{
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE CopyTo(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
{
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags)
{
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE Revert(void)
{
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
{
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
{
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG *pstatstg, DWORD grfStatFlag)
{
HRESULT ret = S_OK;
if ((grfStatFlag != STATFLAG_NONAME) && (grfStatFlag != STATFLAG_DEFAULT))
{
ret = STG_E_INVALIDFLAG;
}
else if (pstatstg == NULL)
{
ret = STG_E_INVALIDPOINTER;
}
else
{
memset(pstatstg, 0, sizeof(STATSTG));
pstatstg->type = STGTY_STREAM;
pstatstg->cbSize = m_uSize;
}
return ret;
}
virtual HRESULT STDMETHODCALLTYPE Clone(IStream **ppstm)
{
return E_NOTIMPL;
}
private:
ULONG m_uCount;
LPVOID m_lpData;
ULARGE_INTEGER m_uSize;
ULARGE_INTEGER m_uCurrent;
BOOL m_bDeleteOnRelease;
};int main(int, char**)
{
void* lpBuf = NULL;
DWORD szBuf = 0;
FILE* fp = fopen("bk.png", "rb");
if (fp)
{
fseek(fp, 0, SEEK_END);
szBuf = (DWORD)ftell(fp);
fseek(fp, 0, SEEK_SET);
lpBuf = malloc(szBuf);
if (lpBuf)
fread(lpBuf, szBuf, 1, fp);
fclose(fp);
}
if (lpBuf)
{
IStreamEx* pStm = IStreamEx::CreateIStream(lpBuf, szBuf);
if (pStm)
{
DWORD dwToken = 0;
Gdiplus::GdiplusStartupInput input;
Gdiplus::GdiplusStartupOutput output;
Gdiplus::GdiplusStartup(&dwToken, &input, &output);
if (dwToken != 0)
{
Gdiplus::Bitmap* bmp = Gdiplus::Bitmap::FromStream(pStm);
if (bmp)
{
if (bmp->GetLastStatus() == Gdiplus::Ok)
{
printf("Succeeded!\r\n");
GUID jpg = {0x557CF401, 0x1A04, 0x11D3, 0x9A, 0x73, 0x00, 0x00, 0xF8, 0x1E, 0xF3, 0x2E};
bmp->Save(L"bk.jpg", &jpg);
}
delete bmp;
}
Gdiplus::GdiplusShutdown(dwToken);
}
pStm->Release();
}
free(lpBuf);
}
system("PAUSE");
return 0;
}
最后多嘴一下,在Image*存在的情况下,不要把ISteam*和相关内存释放掉,否则会出错,这个苦头以前吃过……
贴子暂不结, 给大家再讨论讨论, 沉了就给分.