|

Author's Note
This article was written based on Access '97 (I believe) and I haven't updated it since. It will probably not work with other versions of Access but I welcome others to update the code to work with newer versions of Access.
Introduction
This class (CAccessReports) was created for those of us who have the misfortune of having to 1) use the MS Access database engine and 2) use the MS Access database engine from a Visual C++ application. The CAccessReports class uses the Access Automation objects to open a specified database, run a report (within Access), print the report and save the Access database in HTML format so that it can be viewed in a Visual C++ application. You can accomplish each of these tasks with a single line of code. Here are some examples of how to use the CAccessReports class.
Examples of how to use the CAccessReports class
When you download the source code for the CAccessReports, you will also find a full-fledged test application. However, it's always nice to be able to see what you're getting before you invest the time in downloading, unzipping and running someone else's code. Therefore, here are some code snippets that show how easy the CAccessReports class is to use.
Instantiating a CAccessReports object
How you choose to instantiate CAccessReports object depends on how you plan to use it in your application. The first argument of the CAccessReports is the fully qualified name of the database file. The second argument specifies whether you want the CAccessReports class to preload all of the report names. An example of when you would want the class to retrieve all of the report names is if your application needs to display a list of the reports to the end-user. Otherwise, if you are instantiating a CAccessReports object in order to run, print or display specific reports whose names are known at compile-time, you can pass a value of FALSE for this argument.
CAccessReports accessReports(YOUR_ACCESS_DATABASE, TRUE);
CAccessReports accessReports(YOUR_ACCESS_DATABASE, FALSE);
Getting a List of Reports from an Access Database
If you specified a value of TRUE for the second argument of the CAcessReport constructor, you can then retrieve the list of reports for a given Access database. Here's an example of a simple loop to retrieve and display all of the report names.
CAccessReports accessReports(YOUR_ACCESS_DATABASE, TRUE);
for (int i = 0; i < accessReports.m_reports.GetSize(); i++)
{
AfxMessageBox(accessReports.m_reports[i]);
}
Running an Access Report
While the CAccessReports class does allow you to display an Access report from a Visual C++ application (shown below), there are still valid reasons to run the report from within Access. Therefore, the RunReport member function does exactly that.
CAccessReports accessReports(YOUR_ACCESS_DATABASE, FALSE);
accessReports.RunReport(YOUR_REPORT_NAME);
Printing an Access Report
The PrintReport function takes as its only argument the name of a report to print. This function calls RunReport and then uses Automation to print the report.
CAccessReports accessReports(YOUR_ACCESS_DATABASE, FALSE);
accessReports.PrintReport(YOUR_REPORT_NAME);
Displaying an Access Report (Visual C++ 6.0)
Access Automation doesn't allow for the ability to redirect the output of a report to a given window. However, it does allow for a report to be run and then saved in HTML format. That combined with the new Visual C++ 6.0 CHtmlView gives you the ability to run an Access report and display it in a Visual C++ application. In the example below, CAccessReportView is a CHtmlView derived class.
void CAccessReportView::OnInitialUpdate()
{
CHtmlView::OnInitialUpdate();
CAccessReports accessReports(YOUR_ACCESS_DATABASE, FALSE);
accessReports.SaveAsHtml(YOUR_REPORT_NAME, DESTINATION_FOLDER);
Navigate2(FULLY_QUALIFIED_FILE_NAME, NULL, NULL);
}
Displaying an Access Report (Visual C++ 5.0)
Unfortunately, Visual C++ 5.0 does not have the CHtmlView class. However, you can still display Access reports using the WebBrowser control (in the Visual C++ Component Gallery). In order to display the Access report in a Visual C++ 5 application, simply instantiate a CAccessReports object, call its SaveAsHtml member function and then call the WebBrowser control's Navigate function specifying the name of the HTML file.
Access Automation can not be used to get the entire list of reports for a an Access database. Therefore, if you specify TRUE to the second argument of the CAccessReports constructor, the class attempts to use the MFC DAO classes to access the msysobjects table of the specified database. In order to accomplish this, you must give the Admin user "read" priveleges to the database's msysobjects table (see below). If your application is printing or viewing a specific report from a specific database and you don't need the list of reports, then this limitation does not apply. If anyone knows of a better way of doing this, I'm always open to learning new things :)
Granting access to the MS Access MSysObjects table
- Open Microsoft Access
- From the Tools menu, select the Options menu option
- On the View tab, click the System Objects checkbox
- Click OK to save your changes
- From the Tools menu, select the Security -> User and Group Permissions menu option
- Click the Permissions tab
- Select the Table entry in the Object Type combo box
- Select the Admin userid in the User/Group Name listbox
- In the Object Name listbox, select the MSysObjects entry
- In the Permissions group box, check the Read Data check box
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 25 (Total in Forum: 25) (Refresh) | FirstPrevNext |
|
|
 |
|
|
not sure where to start. cant find the error string or where its flaged I get this error with all your code. compiles fine yet it cant undestand my databse using MSAccess 2000 (9.0.2720)
Waas up widat ??
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
This was something I wrote almost 10 years ago using Access '97 (I believe) and I haven't updated it since. Unless someone else wants to update it to work with subsequent versions of Access, I'll ask the CP editors to take it down as it's way out of date and not something I have time to update.
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
I can remove it if you want but I'd much rather leave it and maybe place a note at the top along the lines of "Only works with Access '97. Anyone care to update it?"
What do you think?
cheers, Chris Maunder CodeProject.com : C++ MVP
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
I downloaded the demo project named CAccessReports. I also have placed my mdb file in the very same location as the project. But I get an error when I run my application saying "Record(s) can't be read. No read permission on MSysObjects". I did as instructed in the article, to grant access to the MSAccess MSysObjects table, but the error still occurs. Could anybody help me solve this error.
Expecting a reply at the earliest.
Thanking you in advance.
Kind Regards Lavinia
|
| Sign In·View Thread·PermaLink | 2.00/5 (3 votes) |
|
|
|
 |
|
|
Hello, i download the accessAutomation projet. And when i compile this, i have these errors. (i have Visual c++ 6 and Ms access 2003). Can you help me please!
Compiling... Access.cpp D:\download\AccessAutomationFromVBAndVC\Chip\NewChip\AccessAutomation\Access.cpp(79) : error C2664: 'lstrcpyW' : cannot convert parameter 1 from 'char [255]' to 'unsigned short *' Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast D:\download\AccessAutomationFromVBAndVC\Chip\NewChip\AccessAutomation\Access.cpp(81) : error C2664: 'Open' : cannot convert parameter 1 from 'char [255]' to 'const unsigned short *' Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast D:\download\AccessAutomationFromVBAndVC\Chip\NewChip\AccessAutomation\Access.cpp(93) : error C2664: 'int __thiscall COleDispatchDriver::CreateDispatch(const struct _GUID &,class COleException *)' : cannot convert parameter 1 from 'char [21]' to 'con st struct _GUID &' Reason: cannot convert from 'char [21]' to 'const struct _GUID' No constructor could take the source type, or constructor overload resolution was ambiguous D:\download\AccessAutomationFromVBAndVC\Chip\NewChip\AccessAutomation\Access.cpp(94) : error C2664: 'AfxTrace' : cannot convert parameter 1 from 'char [37]' to 'const unsigned short *' Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast Error executing cl.exe.
AccessAutomation.dll - 4 error(s), 0 warning(s)
hervy
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
THX a lot - Great Article! (Helped me much in understanding Automation etc.. too) former I used DDE to access these functions, but now I prefer this way
But I run in troubles using MSysObjects-Table. I never got access to it (even cant find it in MS ACCESS security options) so I use the following solution(shown without any try/catch etc.)
_CurrentProject cp(m_pAccess->GetCurrentProject()); Reports rps(cp.GetAllReports()); for (long i=0; i{ _Report rp = rps.GetItem(COleVariant(i)); m_reports.Add(rp.GetName()); } It seems to work.
using m_pAccess->GetReports() did not work anyhow. I got a Reports() object but the GetCount() always return 0.
Hope this my help someone ...
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
Does someone know how to do things described in this article but using ADO instead of DAO.
Thanks for any help.
cybz55
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
The demo project works fine, with no problems. However, I wanted to use the Access 2000 DB. So I made the modifications suggested in the thread somewhere below.
After the modifications, now I'm getting the following errors: error C2660: 'OpenCurrentDatabase' : function does not take 2 parameters error C2660: 'OpenReport' : function does not take 4 parameters error C2660: 'OutputTo' : function does not take 6 parameters
Understandably, the functions used for Access 97 format takes fewer arguments than the newer functions in Access 2000 format. Any idea about how to get rid of these errors. Any pointers about the extra parameters to be passed into these functions would be greatly appreciated.
Thanks for any help.
Naveen.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
As I primarily use SQL Server and Oracle, I haven't had a need to update this since I wrote it about 6 years ago.
If someone else has the time and inclination to update the code to work with Access 2000, then I'd be happy to give them credit here and update the article.
Cheers, Tom Archer Inside C#, Extending MFC Applications with the .NET Framework It's better to listen to others than to speak, because I already know what I'm going to say anyway. - Jörgen Sigvardsson
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
Hi, I'm a newbie to VC++. I wanted to test out this really cool program in my own app. So I created a new project using the MFC Appwizard(exe), dialog based.
I then added the "AccessReports", "AccessReportsSet", "msacc8" .cpp & .h files to the project.
Then in the Initinstance(), I added the following lines:
CAccessReports accessReports(YOUR_ACCESS_DATABASE, FALSE); accessReports.SaveAsHtml(YOUR_REPORT_NAME, DESTINATION_FOLDER);
Where the YOUR_ACCESS_DATABASE, YOUR_REPORT_NAME, DESTINATION_FOLDER where replaced by proper arguments. When I tried to compile program I got these errors:
error C2065: 'CAccessReports' : undeclared identifier error C2146: syntax error : missing ';' before identifier 'accessReports' error C2065: 'accessReports' : undeclared identifier
Please guide me as to how to proceed. Your help would be very much appreciated.
Thank you Naveen.
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
Looks like you didn't include the header file. With you being that new to VC++, I would recommend that you either start with the demo project and modify it to suit your needs or use the demo project to compare to your code when something doesn't work in your own project.
Cheers, Tom Archer Inside C#, Extending MFC Applications with the .NET Framework It's better to listen to others than to speak, because I already know what I'm going to say anyway. - Jörgen Sigvardsson
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I am printing reports from a database that is protected by a workgroup file. Is there a way to pass the /user and /pwd information when calling OpenCurrentDatabase()? I keep getting error message "database is missing or opened exclusively by another user"
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I wrote this for a gig at AT&T about 6 years ago for Access '97 and don't even know what a "workgroup file" is. Sorry, but what you see here is the extent of my knowledge about automating Access as this got the job done and I've not had reason to use Access since.
Cheers, Tom Archer, Inside C# Mainstream is just a word for the way things always have been -- just a middle-of-the-road, tow-the-line thing; a front for the Man serving up the same warmed-over slop he did yesterday and expecting you to say, "Thank you sir, may I have another?"
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Wow... that was a fast response. Looks like we are both working hard here in ATL... Unfortunately, I think I just found the answer on a VB site...
Automation does not allow you to specify a different MDW file along with a new username and password when opening a secured database from code. One way to get around this limitation is to Shell out to the secured mdb whiile specifying all necessary information through command line parameters.
'************* Code Start ***************** Sub sOpenDBWithPwd() Dim strDB As String Dim strCmd As String Dim objSecuredDB As Access.Application strDB = "J:\NewCode97.mdb" strCmd = SysCmd(acSysCmdAccessDir) & "\MSAccess.exe " _ & strDB & " /wrkgrp " & DBEngine.SystemDB _ & " /user Admin" '/pwd ''" Call Shell(strCmd, vbNormalFocus) DoEvents: DoEvents: DoEvents Set objSecuredDB = GetObject(strDB) Stop End Sub
I'll post it in case others are trying to do the same. Looks like I may be experimenting with shell commands in lieu of automation.
Love the Inside C# book btw... Thanks for the response.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
That's too bad. But at least you have a direction now.
Also, coolness on the Inside C# book helping you!!
Cheers, Tom Archer, Inside C# Mainstream is just a word for the way things always have been -- just a middle-of-the-road, tow-the-line thing; a front for the Man serving up the same warmed-over slop he did yesterday and expecting you to say, "Thank you sir, may I have another?"
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Does any know how to obtain the primary key information for a given table in access 2000? The MDAC ODBC driver does not implement the SQLPrimaryKeys function. I am not using DOA, RDO or ADO objects, nor am I developing in VB. I would need a query to select the keys from each table, if it is possible.
Thanks, Jason Jennings jasonj@equitrac.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
This source code is GREAT and I cannot tell you how relieved I am to find something this slick and clean. My question is this .. my report comes off a query in access, I would like to pass a parameter to the query that generates the data for the report. Currently I have the query hard coded to find a specific value and have a number of other queries set up that I passed params to, but not in this instance (from the report viewer) and am a bit unsure of the most effect way to go about it. Any and all help is appreciated
Thanks
Todd
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
Thanks for the kind words, Todd. Did you ever find an solution to your problem? If so, let me know and we'll update the article with proper credit going to you for your contributions.
Cheers, Tom Archer, Inside C# Mainstream is just a word for the way things always have been -- just a middle-of-the-road, tow-the-line thing; a front for the Man serving up the same warmed-over slop he did yesterday and expecting you to say, "Thank you sir, may I have another?"
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
To get it to work for access 2000 first read the following article: http://support.microsoft.com/support/kb/articles/Q236/9/91.ASP
Then in the project remove all references to msacc8.h and msacc8.cpp.
Go the class wizard (crtl+w) and click on the automation tab. Therefater insert a new class from a type library and select the following file: c:\program files\microsoft office\office\msacc9.olb Thereafter select the classes you wish to add to your application. (I just added averything).
Then you just need to change the following line(s) in accessreports.h line 3 from #include "msacc8.h" to #include "msacc9.h"
and line 18 from IDoCmd* m_pDoCmd; to DoCmd* m_pDoCmd;
and then change the following line 30 in accessreports.cpp from2 m_pDoCmd = new IDoCmd(lpDispDoCmd); to m_pDoCmd = new DoCmd(lpDispDoCmd);
Finally add the following line to your program:
AfxGetModuleState()->m_dwVersion = 0x0601;
I put it in the first line of the constructor: CAccessReports::CAccessReports(CString const& strDatabaseName, BOOL bLoadAllReports)
Be sure that you are using mfc in a shared dll. (To get it to work for static dll read the article stated above).
And viola you got it working for access2000
|
| Sign In·View Thread·PermaLink | 3.00/5 (2 votes) |
|
|
|
 |
|
|
Hi! Thank your for posting that tip, it's great help! However, I still can't get it to work properly, not even the demo app. I granted the access to msSysObjects as the article says, did everything your post says, but it keeps causing an unhandled exceptiona at:
InvokeHelperV(dwDispID, wFlags, vtRet, vRet, pbParamInfo, argList); inside [oleDisp2.cpp] in COleDispatchDriver::InvokeHelper
called by InvokeHelper(0x85c, DISPATCH_METHOD, VT_EMPTY, NULL, parms, filepath, Exclusive); inside [msacc9.cpp] in _Application::OpenCurrentDatabase()
called by m_pAccess->OpenCurrentDatabase(strDatabaseName, FALSE); inside [AccessReports.cpp] in CAccessReports::CAccessReports()
The same result if I use an Access97 format database. I have only access 2000 installed.
Does anyone knows what can be causing this and how can this be fixed? This code is just awesome, I want to use it! ^_^
Thanx in advance for any reply  later!
|
| Sign In·View Thread·PermaLink | 2.50/5 (2 votes) |
|
|
|
 |
|
|
 |
|
|
How could I implement an ODBC report to see data from an SQL Server 7.0 database using Visual C++ 6.0? We are developing a client application to manage a database. We connect to database througt ODBC driver and we are having problems with printed reports. Now we are looking for a class, library or whatever that can help us to do them in an easy way. We are not worried about price. If it is free, great but if not it doesn't matter. If you know something about this, please contact us. Thank you.

Luis
|
| Sign In·View Thread·PermaLink | 2.00/5 (2 votes) |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|