ADO流无法保存从数据库加载的BLOB

时间:2014-12-03 05:21:01

标签: c++ stream ms-access-2007 blob ado

引言及相关资料:

我编写了演示应用,试图学习如何使用ADO流。除了一个特殊情况外,一切正常。首先让我提供相关信息:

我正在使用WinAPI创建GUI,并在按下按钮时加载(并将其保存在磁盘上)/插入BLOB。按钮位于对话框中。

问题:

当我按下按钮将BLOB插入数据库时​​,我可以看到它被插入(我保持MS Access打开)。如果我尝试从数据库加载任何现有的BLOB,则不会发生任何错误信号。

但是,如果我执行insert,然后关闭并重新打开对话框,按下按钮以加载BLOB并将其保存到磁盘中效果很好。

我在x64双核CPU笔记本电脑上使用Visual Studio 2013在Windows 8.1上工作(这可能很重要)。 我已经在C:\分区中测试了我的应用程序操作系统,只是提到它是相关的。

编辑:

我在D分区上尝试了我的应用程序,但它确实有效。这意味着问题出在权限的某个地方。你能帮助我吗,因为我不知道如何开始解决这个问题?

END OF EDIT

SSCCE:

为了进一步帮助您,请仔细按照说明创建非常简单的代码示例来重现问题:

1。)在Visual Studio中创建default Win32 project

2。)在stdafx.h #include <windows.h>下面添加以下内容:

#include <comutil.h>
#include <stdio.h>
#include <ole2.h>
#include <string>
#include <shlwapi.h>
#pragma comment( lib, "comsuppw.lib")
#pragma comment( lib, "shlwapi.lib")

3。)在.cpp指令下面的主#include文件中添加以下内容:

#import <C:\\Program Files\\Common Files\\System\\ado\\msado15.dll>  \
    rename( "EOF", "AdoNSEOF" )

4.。)在对话框程序About上面添加以下函数:

BOOL OpenFile(HWND hDlg, LPWSTR szFileName, LPWSTR szFilter)
{
    // prepare OPENFILE dialog 
    OPENFILENAME ofn;

    memset(&ofn, 0, sizeof(ofn));
    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hwndOwner = hDlg;
    ofn.lpstrFilter = szFilter;
    ofn.lpstrFile = szFileName;
    ofn.lpstrFile[0] = L'\0';
    ofn.nMaxFile = MAX_PATH;
    ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST |
        OFN_DONTADDTORECENT | OFN_HIDEREADONLY |
        OFN_PATHMUSTEXIST;
    ofn.lpstrDefExt = L".pdf";

    if (GetOpenFileName(&ofn))
        return TRUE;

    return FALSE;
}

5.用这个替换About对话框程序:

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    // connection string
    static wchar_t bstrConnect[MAX_PATH];
    switch (message)
    {
    case WM_INITDIALOG:
    {
        // create connection string by choosing database 
        wchar_t szFile[MAX_PATH];
        OpenFile(hDlg, szFile, L".accdb\0");
        swprintf_s(bstrConnect, MAX_PATH, 
            L"Provider=Microsoft.ACE.OLEDB.12.0; Data Source = %s;", szFile);
    }
         return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDC_BUTTON1)  // save BLOB to database
        {
            wchar_t szFileName[MAX_PATH] = L"";

            if (OpenFile(hDlg, szFileName, L"All files\0*.*"))
            {
                try
                {
                    HRESULT hr = CoInitialize(NULL);

                    ADODB::_ConnectionPtr pConn(L"ADODB.Connection");
                    ADODB::_RecordsetPtr pRS(L"ADODB.Recordset");

                    hr = pConn->Open(bstrConnect, 
                        L"", L"", ADODB::adConnectUnspecified);

                    // create new recordset 
                    pRS->Open( L"test", _variant_t((IDispatch*)pConn, true),
                        ADODB::adOpenKeyset, 
                        ADODB::adLockOptimistic, 
                        ADODB::adCmdTable);

                    // create stream object
                    ADODB::_StreamPtr pStream(L"ADODB.Stream");
                    // set stream type
                    pStream->Type = ADODB::adTypeBinary;
                    // missing parameter for Open 
                    _variant_t varOptional(DISP_E_PARAMNOTFOUND, VT_ERROR);  
                    // open stream
                    pStream->Open(varOptional, 
                        ADODB::adModeUnknown, 
                        ADODB::adOpenStreamUnspecified,
                        _bstr_t(L""), _bstr_t(L""));

                    // open selected file
                    hr = pStream->LoadFromFile(szFileName);

                    // error checking
                    if (FAILED(hr))
                        throw _com_error(hr);

                    // add new blank  record
                    pRS->AddNew();
                    // position stream to beginning
                    pStream->Position = 0;
                    // insert data to recordset

                    PathStripPath(szFileName);  // leave only filename

                    pRS->Fields->GetItem(L"tip")->Value = szFileName;
                    pRS->Fields->GetItem(L"field")->Value =
                        pStream->Read(ADODB::adReadAll);

                    // insert data
                    pRS->Update();

                    //cleanup
                    pRS->Close();
                    pConn->Close();
                    pStream->Close();
                    CoUninitialize();
                    MessageBeep(0);
                }
                catch (_com_error e)
                {
                    MessageBox(hDlg, (LPWSTR)e.Description(), L"", 0);
                }
            }
        }
        if (LOWORD(wParam) == IDC_BUTTON3)  // load BLOB and save it into disk
        {
            try
            {
                // napravi upit

                HRESULT hr = CoInitialize(NULL);

                ADODB::_ConnectionPtr pConn(L"ADODB.Connection");
                ADODB::_RecordsetPtr pRS(L"ADODB.Recordset");

                hr = pConn->Open(bstrConnect, L"", L"", ADODB::adConnectUnspecified);

                // create stream object
                ADODB::_StreamPtr pStream(L"ADODB.Stream");
                // set stream type
                pStream->Type = ADODB::adTypeBinary;
                // missing parameter for Open
                _variant_t varOptional(DISP_E_PARAMNOTFOUND, VT_ERROR); 
                // open stream 
                pStream->Open(varOptional, 
                    ADODB::adModeUnknown, 
                    ADODB::adOpenStreamUnspecified,
                    _bstr_t(L""), _bstr_t(L""));

                // primary key is taken from edit control
                wchar_t query[200] = L"";
                swprintf_s(query, 200, L"select tip, field from test where ID = %d;",
                    (int)GetDlgItemInt(hDlg, IDC_EDIT1, FALSE, FALSE));

                pRS->Open(query, _variant_t((IDispatch *)pConn, true),
                    ADODB::adOpenUnspecified, ADODB::adLockPessimistic,
                    ADODB::adCmdText);

                if (NULL == pRS)
                    MessageBox(hDlg, L"Empty recordset!", L"", 0);

                hr = pStream->Write(pRS->Fields->GetItem(L"field")->Value);

                if (FAILED(hr))
                    MessageBox(hDlg, L"stream write failed", L"", 0);

                // save to file
                // store this file on disk
                // int he same place our app is running
                wchar_t szFileName[MAX_PATH] = L"";

                swprintf_s(szFileName, MAX_PATH, L".\\%s",
                    pRS->Fields->GetItem(L"tip")->Value.bstrVal);

                hr = pStream->SaveToFile(szFileName, ADODB::adSaveCreateOverWrite);

                if (FAILED(hr))
                    MessageBox(hDlg, L"save to file failed", L"", 0);

                //cleanup
                pRS->Close();
                pConn->Close();
                pStream->Close();
                CoUninitialize();
                MessageBeep(0);
            }
            catch (_com_error e)
            {
                MessageBox(hDlg, (LPWSTR)e.Description(), L"", 0);
            }
        }
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

7。)About编辑器中的返工rc对话框,如下所示:

enter image description here

  • 旋转控件具有auto buddyright align, and设置好友整数样式集
  • 按钮是简单的按钮,没什么特别的
  • 编辑控件很简单,没什么特别的

8。)使用以下字段创建MS Access数据库:

  • 表名: test
  • 第一个字段: ID autonumberprimary key
  • 第二个字段:字段 OLE Object
  • 第三个字段:提示 text 此字段存储文件名(file.extension)

如何使用此应用程序:

运行应用程序时,打开About菜单项,以便弹出对话框。选择我们创建的数据库

单击左侧按钮(从之前提交的图像中的蓝色圆圈)。打开文件对话框弹出,您可以选择任何文件(我尝试使用.pdf.exe.zipjpeg)。文件应插入数据库。

要阅读BLOB并将其保存在应用程序运行的相同位置,请键入要检索的记录数,然后按右键(从之前提交的图片中的红色圆圈)。应该加载BLOB,然后将其保存在应用程序所在的相同位置。

最终说明:

这不是生产代码,请注意这一点。这只是解释问题的最小,最简单的代码示例。

同样,如果你插入BLOB然后尝试加载它,没有任何反应,但代码运行没有错误。

如果您插入BLOB,然后关闭对话框,再次打开对话框,然后尝试从数据库加载BLOB一切正常。

问题:

如何重写我的代码,以便我可以插入,然后加载BLOB而不诉诸&#34;解决方案#2&#34;如前所述。

编辑:

我在D分区上尝试了我的应用程序,但它确实有效。这意味着问题出在权限的某个地方。你能帮助我吗,因为我不知道如何开始解决这个问题?

END OF EDIT

谢谢。

1 个答案:

答案 0 :(得分:2)

通常情况下,当我自己解决问题并且没有答案时,我只是删除了问题。但是,发布的代码对于后代来说可能是一个很好的工作示例。

问题在于我构建文件路径。在重写我的代码后,一切正常。这是完整的对话程序:

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    // connection string
    static wchar_t bstrConnect[MAX_PATH];
    switch (message)
    {
    case WM_INITDIALOG:
    {
        wchar_t szFile[MAX_PATH];
        OpenFile(hDlg, szFile, L".accdb\0");
        swprintf_s(bstrConnect, MAX_PATH, 
            L"Provider=Microsoft.ACE.OLEDB.12.0; Data Source = %s;", szFile);
    }
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDC_BUTTON1:
        {
            wchar_t szFileName[MAX_PATH] = L"";

            if (OpenFile(hDlg, szFileName, L"All files\0*.*"))
            {
                try
                {
                    // disable write button, just in case, until we finish inserting
                    EnableWindow(GetDlgItem(hDlg, IDC_BUTTON3), FALSE);

                    HRESULT hr = CoInitialize(NULL);

                    ADODB::_ConnectionPtr pConn(L"ADODB.Connection");
                    ADODB::_RecordsetPtr pRS(L"ADODB.Recordset");

                    hr = pConn->Open(bstrConnect, L"", L"", 
                        ADODB::adConnectUnspecified);
                    // create new recordset 
                    pRS->Open(L"test", _variant_t((IDispatch*)pConn, true),
                        ADODB::adOpenKeyset, ADODB::adLockOptimistic, 
                        ADODB::adCmdTable);
                    // create stream object
                    ADODB::_StreamPtr pStream(L"ADODB.Stream");
                    // set stream type
                    pStream->Type = ADODB::adTypeBinary;
                    // missing parameter
                    _variant_t varOptional(DISP_E_PARAMNOTFOUND, VT_ERROR);  
                    // open stream
                    pStream->Open(varOptional, ADODB::adModeUnknown,
                        ADODB::adOpenStreamUnspecified, _bstr_t(L""), _bstr_t(L""));
                    // open selected file
                    hr = pStream->LoadFromFile(szFileName);
                    if(FAILED(hr))
                        throw _com_error(hr);
                    // add new blank  record
                    pRS->AddNew();
                    // position stream
                    pStream->Position = 0;
                    // insert data to recordset
                    PathStripPath(szFileName);  // leave only filename
                    pRS->Fields->GetItem(L"tip")->Value = szFileName; // store filename
                    pRS->Fields->GetItem(L"field")->Value =
                        pStream->Read(ADODB::adReadAll); // store BLOB
                    // insert data
                    pRS->Update();
                    //cleanup
                    pRS->Close();
                    pConn->Close();
                    pStream->Close();
                    CoUninitialize();
                    // now is safe to read BLOB from database so enable load button
                    EnableWindow(GetDlgItem(hDlg, IDC_BUTTON3), TRUE);
                    // make a sound just so we know we made it! :)
                    MessageBeep(0);
                }
                catch (_com_error e)
                {
                   MessageBox(hDlg, (LPWSTR)e.Description(), L"", 0);
                }
            }
        }
            break;
       case IDC_BUTTON3:
        {
            try
            {
                HRESULT hr = CoInitialize(NULL);

                if (FAILED(hr))
                    throw _com_error(hr);

                ADODB::_ConnectionPtr pConn(L"ADODB.Connection");
                ADODB::_RecordsetPtr pRS(L"ADODB.Recordset");

                hr = pConn->Open(bstrConnect, L"", L"", ADODB::adConnectUnspecified);

                if (FAILED(hr))
                {
                    MessageBox(hDlg, L"connection error", L"", 0);
                    throw _com_error(hr);
                }


                // create stream object
                ADODB::_StreamPtr pStream(L"ADODB.Stream");
                // set stream type
                pStream->Type = ADODB::adTypeBinary;
                // missing parameter
                _variant_t varOptional(DISP_E_PARAMNOTFOUND, VT_ERROR);  
                hr = pStream->Open(varOptional, ADODB::adModeUnknown,
                    ADODB::adOpenStreamUnspecified, _bstr_t(L""), _bstr_t(L""));

                if (FAILED(hr))
                {
                    MessageBox(hDlg, L"connection error", L"", 0);
                    throw _com_error(hr);
                }

                wchar_t query[200] = L"";
                BOOL ok = true;  // needed for error checking ( GetDlgInt -> see the docs )

                swprintf_s(query, 200, L"select tip, field from test where ID = %d;",
                    (int)GetDlgItemInt(hDlg, IDC_EDIT1, &ok, FALSE));

                if (!ok)
                    MessageBox(hDlg, L"dlgitemint failed", L"", 0);

                hr = pRS->Open(query, _variant_t((IDispatch *)pConn, true),
                    ADODB::adOpenUnspecified, ADODB::adLockPessimistic,
                    ADODB::adCmdText);

                if (FAILED(hr))
                {
                    MessageBox(hDlg, L"connection error", L"", 0);
                    throw _com_error(hr);
                }

                if (NULL == pRS)
                {
                    MessageBox(hDlg, L"NULL pRS!", L"", 0);
                    throw _com_error(hr);
                }

                if (pRS->BOF && pRS->AdoNSEOF)
                    MessageBox(hDlg, L"empty rs", L"", 0);

                hr = pStream->Write(pRS->Fields->GetItem(L"field")->Value);

                if (!pStream->GetSize())
                    MessageBox(hDlg, L"stream write failed", L"", 0);

                if (FAILED(hr))
                {
                    MessageBox(hDlg, L"stream write failed", L"", 0);
                    throw _com_error(hr);
                }

                // save to file
                wchar_t szFileName[MAX_PATH] = L"";

                // this returns directory where our exe is running
                GetModuleFileName(NULL, szFileName, MAX_PATH);
                // now we remove name and extension of the exe file
                PathRemoveFileSpec(szFileName);
                // add backslash at the end
                PathAddBackslash(szFileName);
                // now we "glue" the name of our BLOB ( we stored it into DB )
                wcscat_s(szFileName, MAX_PATH,
                   pRS->Fields->GetItem(L"tip")->Value.bstrVal);

                if (!wcslen(szFileName))
                    MessageBox(hDlg, L"load field name failed", L"", 0);

                hr = pStream->SaveToFile(szFileName, ADODB::adSaveCreateOverWrite);

                if (FAILED(hr))
                {
                    MessageBox(hDlg, L"save to file failed", L"", 0);
                    throw _com_error(hr);
                }

                //cleanup
                pRS->Close();
                pConn->Close();
                pStream->Close();
                CoUninitialize();
                // beep so we know all went well
                MessageBeep(0);
            }
            catch (_com_error e)
            {
                MessageBox(hDlg, (LPWSTR)e.Description(), L"", 0);
            }
        }
            break;
        case IDOK:
        case IDCANCEL:
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }    
            break;
        default:
            break;
        }
    }
    return (INT_PTR)FALSE;
}

这只是一个测试代码,但仍然是我工作的重要部分(插入或加载+保存BLOB)。希望它对未来的读者有用。

如果其他成员有改进读取/写入BLOB的代码部分的建议,请发表评论。建设性的批评总是受欢迎的。

我重写了代码,几乎可以存储任何文件。我已成功测试了GIF,PDF,DOCX,XLSX,JPEG,BMP,EXE和TXT。我也在USB上运行我的应用程序,它也运行良好。