【问题标题】:ADO stream failes to save BLOB loaded from databaseADO 流无法保存从数据库加载的 BLOB
【发布时间】:2014-12-03 05:21:00
【问题描述】:

简介及相关资料:

我编写了演示应用程序以尝试学习如何使用ADO 流。除一种特殊情况外,一切正常。让我从提供相关信息开始:​​

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

问题:

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

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

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

编辑:

我已经在 D 分区上尝试过我的应用程序并且它可以工作。这意味着问题出在权限的某个地方。你能帮我解决这个问题吗,因为我不知道如何开始解决这个问题?

编辑结束

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.) 在 #include 指令下方的主 .cpp 文件中添加以下内容:

#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.) 在rc 编辑器中重做@​​987654335@ 对话框,如下所示:

  • Spin 控件具有auto buddyright align, andset buddy integer` 样式集
  • 按钮是简单的按钮,没什么特别的
  • 编辑控件很简单,没什么特别的

8.) 创建具有以下字段的 MS Access 数据库:

  • 表名:测试
  • 第一个字段:ID autonumber, primary key
  • 第二个字段:字段 OLE Object
  • 第三个字段:tip text 此字段存储文件的名称(file.extension)

如何使用这个应用程序:

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

单击左按钮(来自先前提交的图像中的蓝色圆圈)。打开文件对话框弹出,你可以选择任何文件(我试过.pdf.exe.zipjpeg)。文件应插入数据库。

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

最后说明:

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

同样,如果您插入 BLOB,然后尝试加载它,则不会发生任何事情,但代码会正常运行。

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

问题:

我如何重写我的代码,以便我可以插入,然后加载 BLOB,而无需求助于前面描述的“解决方案 #2”。

编辑:

我已经在 D 分区上尝试过我的应用程序并且它可以工作。这意味着问题出在权限的某个地方。你能帮我解决这个问题吗,因为我不知道如何开始解决这个问题?

编辑结束

谢谢。

【问题讨论】:

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


    【解决方案1】:

    通常,当我自己解决问题并且没有答案时,我会简单地删除问题。但是,发布的代码可能是后代的很好的工作示例。

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

    // 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 上运行了我的应用程序,它也运行良好。

    【讨论】:

      猜你喜欢
      • 2017-12-16
      • 2014-11-24
      • 2018-03-20
      • 2019-09-05
      • 2012-04-11
      • 2015-01-12
      • 1970-01-01
      • 1970-01-01
      • 2011-02-14
      相关资源
      最近更新 更多