2009-12-14 62 views
0

我们有一个完美的功能的应用程序,只需在Windows 7打破了,因为(在GDI +原)GdipCreateBitmapFromStream拒绝(在XP和Vista中,即使没有问题)提交给它的JPEG图像。GdipCreateBitmapFromStream在Windows 7上更改合同?

我们不直接调用GDI +,我们所说的记录ATL CImage类,它调用,并获得误差。

这是我们自己的OLE流实现。

有没有人看到过解决这个问题的方法?

下面是一个完整的测试用例:

#include <atlbase.h> 
#include <atlimage.h> 
#include <gdiplus.h> 
#include <time.h> 
#include <sys/stat.h> 

// GSMemoryStream.h : Declaration of the GSMemoryStream 

/* No ATL or class factory support is needed here. You get one of these via "new", with zero reference count... 
    Image.Load(IStreamPtr(new GSMemoryStream(ptr, len)); 
    and the smart pointer will provoke its deletion at the right time.... 
    */ 

// GSMemoryStream 

class GSMemoryStream : 
    public IStream 
{ 
    private: 
     ULONG m_Length; 
     ULONG m_CurPtr; 
     PBYTE m_Base; 
     int m_rc; 
public: 

    GSMemoryStream(PBYTE _p, DWORD _len) { 
     m_Length = _len; 
     m_CurPtr = 0; 
     m_Base = _p; 
     m_rc = 0; 
    } 

    GSMemoryStream() { 
     m_Length = 0; 
     m_CurPtr = 0; 
     m_Base = NULL; 
     m_rc = 0; 
    } 

     STDMETHODIMP Read(void *,ULONG,ULONG *); 
     STDMETHODIMP Write(const void *,ULONG,ULONG *) {return E_FAIL;} 
     STDMETHODIMP Seek(LARGE_INTEGER,DWORD,ULARGE_INTEGER *); 
     STDMETHODIMP SetSize(ULARGE_INTEGER) {return E_FAIL;} 
     STDMETHODIMP CopyTo(IStream *,ULARGE_INTEGER,ULARGE_INTEGER *,ULARGE_INTEGER *); 
     STDMETHODIMP Commit(DWORD) {return S_OK;} 
     STDMETHODIMP Revert(void) {return S_OK;} 
     STDMETHODIMP LockRegion(ULARGE_INTEGER,ULARGE_INTEGER,DWORD) {return S_OK;} 
     STDMETHODIMP UnlockRegion(ULARGE_INTEGER,ULARGE_INTEGER,DWORD) {return S_OK;} 
     STDMETHODIMP Stat(STATSTG *,DWORD); 
     STDMETHODIMP Clone(IStream **) {return E_FAIL;} 

     STDMETHODIMP QueryInterface(const IID & iid,void ** d) throw() { 
      if (IsEqualGUID(iid, IID_IUnknown) || IsEqualGUID (iid, __uuidof(IStream))) { 
       *d = (PVOID)this; 
       AddRef(); 
       return S_OK; 
      } 
      return E_FAIL; 
     } 

     ULONG STDMETHODCALLTYPE AddRef(void) throw() { 
      m_rc++; 
      return S_OK; 
     } 
     ULONG STDMETHODCALLTYPE Release(void) throw() { 
      if (--m_rc == 0) 
       delete this; // can never go negative, because the m_rc won't be around any more once it is 0. 
      // so it's not even meaningful to test for it and breakpoint or throw. 
      return S_OK; 
     } 
}; 



// CGSMemoryStream 

STDMETHODIMP GSMemoryStream::Read(void * p,ULONG n, ULONG * pNread) { 
    ATLTRACE(L"GSMS$Read p %p bufct %d m_curptr %d\r\n", p, n, m_CurPtr); 

    if ((n + m_CurPtr) > m_Length) 
     n = m_Length - m_CurPtr; 
    memcpy(p, m_Base + m_CurPtr, n); 
    if (pNread) 
     *pNread = n; 
    m_CurPtr += n; 
    ATLTRACE(L"GSMS$Read(final) n %d m_CurPtr %d\r\n", n, m_CurPtr); 
    return S_OK; 
} 

STDMETHODIMP GSMemoryStream::Seek(LARGE_INTEGER pos,DWORD type,ULARGE_INTEGER * newpos) { 
    LONG lpos = (LONG)pos.LowPart; 
    ATLTRACE(L"GSMS$Seek type %d lpos %d m_CurPtr %d\r\n", type, lpos, m_CurPtr); 
    switch (type) { 
     case STREAM_SEEK_SET: 
      if (lpos < 0 || lpos > (LONG) m_Length) 
       return E_POINTER; 
      m_CurPtr = (ULONG)lpos; 
      break; 

     case STREAM_SEEK_CUR: 
      if (lpos + m_CurPtr < 0 || lpos + m_CurPtr > m_Length) 
       return E_POINTER; 
      m_CurPtr += lpos; 
      break; 

     case STREAM_SEEK_END: 
      if (lpos > 0) 
       lpos = -lpos; 
      if (lpos + m_Length < 0) 
       return E_POINTER; 
      m_CurPtr = m_Length + lpos; 
      break; 
     default: 
      return E_FAIL; 

    } 
    ATLTRACE(L"GSMS$Seek end m_CurPtr %d\r\n", m_CurPtr); 
    if (newpos) { 
     newpos->HighPart = 0; 
     newpos->LowPart = m_CurPtr; 
    } 

    return S_OK; 
} 

STDMETHODIMP GSMemoryStream::CopyTo(IStream * pstm,ULARGE_INTEGER cb,ULARGE_INTEGER * pNread,ULARGE_INTEGER * pNwritten){ 
    ATLTRACE("GSMS$CopyTo\r\n"); 
    if (cb.HighPart) 
     return E_INVALIDARG; 
    ULONG n = cb.LowPart; 
    if ((n + m_CurPtr) > m_Length) 
     n = m_Length - m_CurPtr; 
    ULONG nwritten = 0; 
    HRESULT hr = pstm->Write(m_Base+m_CurPtr, n, &nwritten); 
    if (nwritten < n) 
     nwritten = n; 

    if (pNread) { 
     pNread->HighPart = 0; 
     pNread->LowPart = n; 
    } 
    if (pNwritten) { 
     pNwritten->HighPart = 0; 
     pNwritten->LowPart = nwritten; 
    } 
    m_CurPtr += n; 
    return hr; 
} 

STDMETHODIMP GSMemoryStream::Stat(STATSTG * ps,DWORD krazyflag) { 
    ATLTRACE(L"GSMS$Stat kf %d\r\n", krazyflag); 
    memset(ps, 0, sizeof(STATSTG)); 
    ps->type = STGTY_STREAM; 
    ps->cbSize.LowPart = m_Length; 
    ps->cbSize.HighPart = 0; 
#if 0 
    ps->mtime = (DWORD)time(NULL); 
    ps->ctime = (DWORD)time(NULL); 
    ps->atime = (DWORD)time(NULL); 
#endif 
    return S_OK; 
} 






int main (int argc, char ** argv) { 

    if (argc < 2) { 
     fprintf(stderr, "Need image file pathname\n"); 
     exit(2); 
    } 
    struct _stat SSTAT; 
    const char* fn = argv[1]; 
    int failed = _stat(fn, &SSTAT); 
    if (failed) { 
     fprintf(stderr, "Can't open file: %s\n", fn); 
     exit(3); 
    } 
    size_t len = SSTAT.st_size; 
    printf ("Len = %d\n", len); 
    FILE* f = fopen(fn, "rb"); 
    unsigned char * buf = new unsigned char [len]; 
    size_t got = fread (buf, 1, len, f); 
    printf ("Got = %d\n", got); 
    fclose(f); 

    CoInitialize(NULL); 
    Gdiplus::GdiplusStartupInput gdiplusStartupInput; 
    ULONG_PTR gdiplusToken; 

    Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 

    GSMemoryStream G(buf, len); 
    CImage cim; 
    HRESULT hr = cim.Load(&G); 
    printf("HRESULT = 0x%08X\n", hr); 
    delete [] buf; 
    CoUninitialize(); 
    return 0; 
} 

回答

0

进一步的研究表明,W7查询流上的一个额外的可选接口,它返回E_NOINTERFACE而不是E_NOTIMPL它是必不可少的。

0

您是否尝试过使用记录的位图对象,而不是使用无证GDI +的入口点?

+0

看我的编辑。 CImage做出这个选择,我们不这样做。 – bmargulies 2009-12-15 13:28:55