【发布时间】: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 buddy、right align, andset buddy integer` 样式集 - 按钮是简单的按钮,没什么特别的
- 编辑控件很简单,没什么特别的
8.) 创建具有以下字段的 MS Access 数据库:
- 表名:测试
- 第一个字段:ID
autonumber,primary key - 第二个字段:字段
OLE Object - 第三个字段:tip
text此字段存储文件的名称(file.extension)
如何使用这个应用程序:
当您运行应用程序时,打开About 菜单项以便弹出对话框。选择我们创建的数据库。
单击左按钮(来自先前提交的图像中的蓝色圆圈)。打开文件对话框弹出,你可以选择任何文件(我试过.pdf、.exe、.zip和jpeg)。文件应插入数据库。
要读取 BLOB 并将其保存在您的应用程序运行的同一位置,请输入您要检索的记录数并按右键(来自先前提交的图片中的红色圆圈)。应该加载 BLOB,然后将其保存在您的应用所在的同一位置。
最后说明:
这不是生产代码,请注意这一点。这只是说明问题的最小、最简单的代码示例。
同样,如果您插入 BLOB,然后尝试加载它,则不会发生任何事情,但代码会正常运行。
如果插入 BLOB,然后关闭对话框,再次打开对话框,然后尝试从数据库加载 BLOB,一切正常。
问题:
我如何重写我的代码,以便我可以插入,然后加载 BLOB,而无需求助于前面描述的“解决方案 #2”。
编辑:
我已经在 D 分区上尝试过我的应用程序并且它可以工作。这意味着问题出在权限的某个地方。你能帮我解决这个问题吗,因为我不知道如何开始解决这个问题?
编辑结束
谢谢。
【问题讨论】:
标签: c++ stream ms-access-2007 blob ado