NO

Author Topic: Example using ado  (Read 11312 times)

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2115
Example using ado
« on: November 25, 2014, 10:52:17 AM »
This is just an example using ado
Code: [Select]
#define UNICODE
#define _UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define INITGUID
#include <ole2.h>
#include <stdio.h>
#include <tchar.h>

#include "msado15.h"

#pragma comment(lib, "user32.lib")
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "oleaut32.lib")

TCHAR *GetADOErrorCode(DWORD nErr);

int main(int argc, char **argv)
{
HRESULT hr;
Recordset15 *pRst = NULL;

hr = CoInitialize(NULL);
hr = CoCreateInstance(&CLSID_Recordset, NULL, CLSCTX_ALL, &IID_Recordset15, (void **)&pRst);
if (hr)
MessageBox(0, TEXT("Error CoCreateInstance()"), 0, 0);
else
{
VARIANT v1, v2;
VariantInit(&v1);
v1.vt = VT_BSTR;
v1.bstrVal = SysAllocString(L"SELECT * FROM test");
VariantInit(&v2);
v2.vt = VT_BSTR;
v2.bstrVal = SysAllocString(L"Driver={Microsoft Access Driver (*.mdb)};Dbq=test.mdb;");
// STDMETHOD(Open)(THIS,VARIANT,VARIANT,enum CursorTypeEnum,enum LockTypeEnum,LONG);
hr = pRst->lpVtbl->Open(pRst, v1, v2, adOpenKeyset, adLockUnspecified, adCmdText);
SysFreeString(v1.bstrVal);
SysFreeString(v2.bstrVal);
//hr = pRst->lpVtbl->Open(pRst, v1, v2, 1, -1, -1);
if (!hr) {
Fields* pFlds;
Field* pFld;
long nRecs = 0;
hr = pRst->lpVtbl->get_RecordCount(pRst, &nRecs);
_tprintf(TEXT("nRecs = %d\n"), nRecs);
hr = pRst->lpVtbl->get_Fields(pRst, &pFlds);
if (!hr) {
long nFlds;
VARIANT vIdx;
hr = pFlds->lpVtbl->get_Count(pFlds, &nFlds);
_tprintf(TEXT("nFlds = %d\n"), nFlds);
VariantInit(&vIdx);
vIdx.vt = VT_I4;
for (int i = 0; i < nFlds; i++) {
vIdx.lVal = i;
hr = pFlds->lpVtbl->get_Item(pFlds, vIdx, &pFld);
if (!hr) {
BSTR bstrTmp;
VARIANT v3;
VariantInit(&v3);
v3.vt = VT_BSTR;
v3.bstrVal = bstrTmp;
hr = pFld->lpVtbl->get_Name(pFld, &bstrTmp);
if (!hr) {
_tprintf(bstrTmp);
SysFreeString(bstrTmp);
}
hr = pFld->lpVtbl->get_Value(pFld, &v3);
if (!hr) {
if (v3.vt == VT_BSTR) {
_tprintf(TEXT(" %ls\n"), bstrTmp);
SysFreeString(bstrTmp);
} else {
VariantChangeType(&v3, &v3, VARIANT_LOCALBOOL, VT_BSTR);
_tprintf(TEXT(" %ls\n"), bstrTmp);
SysFreeString(bstrTmp);
}
}
pFld->lpVtbl->Release(pFld);
}
}
pFlds->lpVtbl->Release(pFlds);
}
} else
_tprintf(TEXT("%Xh %ls\n"), hr, GetADOErrorCode(hr));
pRst->lpVtbl->Release(pRst);
}
CoUninitialize();

//MessageBox(0, TEXT("Done"), 0, 0);
return 0;
}
Let me know, if there is something wrong.
« Last Edit: November 25, 2014, 03:38:20 PM by TimoVJL »
May the source be with you

czerny

  • Guest
Re: Example using ado
« Reply #1 on: November 25, 2014, 01:35:34 PM »
If the database doesn't exist, I get: 80004005h Unspecified Error
Shouldn't be used in this case:  800A0F0Bh Database does not exist?

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2115
Re: Example using ado
« Reply #2 on: January 09, 2024, 03:48:25 PM »
A simple ADO test, not useful
Those who have MS Office or AccessDatabaseEngine installed can test it with test.mdb
« Last Edit: January 09, 2024, 03:59:08 PM by TimoVJL »
May the source be with you

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: Example using ado
« Reply #3 on: January 09, 2024, 05:26:49 PM »
Looks good, Timo, and works fine, but how do you get the names of tables after OpenSchema? I tried this:

Code: [Select]
hr = pCon->lpVtbl->OpenSchema(pCon, adSchemaTables, vtCriteria, vtMissing, &pRst);
if (!hr) {
printf("Recordset tables=%i\n", pRst);
printf("Count=%i\n", pRst->GetRows);
pRst->lpVtbl->Release(pRst); // release the _Recordset
printf("Recordset close\n");

Unknown field 'GetRows' of '_Recordset (aka struct _Recordset)'
 :(

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2115
Re: Example using ado
« Reply #4 on: January 09, 2024, 06:33:28 PM »
something like this:
Code: [Select]
hr = pCon->lpVtbl->OpenSchema(pCon, adSchemaTables, vtCriteria, vtMissing, &pRst);
if (!hr) {
Fields* pFlds;
Field* pFld;
long nRecs = 0;
hr = pRst->lpVtbl->get_RecordCount(pRst, &nRecs);
printf("nRecs = %d\n", nRecs);
hr = pRst->lpVtbl->get_Fields(pRst, &pFlds);
if (!hr) {
long nFlds = 0;
hr = pFlds->lpVtbl->get_Count(pFlds, &nFlds);
printf("nFlds = %d\n", nFlds);
VARIANT vIdx;
VariantInit(&vIdx);
vIdx.vt = VT_I4;
for (int i = 0; i < nFlds; i++) {
vIdx.lVal = i;
hr = pFlds->lpVtbl->get_Item(pFlds, vIdx, &pFld);
if (!hr) {
BSTR bstrTmp;
VARIANT v3;
VariantInit(&v3);
v3.vt = VT_BSTR;
v3.bstrVal = bstrTmp;
hr = pFld->lpVtbl->get_Name(pFld, &bstrTmp);
if (!hr) {
printf("%ls\n", bstrTmp);
SysFreeString(bstrTmp);
}
}
pFld->lpVtbl->Release(pFld);
}
pFlds->lpVtbl->Release(pFlds);
}
// done
pRst->lpVtbl->Release(pRst);
printf("Recordset close\n");
}
« Last Edit: January 09, 2024, 06:37:43 PM by TimoVJL »
May the source be with you

Offline Vortex

  • Member
  • *
  • Posts: 864
    • http://www.vortex.masmcode.com
Re: Example using ado
« Reply #5 on: January 09, 2024, 07:38:21 PM »
Hi Timo,

Thanks, both of your applications are processing correctly the database file on Windows 7 Sp1 64-bit.
Code it... That's all...

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: Example using ado
« Reply #6 on: January 09, 2024, 09:10:07 PM »
Hi Timo,
This works fine so far, but it returns as names
 TABLE_CATALOG
 TABLE_SCHEMA
 TABLE_NAME
 TABLE_TYPE
etc. - the labels. What I am really interested in is the value of TABLE_NAME, i.e. the sheet's actual name, e.g. main.

What am I doing wrong here? It compiles with TheValue, but I get error 800a0bcd (EOF or BOF) and a nullstring :(

Code: [Select]
hr = pFld->lpVtbl->get_Name(pFld, &bstrTmp);
if (!hr) {
VARIANT TheValue;
VariantInit(&TheValue);
TheValue.vt = VT_BSTR;
printf("Item %ls\n", bstrTmp);
hr = pFld->lpVtbl->get_Value(pFld, &TheValue);
printf("val %x %ls\n", hr, TheValue.bstrVal);
SysFreeString(bstrTmp);
}

Btw googling for "get_Fields" "get_name" "get_value" "get_RecordCount" puts this post on rank #2 - congrats :)
« Last Edit: January 09, 2024, 09:35:26 PM by jj2007 »

Offline John Z

  • Member
  • *
  • Posts: 860
Re: Example using ado
« Reply #7 on: January 09, 2024, 09:25:22 PM »
Hi TimoVJL,

A simple ADO test, not useful
Those who have MS Office or AccessDatabaseEngine installed can test it with test.mdb

How to test? I tried as posted and tried using the full path to test.mdb.
All I get is:
Code: [Select]
C:\Users\John\Downloads\Pelles\msado>msado_test2_64.exe
adStateClosed
Error count 0

I can open test.mdb with Access and see the table and entries.

Well, worth mentioning this is WIN11

John Z

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: Example using ado
« Reply #8 on: January 09, 2024, 09:39:52 PM »
> using the full path

Hi John,

Try escaping the backslashes: D:\\PellesC\\test.mdb should work, at least it does on my Win10 machine.

@Timo: please see reply #6

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2115
Re: Example using ado
« Reply #9 on: January 09, 2024, 09:51:14 PM »
Hi John Z,
The msado_test2_64.exe won't work, as 64-bit don't have "Microsoft.JET.OLEDB.4.0" working connection string.
For x64 it's something like "Microsoft.ACE.OLEDB.12.0"
If you have 32-bit MS Office, it doesn't help.
« Last Edit: January 10, 2024, 12:59:33 AM by TimoVJL »
May the source be with you

Offline John Z

  • Member
  • *
  • Posts: 860
Re: Example using ado
« Reply #10 on: January 09, 2024, 10:34:56 PM »
Thanks TimoVJL, got it, looks good with the non-64 bit version
running Windows 11 Home, 23H2, OS Build 22631.2861
results:
Code: [Select]
C:\Users\John\Downloads\Pelles\msado>msado_test2.exe
nRecs = -1
nFlds = 9
TABLE_CATALOG
TABLE_SCHEMA
TABLE_NAME
TABLE_TYPE
TABLE_GUID
DESCRIPTION
TABLE_PROPID
DATE_CREATED
DATE_MODIFIED
Recordset close

Thank jj2007 - I did double \ because it would not compile otherwise.  Cheers

John Z

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2115
Re: Example using ado
« Reply #11 on: January 10, 2024, 09:48:51 AM »
With this version:
Code: [Select]
nRecs = -1
TABLE_NAME      test

Recordset close
May the source be with you

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: Example using ado
« Reply #12 on: January 10, 2024, 01:41:46 PM »
Code: [Select]
nRecs = -1
TABLE_NAME      JJWasHere

Recordset close

Compliments, Timo - you are a genius :)

I had played around with the OpenSchema needs a SAFEARRAY problem, without success. Thanks a lot for looking into this.

Code: [Select]
BSTR bstrConStr = SysAllocString(L"Data Source=test.xls;Extended Properties='Excel 8.0;HDR=NO'");
Yields the name of an Excel sheet. Excellent :)

Same for dbf:
Code: [Select]
BSTR bstrConStr = SysAllocString(L"Data Source=.;Extended Properties='dBASE IV'");
The first line causes a linker error for me ("Unresolved external symbol '_GetADOErrorCode'"):
Code: [Select]
//printf("hr=%Xh %ls\n", hr, GetADOErrorCode(hr));
//ADOError(pCon);

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2115
Re: Example using ado
« Reply #13 on: January 10, 2024, 03:49:19 PM »
That ADOErrors.c is in msado_test2_WS1.zip amd msado_test2_WS1.zip, if you need it.
May the source be with you

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: Example using ado
« Reply #14 on: January 12, 2024, 01:41:57 PM »
Here is a list of the connection strings that work for me on Windows 10:
Code: [Select]
; MyCon$ db 'Provider="Microsoft.JET.OLEDB.4.0";Data Source=test2000.mdb', 0
; MyCon$ db 'Provider="Microsoft.JET.OLEDB.4.0";Data Source=testjj5.xls;Extended Properties="Excel 8.0"', 0
; MyCon$ db 'Provider="Microsoft.JET.OLEDB.4.0";Data Source=testjj5.xls;Extended Properties="Excel 8.0;HDR=NO"', 0
; MyCon$ db 'Provider="Microsoft.JET.OLEDB.4.0";Data Source=test2000.mdb', 0 ; ok
; MyCon$ db 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=.;Extended Properties=dBASE IV;', 0 ; ok

Note that the table name for Excel files is kind of boring: it always returns Database
For dBase, in contrast, you can only specify the folder, not a specific file, and it picks files from that folder randomly. Maybe it can be solved with SELECT * from specificfile.xls, I'll have to test that.

Thanks a lot, Timo, for all the work you put into this :)