how to handle excel files using C++? - c++

I'm new to C++, And I want to enter values into an excel spreadsheet using C++, I know we can handle files using fstream but how to get a specific column or row using this method.

If you want to persist in using C++ (despite the comments above), this sample will give you an idea of the coding work needed to use C++ to automate the Excel application (as you might do in VBA or C#) rather than manipulate the file using a known file format (using a third-party library). The sample opens an existing worksheet in the background, adds 1 to the value in cell A1 on Sheet1, and then saves it.
Whether this is a suitable or efficient solution for your case will depend on what exactly you are trying to do with the files.
NB. Only works with the MS Visual Studio compiler.
The hard-coded paths to the import libraries may be different on your computer, and may depend on your Excel version.
//Import all the type libraries
#import "C:\Program Files\Microsoft Office\Root\VFS\ProgramFilesCommonX86\Microsoft Shared\OFFICE16\MSO.dll" \
rename("RGB","RGB_mso") rename("DocumentProperties","DocumentProperties_mso")
using namespace Office;
#import "C:\Program Files\Microsoft Office\root\vfs\ProgramFilesCommonX86\Microsoft Shared\VBA\VBA6\VBE6EXT.OLB"
using namespace VBIDE;
#import "C:\Program Files\Microsoft Office\root\Office16\EXCEL.EXE" \
rename( "DialogBox", "ExcelDialogBox" ) \
rename( "RGB", "ExcelRGB" ) \
rename( "CopyFile", "ExcelCopyFile" ) \
rename( "ReplaceText", "ExcelReplaceText" ) \
exclude( "IFont", "IPicture" )
#include <iostream>
using namespace std;
int main()
{
HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED);
Excel::_ApplicationPtr pXL;
if (FAILED(pXL.CreateInstance("Excel.Application")))
{
cout << "Could not create instance of Excel" << endl;
return 1;
}
try
{
//Uncomment this to see what is going on during each step
//pXL->Visible = true;
Excel::_WorkbookPtr pWb = pXL->Workbooks->Open(L"c:\\temp\\testbook.xlsx");
//Gets number from cell A1 in Sheet1 and increments
Excel::_WorksheetPtr pSheet = pWb->Worksheets->Item[L"Sheet1"];
Excel::RangePtr pRng = pSheet->Cells;
_variant_t val = pRng->Item[1][1];
double dVal{ val };
pRng->Item[1][1] = ++dVal;
pWb->Save();
pWb->Close();
}
catch (_com_error ce)
{
cout << "Something went wrong" << endl;
_bstr_t bstrDesc = ce.Description();
if( ! bstrDesc )
{
cout << " Unknown Error" << endl;
}
else
{
cout << " Error text: " << bstrDesc << endl;
}
}
pXL->Quit();
}
EDIT: In answer to the unspoken question why is it Excel::_ApplicationPtr, Excel::_WorkbookPtr etc, but for a Range it is Excel::RangePtr (no _)? Absolutely no idea.

C++ is probably no the best choice to use if you want to manipulate .xlsx files. You would be better off either using macros in Excel using VBA, or you can write an Excel plugin using VSTO. If you really need to stick with C++, consider if you really need native Excel format. Maybe just .csv file be sufficient.

OpenXLSX is a great library for reading and writing excel sheets using C++. Its API documentation is not in the Github repo. It can be found here. The examples in the repo are quite extensive and detailed. Build instructions are also straightforward.
I have tried it on Linux and Windows (with MinGW). It works great and has the same behavior on both OSs.

Related

Connect To Matlab 2017b from c++ vs2013

I would like to read some variable's value in Matlab from c++. I searched in Internet and found out below example in Matlab Documentation Page.
for using this example I Did below steps:
I add this include path to project :
c:\program files\Matlab\r2017b\extern\include
then I Add this path Library Directory :
c:\program Files\Matlab\r2017b\extern\lib\win64\microsoft
then I Add this library to project :
"libMatlabEngine.lib"
"libMatlabDataArray.lib"
then I placed needed DLLs beside application EXE file.
then I ran the application after that application faced with access violataion error when startMATLAB() Method has been ran.
Note: I had other problem that I resolved it. but I think that problem was very strange and may be knowing that problem help you to find main reason of my problems.
problem was : when I set dll's files path in environment variables my app didn't find dlls and get "no entry point to *.dll" run time error. but when I copy dlls beside of exe, my app saw them.(I restarted VS2013 after change environment variables.)
#include "MatlabDataArray.hpp"
#include "MatlabEngine.hpp"
#include <iostream>
void callgetVars() {
using namespace matlab::engine;
// Start MATLAB engine synchronously
std::unique_ptr<MATLABEngine> matlabPtr = startMATLAB();
// Evaluate MATLAB statement
matlabPtr->eval(convertUTF8StringToUTF16String("[az,el,r] = cart2sph(5,7,3);"));
// Get the result from MATLAB
matlab::data::TypedArray<double> result1 = matlabPtr->
getVariable(convertUTF8StringToUTF16String("az"));
matlab::data::TypedArray<double> result2 = matlabPtr->
getVariable(convertUTF8StringToUTF16String("el"));
matlab::data::TypedArray<double> result3 = matlabPtr->
getVariable(convertUTF8StringToUTF16String("r"));
// Display results
std::cout << "az: " << result1[0] << std::endl;
std::cout << "el: " << result2[0] << std::endl;
std::cout << "r: " << result3[0] << std::endl;
}
I use vs2013 and Matlab 2017b in windows 7.
Thanks for your help.

Listing all files of a directory using C++ in Linux is not working

I used following code.
dp = opendir( dir.c_str() );
while ((dirp = readdir( dp )))
{
filepath = dir + "/" + dirp->d_name;
}
But dirp->d_name value is as follows.
.\000\000\000\004\324E\020\000\000\000\000\000\324!+^S\361Tf\030\000\004..\000\000\004\237X\n\000\000\000\000\000fJ\035\224\321M\264l(\000\bFontTest1.pdf\000\000\000\000\000\000\000\b\236X\n\000\000\000\000\000\377\377\377\377\377\377\377\177(\000\bproject_report.pdf\000\000\b
Are you perhaps mis-handling the "." and ".." dirs? (every dir has them)
I excluded them with:
std::string fn(ent->dname);
if(fn == ".") { if(dbg2) { std::cout << "S_DOT" << std::endl; } continue;}
if(fn == "..") { if(dbg2) { std::cout << "D_DOT" << std::endl; } continue;}
... prior to handling the various d_types
switch(ent->d_type)
{
case DT_UNKNOWN: {...}
case DT_DIR: {...}
// ... etc
}
The "continue" jumped to the beginning of the loop processing dirent entries.
The best cross platform way to do this is if you have the filesystem library. Unfortunately that's still a Technical Specification right now, so you'll need to either use Boost's version of this library or: experimental/filesystem.
Once you have filesystem though you can simply use a directory_iterator:
copy(directory_iterator(dir), directory_iterator(), ostream_iterator<path>(cout, "\n"))
That example may have been a bit complex. If I can clarify something for you let me know.
In Visual Studio 2015 this code runs if you simply #include <filesystem> and do using namespace tr2::sys. Unfortunately gcc 5.3 hasn't implemented directory_iterator.operator++() yet, so you'll need Boost there or you'll get an error along the lines of:
Undefined reference to std::experimental::filesystem::v1::__cxx11::directory_iterator::operator++()
Thanks all. I am able to sort it out by adding following code.
unsigned char isFile =0x8;
if ( dirp->d_type == isFile)
//process it

How to read and write Excel via COM object together with Excel instance manual operating

I am trying to read and write Excel via COM.
And on the same time , I also want to modify the cell value manually .
It seems there is an access conflict.
How can I detect this conflict and avoid it/
The following is my code example.
In the example, a do-loop will keep copying cell A1 value to cell A2.
when I want to modify the value A1 manualy during COM running, error occurs and program exits.
//MicroSoft Office Objects
#import "C:\Program Files (x86)\Common Files\microsoft shared\OFFICE12\mso.dll"\
rename("DocumentProperties","DocumentPropertiesXL")\
rename("RGB","RBGXL")
//Microsoft VBA Objects
#import "C:\Program Files (x86)\Common Files\microsoft shared\VBA\VBA6\vbe6ext.olb"
//EXCEL application objects
#import "C:\Program Files (x86)\Microsoft Office\Office12\excel.exe" \
rename("DialogBox","DialogBoxXL") \
rename("RGB","RGBCL") \
rename("DocumentProperties","DocumentPropertiesXL")\
rename("ReplaceText","ReplaceTextXL") \
rename("CopyFile","CopyFileXL") \
exclude("IFont","IPicture") no_dual_interfaces
#include "stdafx.h"
#include <iostream>
int main(int argc, _TCHAR* argv[])
{
//A try block is used to trap any errors in communication
try
{
//Initialize COM interface
CoInitialize(NULL);
Excel::_ApplicationPtr XL;
//Start the Excel Application
XL.CreateInstance(L"Excel.Application");
//Make the Excel Application visible, so that we can see it!
XL->Visible=true;
Excel::_WorkbookPtr pWorkbook;
pWorkbook=XL->Workbooks->Open(L"D:\\test.xls");
//Get a pointer to the active worksheet
Excel::_WorksheetPtr pSheet = pWorkbook->Sheets->Item[L"Sheet1"];
//Get a pointer to the cells on the active worksheet
Excel::RangePtr pRange = pSheet->Cells;
pRange->Item[1][1]=20;
int a;
//perform a loop to copy value in A1 to A2
do
{
a=pRange->Item[1][1];
std::cout<<"a="<<a<<std::endl;
pRange->Item[2][1]=a;
}while(a>0);
}
//If a communication error is thrown, catch it and complain
catch(_com_error)
{
std::cout<<"COM error "<<std::endl;
}
//Finally Uninitialise the COM interface
CoUninitialize();
//Finish the C++ program
return 0;
}
I have solved this problem by using COM directly but not OLE
after reading freddie1's article http://www.cplusplus.com/forum/windows/125996/
Thanks anyway.

"Access violation" Error on displaying string of simple Oracle Query (VS10 Exp C++)

I am struggling with an issue regarding running a SQL statement to an Oracle database through C++, using occi. My code is as follows:
#include <iostream>
#include "occi.h"
namespace oc = oracle::occi;
int main() {
std::cout << "Setting up environment...\n";
oc::Environment * env = oc::Environment::createEnvironment();
std::cout << "Setting up connection...\n";
oc::Connection * conn = env->createConnection("user","pass","server");
std::cout << "Creating statement...\n";
//Very simply query...
oc::Statement * stmt = conn->createStatement("SELECT '1' FROM dual");
std::cout << "Executing query...\n";
oc::ResultSet * rs = stmt->executeQuery();
while(rs->next()) {
std::cout << rs->getString(1) << std::endl; //Error is thrown at this line, but after printing since I can see '1' on the console.
}
stmt->closeResultSet(rs);
conn->terminateStatement(stmt);
env->terminateConnection(conn);
oc::Environment::terminateEnvironment(env);
return 0;
}
The error that is shown is:
Unhandled exception at 0x1048ad7a (msvcp100d.dll) in MyDatabaseApp.exe: 0xC0000005: Access violation reading location 0xccccccd0.
My program stops inside 'xstring' at the following line of code:
#if _ITERATOR_DEBUG_LEVEL == 0
....
#else /* _ITERATOR_DEBUG_LEVEL == 0 */
typedef typename _Alloc::template rebind<_Elem>::other _Alty;
_String_val(_Alty _Al = _Alty())
: _Alval(_Al)
{ // construct allocator from _Al
....
}
~_String_val()
{ // destroy the object
typename _Alloc::template rebind<_Container_proxy>::other
_Alproxy(_Alval);
this->_Orphan_all(); //<----------------------Code stops here
_Dest_val(_Alproxy, this->_Myproxy);
_Alproxy.deallocate(this->_Myproxy, 1);
this->_Myproxy = 0;
}
#endif /* _ITERATOR_DEBUG_LEVEL == 0 */
If I change my query to:
oc::Statement * stmt = conn->createStatement("SELECT 1 FROM dual");
and the loop statement to:
std::cout << rs->getInt(1) << std::endl;
It works fine with no errors. I think this is because getting an integer simply returns a primitive, but when an object is being returned it is blowing up (I think on a destructor, but I'm not sure why...)
I have been playing around with this for hours today, and I am pretty stuck.
Some information about my system:
OS - Windows XP
Oracle Version - 10g
IDE - Microsoft Visual Studio 2010 Express C++
My project properties are as follows:
C/C++ - General - Additional Include Directories = C:\oracle\product\10.2.0\client_1\oci\include;%(AdditionalIncludeDirectories)
C/C++ - Code Generation - Multi-threaded Debug DLL (/MDd)
Linker - General - Additional Library Directories = C:\oracle\product\10.2.0\client_1\oci\lib\msvc\vc8;%(AdditionalLibraryDirectories)
Linked - Input - Additional Dependencies = oraocci10.lib;oraocci10d.lib;%(AdditionalDependencies)
I hope I haven't been confusing with too much info... Any help or insight would be great, Thanks in advance!
EDIT If I rewrite my loop, storing the value in a local variable, the error is thrown at the end of the loop:
while(rs->next()) {
std::string s = rs->getString(1); //s is equal to "1" as expected
std::cout << s << std::endl; //This is executed successfully
} //Error is thrown here
Usually such kind of problems come from differences in build environments (IDE) of end user and provider.
Check this.
Related problems:
Unhandled exception at 0x523d14cf (msvcr100d.dll)?
Why does this program crash: passing of std::string between DLLs
First try to use correct lib and dll. If compiled in debug mode then all libs and dlls must be debug. Use VC++ Modules view to be sure that proper DLL loaded.
I was lucky with my application to have all libs compiled for MSVC2010. So I just check debug and release mode DLLs and got working application.
I revisited this issue about a month ago and I found that the MSVC2010 occi library was built for Oracle 11g. We are running Oracle 10g, so I had to use the MSVC2005 library. So I installed the outdated IDE and loaded the Debug library and it worked (for some reason the release version wouldn't work though).
EDIT
For anyone who is having the same problem I was, if downgrading the IDE from MSVC2010 to MSVC2005 with the appropriate libraries doesn't work, you could try upgrading the Oracle client from 10g to 11g and use the MSVC2010 library, as suggested by harvyS. In retrospect this would've probably been the better solution.

Connecting to MS Access database using C++ using Visual Studio 2008

I need some serious help trying to connect to an Access database using VS 2008's C++. I have done this in C# but I cant figure this out in C++. I need to use C++ for the connection because I am grabbing data using pre-compiled C++ code. I would really appreciate some help with this. Thanks
I would like to odbc, but if you have another recommendation then I could change my mind.I am trying to connect to an Access database, the Northwind sample database, by following this example,
http://msdn.microsoft.com/en-us/library/cc811599.aspx
I am using a Windows 7 OS with Visual C++ 2008 for the compiler and IDE. The program is a console application. This example is specified for Access 2007 .accdb file types. Once I get it running correctly I will switch the path name, queries, and table names to my database. Below is the code that fails to build. I don't know what is causing this:
Includes-->
fstream
cmath
complex
iostream
iomanip
vector
limits
stdlib.h
stdio.h
time.h
fcntl.h
string.h
ctype.h
icrsint.h
using namespace std;
#import C:\\Program Files\\Common Files\\system\\ado\\msado15.dll rename("EOF",
"AdoNSEOF")
_bstr_t bstrConnect="Provider=Microsoft.ACE.OLEDB.12.0;Data "
"Source=C:\\Users\\lriley\\Documents\\Northwind 2007.mdb;";
HRESULT hr;
int main()
{
::CoInitialize(NULL);
const char* DAM = "ADO";
ADODB::_ConnectionPtr pConn("ADODB.Connection");
hr = pConn->Open(bstrConnect, "admin", "", ADODB::adConnectUnspecified);
if(SUCCEEDED(hr))
{
cout<<DAM<<": Successfully connected to database. Data source name:\n "
<<pConn->GetConnectionString()<<endl;
// Prepare SQL query
_bstr_t query = "SELECT Customers.[Company], Customers.[First Name] FROM "
"Customers;";
cout <<DAM<<": SQL query \n "<<query<<endl;
// Execute
ADODB::_RecordsetPtr pRS("ADODB.Recordset");
hr = pRS->Open(query,
_variant_t((IDispatch *) pConn, true),
ADODB::adOpenUnspecified,
ADODB::adLockUnspecified,
ADODB::adCmdText);
if(SUCCEEDED(hr))
{
cout<<DAM<<": Retrieve schema info for the given result set: "<< endl;
ADODB::Fields* pFields = NULL;
hr = pRS->get_Fields(&pFields);
if(SUCCEEDED(hr) && pFields && pFields->GetCount() > 0)
{
for(long nIndex=0; nIndex < pFields->GetCount(); nIndex++)
{
cout << " | "<<_bstr_t(pFields->GetItem(nIndex)->GetName());
}
cout << endl;
}
else
{
cout << DAM << ": Error: Number of fields in the " <<
"result is set to zero." << endl;
}
cout<<DAM<<": Fetch the actual data: " << endl;
int rowCount = 0;
while (!pRS->AdoNSEOF)
{
for(long nIndex=0; nIndex < pFields->GetCount(); nIndex++)
{
cout<<" | "<<_bstr_t(pFields->GetItem(nIndex)->GetValue());
}
cout<< endl;
pRS->MoveNext();
rowCount++;
}
cout<<DAM<<": Total Row Count: " << rowCount << endl;
}
pRS->Close();
pConn->Close();
cout<<DAM<<": Cleanup Done" << endl;
}
else
{
cout<<DAM<<" : Unable to connect to data source: "<<bstrConnect<<endl;
}
::CoUninitialize();
return 0;
}
I recieve the following error when I try to build it:
fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add #include "stdafx.h" to your source?
c:\users\lriley\documents\visual studio 2008\projects\test12\test12\test12.cpp
Any help would be appreciated.
Thanks
Dante
Well, it's been a while, but you are going to need something like: http://msdn.microsoft.com/en-us/library/ms714562%28v=vs.85%29.aspx, look at SQLConnect..., a lot of variations to a theme, but the 2nd parameter is basically the path to your access db (*.mdb) file.
good luck.
You just have to give in file properties *. Cpp
-> Precompiled Header-No Precompiled Headers
Use precompiled header file - Stdafx.h xxxx