Insert raw file data into BLOB (“OLE Object”) fiel

2019-07-11 18:52发布

问题:

I am trying to insert a file into MS Access database, into a field of OLE Object type. I am using C++ and ADO.

Currently I get error Invalid pointer error.

I think that my problem is mishandling variants since this is the first time I use them. I am learning from this code example but have problem understanding how to insert file from disk into variant.

They read it from database, and copied it into new record so the part where I read file from disk and then insert it into variant is missing.

I am firing off my code in GUI when menu item is selected. Database has one table named test with fields ID which is primary key and field which is of OLE Object type.

After searching online I have found nothing that can help me.

Here is smallest code snippet possible that illustrates the problem ( error checking is minimal):

wchar_t *bstrConnect = L"Provider=Microsoft.ACE.OLEDB.12.0; \
        Data Source = C:\\Users\\Smiljkovic85\\Desktop\\OLE.accdb";

    try
    {
        HRESULT hr = CoInitialize(NULL);

        // connection
        ADODB::_ConnectionPtr pConn(L"ADODB.Connection");

        // recordset
        ADODB::_RecordsetPtr pRS(L"ADODB.Recordset");

        // connect to DB
        hr = pConn->Open(bstrConnect, L"admin", L"", ADODB::adConnectUnspecified);

        // open file
        std::ifstream in(L"C:\\Users\\Smiljkovic85\\Desktop\\file.pdf",
               std::ios::ate | std::ios::binary);

        // get file size
        int fileSize = in.tellg();

        // here I tried to adapt code from the example linked above
        pRS->Open(L"test", _variant_t((IDispatch*)pConn, true), 
            ADODB::adOpenKeyset, ADODB::adLockOptimistic, ADODB::adCmdTable);

        // add new record
        pRS->AddNew();

        // copy pasted
        _variant_t varChunk;

        SAFEARRAY FAR *psa;
        SAFEARRAYBOUND rgsabound[1];
        rgsabound[0].lLbound = 0;
        // modify to our file size
        rgsabound[0].cElements = fileSize;
        psa = SafeArrayCreate(VT_UI1, 1, rgsabound);

        //=================== try to add file into variant
        char *chData = (char *)psa->pvData;

        chData = new char[fileSize];
        in.read(chData, fileSize);

        /* ============= I have even tried the following :

        char *chData = new char[fileSize];
        in.read(chData, fileSize);

        BYTE* pData;
        SafeArrayAccessData(psa, (void **)&pData);
        memcpy(pData, chData, fileSize);
        SafeArrayUnaccessData(psa);

        ===============*/

        //=================================================

        // Assign the Safe array  to a variant. 
        varChunk.vt = VT_ARRAY | VT_UI1;
        varChunk.parray = psa;

        pRS->Fields->GetItem(L"field")->AppendChunk(varChunk);
        // add this record into DB
        pRS->Update();

        // cleanup
        delete[] chData;
        in.close();
        pRS->Close();
        pConn->Close();
        CoUninitialize();
    }
    catch (_com_error e)
    {
        MessageBox(hWnd, (LPWSTR)e.Description(), L"", 0);
    }

Can you help me to modify this code snippet so I can insert file into variant?

EDIT:

I have searched here for help and two posts that gave me an idea. Still none of my solutions work. You can see them in the above code snippet, in the comments.

What I get now, is the following error: a problem occurred while microsoft access was communicating with the ole server or activex control in MS Access. I have searched online for solution but had no luck, every link claims it has to do with access and not with the code.

Please help...

回答1:

Since you are already using ADODB.Connection and ADODB.Recordset objects you should be able to use a binary ADODB.Stream object to manipulate the file contents with

  • .LoadFromFile to fill the Stream with the file contents, and
  • .Read to pull it back out of the Stream and store it in the database field.

Unfortunately I cannot offer a C++ example, but in VBA the code would be:

Dim con As ADODB.Connection, rst As ADODB.Recordset, strm As ADODB.Stream
Set con = New ADODB.Connection
con.Open _
        "Provider=Microsoft.ACE.OLEDB.12.0;" & _
        "Data Source=C:\Users\Public\Database1.accdb"
Set rst = New ADODB.Recordset
rst.Open "test", con, adOpenKeyset, adLockOptimistic, adCmdTable
Set strm = New ADODB.Stream
strm.Type = adTypeBinary
strm.Open
strm.LoadFromFile "C:\Users\Gord\Desktop\test.pdf"
rst.AddNew
strm.Position = 0
rst.Fields("FileData").Value = strm.Read
rst.Update
rst.Close
Set rst = Nothing
con.Close
Set con = Nothing
strm.Close
Set strm = Nothing