ВВЕДЕНИЕ И СООТВЕТСТВУЮЩАЯ ИНФОРМАЦИЯ:
Я написал демонстрационное приложение, пытаясь научиться использовать ADO
потоки. Все работает нормально, за исключением одного особого случая. Позвольте мне начать с предоставления соответствующей информации:
Я использую WinAPI
для создания графического интерфейса и загружаю (и сохраняю его на диске)/вставляю BLOB при нажатии кнопки. Кнопки находятся в диалоговом окне.
ПРОБЛЕМА:
Когда я нажимаю кнопку для вставки BLOB в базу данных, я вижу, что она вставляется (я держу MS Access открытым). Если я попытаюсь загрузить любой существующий BLOB из базы данных, ничего не произойдет, но об ошибках не будет сообщено.
Однако, если я выполняю вставку, затем закрываю и снова открываю диалоговое окно, нажатие кнопки для загрузки BLOB и сохранения его на диск работает хорошо.
Я работаю над Windows 8.1, используя Visual Studio 2013 на ноутбуке с двухъядерным процессором x64 (это может быть важно упомянуть). Я протестировал свое приложение на разделе C:\, где находится ОС, просто решил упомянуть, если это уместно.
ИЗМЕНИТЬ:
Я попробовал свое приложение на разделе D, и оно работает. Это означает, что проблема кроется где-то в разрешениях. Можете ли вы помочь мне с этим, потому что я понятия не имею, как начать решать эту проблему?
КОНЕЦ РЕДАКТИРОВАНИЯ
SSCCE:
Чтобы помочь вам еще больше, внимательно следуйте инструкциям, чтобы создать очень минимальный пример кода, который воспроизводит проблему:
1.) Создайте default Win32 project
в Visual Studio.
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
, как показано ниже:
- В управлении вращением установлены стили
auto buddy
,right align, and
set 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, и оно работает. Это означает, что проблема кроется где-то в разрешениях. Можете ли вы помочь мне с этим, потому что я понятия не имею, как начать решать эту проблему?
КОНЕЦ РЕДАКТИРОВАНИЯ
Спасибо.