LRESULT CDlg::OnBnClickedRead(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
// TODO: 在此添加控件通知处理程序代码
CISSHelper css;//接口类,继承了ISequentialStream
char* fn = "f:\\first.jpeg";
HRESULT hr;
CBB rs;//数据库的数据格式,本人是用ATL中的OLEDB使用者向导打开的.
BYTE m_blob[8000];//文件在内存中形式
size_t len;
//打开数据库
hr = rs.OpenAll();
hr = rs.MoveFirst();
if(FAILED(hr))
{
ATLTRACE("MoveFirst Failed!\n");
} //读文件
FILE* file;
file = fopen( fn, "rb");
len = fread( m_blob, sizeof(BYTE), 8000, file);
m_blob[ len + 1] = '\0';
fclose( file);
         
         //向ISequentialStream接口继承类写数据
hr = css.Write( m_blob, len, NULL);

rs.m_BLOB = (ISequentialStream*)&css;
rs.m_dwBLOBStatus = DBSTATUS_S_OK;
rs.m_dwBLOBLength = css.m_ulLength;
//>>-------------------------------------------------------------->>
         // 向数据库插入数据
hr = rs.Insert();// 返回值hr= E_UNEXPECTED
         //此处报错. 请高手给看看.
//<<--------------------------------------------------------------<<
if(FAILED(hr))
{
ATLTRACE("SaveToDb Failed!\n");
}
//关闭数据库
rs.CloseAll(); return 0;
}
class CISSHelper : public ISequentialStream  
{
public: // Constructor/destructor.
CISSHelper();
virtual ~CISSHelper(); // Helper function to clean up memory.
virtual void Clear(); // ISequentialStream interface implementation.
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppv);
    STDMETHODIMP Read( 
            /* [out] */ void __RPC_FAR *pv,
            /* [in] */ ULONG cb,
            /* [out] */ ULONG __RPC_FAR *pcbRead);
    STDMETHODIMP Write( 
            /* [in] */ const void __RPC_FAR *pv,
            /* [in] */ ULONG cb,
            /* [out] */ ULONG __RPC_FAR *pcbWritten);public: void*       m_pBuffer; // Buffer
ULONG       m_ulLength;     // Total buffer size.
ULONG       m_ulStatus;     // Column status.private: ULONG m_cRef; // Reference count (not used).
ULONG       m_iReadPos;     // Current index position for reading from the buffer.
ULONG       m_iWritePos;    // Current index position for writing to the buffer.};
CISSHelper::CISSHelper()
{
m_cRef = 0;
m_pBuffer = NULL;
m_ulLength = 0;
m_ulStatus  = DBSTATUS_S_OK;
m_iReadPos = 0;
m_iWritePos = 0;
}CISSHelper::~CISSHelper()
{
Clear();
}void CISSHelper::Clear() 
{
CoTaskMemFree( m_pBuffer );
m_cRef = 0;
m_pBuffer = NULL;
m_ulLength = 0;
m_ulStatus  = DBSTATUS_S_OK;
m_iReadPos = 0;
m_iWritePos = 0;
}ULONG CISSHelper::AddRef(void)
{
return ++m_cRef;
}ULONG CISSHelper::Release(void)
{
return --m_cRef;
}HRESULT CISSHelper::QueryInterface( REFIID riid, void** ppv )
{
*ppv = NULL;
if ( riid == IID_IUnknown )  *ppv = this;
if ( riid == IID_ISequentialStream ) *ppv = this;
if ( *ppv )
{
( (IUnknown*) *ppv )->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}HRESULT CISSHelper::Read( void *pv, ULONG cb, ULONG* pcbRead )
{
// Check parameters.
if ( pcbRead ) *pcbRead = 0;
if ( !pv ) return STG_E_INVALIDPOINTER;
if ( 0 == cb ) return S_OK;  // Calculate bytes left and bytes to read.
ULONG cBytesLeft = m_ulLength - m_iReadPos;
ULONG cBytesRead = cb > cBytesLeft ? cBytesLeft : cb; // If no more bytes to retrive return S_FALSE.
if ( 0 == cBytesLeft ) return S_FALSE; // Copy to users buffer the number of bytes requested or remaining
memcpy( pv, (void*)((BYTE*)m_pBuffer + m_iReadPos), cBytesRead );
m_iReadPos += cBytesRead; // Return bytes read to caller.
if ( pcbRead ) *pcbRead = cBytesRead;
if ( cb != cBytesRead ) return S_FALSE;  return S_OK;
}
        
HRESULT CISSHelper::Write( const void *pv, ULONG cb, ULONG* pcbWritten )
{
// Check parameters.
if ( !pv ) return STG_E_INVALIDPOINTER;
if ( pcbWritten ) *pcbWritten = 0;
if ( 0 == cb ) return S_OK; // Enlarge the current buffer.
m_ulLength += cb; // Grow internal buffer to new size.
//m_pBuffer = CoTaskMemRealloc( m_pBuffer, m_ulLength );
m_pBuffer = CoTaskMemAlloc ( m_ulLength );
// Check for out of memory situation.
if ( NULL == m_pBuffer ) 
{
Clear();
return E_OUTOFMEMORY;
} // Copy callers memory to internal bufffer and update write position.
memcpy( (void*)((BYTE*)m_pBuffer + m_iWritePos), pv, cb );
m_iWritePos += cb; // Return bytes written to caller.
if ( pcbWritten ) *pcbWritten = cb; return S_OK;
}

解决方案 »

  1.   

    这是数据库的文件类.
    class CBBAccessor
    {
    public:
     ISequentialStream* m_BLOB;
    //BYTE m_BLOB[8000]; // 以下向导生成的数据成员包含列映射中相应字段的状态值。
    // 可以使用这些值保存数据库返回的 NULL 值或在编译器返回
    // 错误时保存错误信息。有关如何使用这些字段的详细信息,
    // 请参见 Visual C++ 文档中的“向导生成的访问器中的字段状态数据成员”。
    // 注意: 在设置/插入数据前必须初始化这些字段! DBSTATUS m_dwBLOBStatus; // 以下向导生成的数据成员包含列映射中相应字段的长度值。
    // 注意: 对变长列,必须在设置/插入数据前初始化这些字段! DBLENGTH m_dwBLOBLength;
    void GetRowsetProperties(CDBPropSet* pPropSet)
    {
    pPropSet->AddProperty(DBPROP_CANFETCHBACKWARDS, true, DBPROPOPTIONS_OPTIONAL);
    pPropSet->AddProperty(DBPROP_CANSCROLLBACKWARDS, true, DBPROPOPTIONS_OPTIONAL);
     pPropSet->AddProperty(DBPROP_ISequentialStream, true);
    pPropSet->AddProperty(DBPROP_IRowsetChange, true, DBPROPOPTIONS_OPTIONAL);
    pPropSet->AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE);
    } HRESULT OpenDataSource()
    {
    CDataSource _db;
    HRESULT hr;
    //#error Security Issue: The connection string may contain a password
    // 此连接字符串中可能包含密码
    // 下面的连接字符串中可能包含明文密码和/或
    // 其他重要信息。请在查看完
    // 此连接字符串并找到所有与安全有关的问题后移除 #error。可能需要
    // 将此密码存储为其他格式或使用其他的用户身份验证。
    hr = _db.OpenFromInitializationString(L"Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=temp;Use Procedure for Prepare=1;Auto Translate=True;Packet Size=4096;Workstation ID=HONGYING-JNCC45;Use Encryption for Data=False;Tag with column collation when possible=False");
    if (FAILED(hr))
    {
    #ifdef _DEBUG
    AtlTraceErrorRecords(hr);
    #endif
    return hr;
    }
    return m_session.Open(_db);
    } void CloseDataSource()
    {
    m_session.Close();
    } operator const CSession&()
    {
    return m_session;
    } CSession m_session; DEFINE_COMMAND_EX(CBBAccessor, L" \
    SELECT \
    BLOB \
    FROM dbo.BB")// 该表/命令包含可以通过 ISequentialStream 接口访问
    // 的列。然而,并非所有提供程序都支持此功能,即使
    // 那些确实支持此功能的提供程序通常也仅限为每个行集
    // 只有一个 ISequentialStream。
    // 如果希望在此访问器中使用流,请使用以下代码的示例
    // 行,并将 DBPROP_ISequentialStream 行集属性设置为
    // “真”。然后就可以使用 Read() 方法读取数据或使用 Write()
    // 方法写入数据(注意此操作要求将 STGM_READ 流属性
    // 更改为 STGM_WRITE 或 STGM_READWRITE)。有关
    // ISequentialStream 绑定的详细信息,请参见文档 // 为解决某些提供程序的若干问题,以下代码可能以
    // 不同于提供程序所报告的顺序来绑定列 BEGIN_COLUMN_MAP(CBBAccessor)
     BLOB_ENTRY_LENGTH_STATUS(1, IID_ISequentialStream, STGM_READ, m_BLOB, m_dwBLOBLength, m_dwBLOBStatus)
    //COLUMN_ENTRY_LENGTH_STATUS(1, m_BLOB, m_dwBLOBLength, m_dwBLOBStatus)
    END_COLUMN_MAP()
    };class CBB : public CCommand<CAccessor<CBBAccessor> >
    {
    public:
    HRESULT OpenAll()
    {
    HRESULT hr;
    hr = OpenDataSource();
    if (FAILED(hr))
    return hr;
    __if_exists(GetRowsetProperties)
    {
    CDBPropSet propset(DBPROPSET_ROWSET);
    __if_exists(HasBook)
    {
    if( HasBook() )
    propset.AddProperty(DBPROP_IRowsetLocate, true);
    }
    GetRowsetProperties(&propset);
    return OpenRowset(&propset);
    }
    __if_not_exists(GetRowsetProperties)
    {
    __if_exists(HasBook)
    {
    if( HasBook() )
    {
    CDBPropSet propset(DBPROPSET_ROWSET);
    propset.AddProperty(DBPROP_IRowsetLocate, true);
    return OpenRowset(&propset);
    }
    }
    }
    return OpenRowset();
    } HRESULT OpenRowset(DBPROPSET *pPropSet = NULL)
    {
    HRESULT hr = Open(m_session, NULL, pPropSet);
    #ifdef _DEBUG
    if(FAILED(hr))
    AtlTraceErrorRecords(hr);
    #endif
    return hr;
    } void CloseAll()
    {
    Close();
    ReleaseCommand();
    CloseDataSource();
    }
    };