none
How to automate Access from C++ without using MFC or #import RRS feed

  • Question

  • Hi 

    My database (mdb) is getting modified when i am closing the file. (mdb file date getting modified). I even tried setting the read only flag to true/false while opening the database and while closing the database but no use. 

    May i know what went wrong. Please have a look at below code and let me know what went wrong and what to set in order to not to change the date of the mdb file during closing the database.

    Thanks in advance.

    HRESULT OpenDatabase(CString &csDatabaseName, CComPtr<IDispatch>& AccessApp, CComPtr<IDispatch>& plAccess)
    {
    HRESULT hr = S_OK;

    //check for file existence
    if (TRUE == ::PathFileExists(csDatabaseName))
    {
    try
    {
    // Get CLSID for our server...
    CLSID clsid;
    hr = CLSIDFromProgID(L"Access.Application", &clsid);

    if (FAILED(hr))
    {
    goto wrapup;
    }

    // Start server and get IDispatch...
    hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void **)&plAccess);

    if (FAILED(hr))
    {
    goto wrapup;
    }

    // Make it hidden (i.e. app.visible = 0)
      {
      CComVariant x;
      x.vt = VT_BOOL;
      x.boolVal = false;
      hr = AutoWrap(DISPATCH_PROPERTYPUT, NULL, plAccess, L"Visible", 1, x);
      }

    // Get Workbooks collection
    {
    CComVariant result;
    VariantInit(&result);
    CComVariant x[3];
    x[0].vt = VT_BSTR;
    x[0].bstrVal = csDatabaseName.AllocSysString();
    x[1].vt = VT_BOOL;
    x[1].boolVal = false; // i tried setting true & false but still its not working. :( 

    hr = AutoWrap(DISPATCH_METHOD, &result, plAccess, L"OpenCurrentDatabase", 2,x[1],x[0]);

    if (FAILED(hr))
    {
    goto wrapup;
    }
    }

    CComVariant result;
    hr = AutoWrap(DISPATCH_METHOD, &result, plAccess, L"CurrentDb", 0);

    if (FAILED(hr))
    {
    goto wrapup;
    }
    AccessApp = result.pdispVal;
    }
    catch (...)
    {
    goto wrapup;
    }
    }
    else
    {
    goto wrapup;
    }

    wrapup:
    return hr;

    }

    HRESULT CloseDatabase(CComPtr<IDispatch>& plAccess)
    {
    HRESULT hr = S_OK;

    if (plAccess != nullptr)
    {
    //close database
    CComVariant x;
    x.vt = VT_BOOL;
    x.boolVal = false;

    hr = AutoWrap(DISPATCH_METHOD, NULL, plAccess, L"CloseCurrentDatabase",1,x);

    //call quit
    hr = AutoWrap(DISPATCH_METHOD, NULL, plAccess, L"Quit", 0);
    }

    return hr;

    }

    HRESULT AutoWrap(int autoType, CComVariant *pvResult, IDispatch *pDisp, LPOLESTR ptName, int cArgs...) 
    {
    // Begin variable-argument list...
    va_list marker;
    va_start(marker, cArgs);

    if (!pDisp) {
    _exit(0);
    }

    // Variables used...
    DISPPARAMS dp = { NULL, NULL, 0, 0 };
    DISPID dispidNamed = DISPID_PROPERTYPUT;
    DISPID dispID;
    HRESULT hr;
    char szName[256];


    // Convert down to ANSI
    WideCharToMultiByte(CP_ACP, 0, ptName, -1, szName, sizeof(szName), NULL, NULL);

    // Get DISPID for name passed...
    hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT, &dispID);

    if (FAILED(hr)) 
    {
    return hr;
    }

    // Allocate memory for arguments...
    CComVariant *pArgs = new CComVariant[cArgs + 1];
    // Extract arguments...
    for (int i = 0; i<cArgs; i++) {
    pArgs[i] = va_arg(marker, CComVariant);
    }

    // Build DISPPARAMS
    dp.cArgs = cArgs;
    dp.rgvarg = pArgs;

    // Handle special-case for property-puts!
    if (autoType & DISPATCH_PROPERTYPUT) {
    dp.cNamedArgs = 1;
    dp.rgdispidNamedArgs = &dispidNamed;
    }

    // Make the call!
    EXCEPINFO exceptionInfo;
    hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, static_cast<WORD>(autoType), &dp, pvResult, &exceptionInfo, NULL);
    if (hr == DISP_E_EXCEPTION)
    {
    // return the scode instead.
    hr = exceptionInfo.scode;
    }
    if (FAILED(hr))
    {
    return hr;
    }

    // End variable-argument section...
    va_end(marker);

    delete[] pArgs;

    return hr;
    }

    Monday, August 1, 2016 3:53 PM

Answers

  • >>>I even tried setting the read only flag to true/false while opening the database and while closing the database but no use. 

    According to your description, I am not familiar with C++, so I create a VBA sample to try to reproduce this issue, unfortunately, I am not able.
    Sub OpenMDB()
    
        Dim accapp As Access.Application
        Set accapp = New Access.Application
        
        accapp.OpenCurrentDatabase ("D:\Database11.mdb")
        accapp.Visible = False
        accapp.CloseCurrentDatabase
    
    End Sub
    Sub ShowFileAccessInfo()
    
        Dim fs, f, s
        Set fs = CreateObject("Scripting.FileSystemObject")
        Set f = fs.GetFile("D:\Database11.mdb")
        s = UCase(filespec) & vbCrLf
        s = s & "Created: " & f.DateCreated & vbCrLf
        s = s & "Last Accessed: " & f.DateLastAccessed & vbCrLf
        s = s & "Last Modified: " & f.DateLastModified
        MsgBox s, 0, "File Access Info"
    End Sub
    So I suggest that you could use above sample VBA code to make sure whether this issue is able to be reproduced.

    In addition you could open an other mdb database file to check whether this issue is related to special mdb file.

    Thanks for your understanding.
    • Proposed as answer by David_JunFeng Thursday, August 11, 2016 1:48 PM
    • Marked as answer by David_JunFeng Tuesday, August 16, 2016 2:00 PM
    Tuesday, August 2, 2016 7:15 AM