ODBC Connection via CDatabase fails with connection string from previous succesfull connection - c++

I'm a bit clueless at the moment what the problem is with this code.
It trows a exception of type CDBException when trying to connect with the given ODBC Connect String and never comes back from .OpenEx - the lower message boxes never display.
There is a message from the ODBC Driver that states that the DSN isnt specified and that no default driver is found.
The Message Box that shows the connect string gives a good looking string - as it should, coming from a working connection
ODBC;DSN=DBTEST;Trusted_Connection=Yes;APP=XXX;WSID=NEUROMANCER;DATABASE=master;
Same problem when using SA/Password for the connection
ODBC;DSN=DBTEST_PW;UID=SA;PWD=password;APP=XXX;WSID=NEUROMANCER;DATABASE=master;
After reading other posts I added "DRIVER=" to the beginning and "SERVER=localhost;" to the end but that changed nothing. Resulting tested connection strings where
DRIVER=ODBC;DSN=DBTEST;Trusted_Connection=Yes;APP=XXX;WSID=NEUROMANCER;DATABASE=master;
DRIVER=ODBC;DSN=DBTEST;Trusted_Connection=Yes;APP=XXX;WSID=NEUROMANCER;DATABASE=master;SERVER=localhost
DRIVER=ODBC;DSN=DBTEST_PW;UID=SA;PWD=password;APP=XXX;WSID=NEUROMANCER;DATABASE=master;
DRIVER=ODBC;DSN=DBTEST_PW;UID=SA;PWD=password;APP=XXX;WSID=NEUROMANCER;DATABASE=master;SERVER=localhost
I also made sure to use the 32bit ODBC Admin tool to generate the system DSNs for the 32bit application.
If I replace "CDatabase::NoOdbcDialog" with "0" it opens the ODBC-Dialog again as if informations necessary to open the connection are missing.
db.OpenEx(NULL, CDatabase::forceOdbcDialog);
CString cstmp;
if (db.IsOpen()) {
cstmp = db.GetConnect();
db.Close();
}
MessageBox(cstmp, _T(""), MB_OK);
if (db.OpenEx(cstmp, CDatabase::noOdbcDialog )) { //Exception here CDBException at 0x004FDD9
MessageBox(_T("Connection success!"), _T("Connection"), MB_OK);
db.Close();
}
else {
MessageBox(_T("Connection failed!"), _T("Connection"), MB_OK);
}
Can anyone tell me where my problem is?

Related

WMI Query for SQL Server FilestreamSettings

Based on what I can find on the internet this doesn't seem to be something a lot of people do but I'm pretty stuck so I'm going to put it out here. I'm using WMI in C++ to try to manipulate SQL Server settings. I have the following code that doesn't return a result from my WMI query and I'm at a loss as to why:
hr = pLoc->ConnectServer(CComBSTR(L"root\\Microsoft\\SqlServer\\ComputerManagement10"), // Object path of WMI namespace
NULL, // User name. NULL = current user
NULL, // User password. NULL = current
0, // Locale. NULL indicates current
NULL, // Security flags
0, // Authority (e.g. Kerberos)
0, // Context object
&pSvc);
// ----- Check for success and set proxy blanket here -----
IEnumWbemClassObject* pClassEnum = 0;
hr = pSvc->ExecQuery(_bstr_t("WQL"), _bstr_t("SELECT * FROM FilestreamSettings"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pClassEnum);
if (SUCCEEDED(hr) && pClassEnum)
{
ULONG uReturn = 0;
while (pClassEnum && !myInstanceFound)
{
hr = pClassEnum->Next(WBEM_INFINITE, 1, &pObjInstance, &uReturn);
if (0 == uReturn || !pObjInstance)
{
break;
}
// Get the value of the InstanceName property - the SQL Server instance name
CComVariant vtProp;
hr = pObjInstance->Get(L"InstanceName", 0, &vtProp, 0, 0);
if (SUCCEEDED(hr) && (VT_BSTR) == vtProp.vt)
{
if (vtProp.bstrVal == _bstr_t('MyInstance'))
{
myInstanceFound = true;
}
}
}
.
.
.
}
The ExecQuery command succeeds. The pClassEnum enumerator object is not null, so the while loop executes. The call to 'Next', however, does not return an object (pObjectInstance is null) and &uReturn is 0 (which, as I understand it means that the call to 'Next' returned 0 results). However, if I run the same query in the wbemtest tool, I get two results (which is correct, as I have 2 SQL Server instances on this machine). I have limited C++ skills and this is my first time with WMI. Not only do I not see what's wrong here, I'm not even sure what else to try. The few code samples I've seen suggest this code should be correct. Any help would be greatly appreciated!
Thanks,
Dennis
Update: The call to Next() actually returns S_FALSE. Which, if I'm reading the docs correctly, mostly just confirms the issue of not getting a result. Next() returns S_FALSE if there are less than the number of requested results (in my case, less than 1 - or in other words, 0).
Update #2: This same code does work on my laptop (well, the Next() call does anyway). Differences are: Does work on my laptop - Win 10, Sql Server 2019 (have to change namespace to be ComputerManagement15 instead of 10), FileStream already enabled. Does not work - Win 7 VM, Sql Server 2008, FileStream not enabled. A query using Wbemtest tool gets the correct data in both cases. Just thought I'd post in case this helps.
FYI, in case anyone stumbles across this: I didn't technically solve this, in that I never got my C++ code to work. I wrote some C# code using SQL Server Management Objects (basically a wrapper over WMI) and made it into a COM server that I could call from C++. Even this didn't work directly because my C# COM server kept getting an "Access Denied" even if I ran the C++ COM client application as Administrator. What eventually worked was to extract the SSMO code out into its own C# console app which I then ran from my C# COM server as its own process using the "run as" verb so it would run as Administrator. This finally managed to enable Filestream on my SQL Server instance. It's possible there was a better/easier way to get this done but I found something that worked (although it was pretty kludgy). So if there's a chance this helps anyone else, I'm putting it out there.

Cannot make connection to SQL Server via ODBC

In the past, I have used ADO to access SQL Server, the connection string for the ADO connection object is:
Provider=sqloledb;Data Source=MYPC;Integrated Security=SSPI;
where MYPC is the name of my computer, and SQL Server is installed on my computer as the default instance.
The above connection string works well.
However, now it is said that ADO is outdated and ODBC is recommended again by Microsoft (see https://blogs.msdn.microsoft.com/sqlnativeclient/2011/08/29/microsoft-is-aligning-with-odbc-for-native-relational-data-access/ ), so I have to modify my code to use ODBC instead.
So I changed the connection to SQL Server to the following code:
CDatabase Database;
// Provider=sqloledb;Data Source=MYPC;Integrated Security=SSPI;
Database.OpenEx(_T("Driver = {SQL Native Client}; Server = MYPC; Trusted_Connection = yes;"), CDatabase::noOdbcDialog);
Database.ExecuteSQL(_T("create database [MyDB2019] on primary (name=[MyDB2019_File],filename='F:\\MyDB2019.mdf')"));
Database.Close();
However, this code does not work. After executing Database.OpenEx, there will be a CDBException indicating
Data source name not found and no default driver specified.
Why?
Note: I am using Visual C++ 2008 and ADO
The error/exception is pointing to the problem (albeit it seems a bit generic at first).
"Data source name not found and no default driver specified"
Data source name not found --> You did not specify a DSN, you do not
want to use a DSN, ignore this part
.
and no default driver specified --> You intend to use a driver, so this part of the error most likely applies to you.
The connection string appears syntactically correct: "Driver={Driver Name}...", so the next
step is to check whether the driver you try to use, named SQL Native Client, exists
on your machine.
"SQL Native Client" was/is the driver name for SQL Server 2005.
From SQL2008 the driver name got a version descriptor.
Driver={SQL Native Client} ,sql2005
Driver={SQL Server Native Client 10.0} ,sql2008
Driver={SQL Server Native Client 11.0} ,sql2012 and later
Driver={ODBC Driver 11 for SQL Server} ,sql2012 and later, odbc appears in the name
Driver={ODBC Driver 13 for SQL Server}
Driver={ODBC Driver 17 for SQL Server}
An easy way to find the installed 'SQL Native' and 'ODBC Driver for SQL Server' drivers on your machine, would be to run the ODBC Data Source Administrator. Type Odbc data sources in your search box or odbcad32.exe in the command/address bar (for 64bit: %windir%\system32\odbcad32.exe)
When in ODBC Data Source Administrator, switch to the Drivers tab and there you will find all the available/installed drivers, at your disposal.
Here is a powershell script that opens a connection to localhost using odbc. Adjust accordingly to your installed driver(s)
cls
$conn = new-object system.data.odbc.odbcconnection
$conn.connectionstring =
# all these installed on my pc and working
#"Driver={SQL Server Native Client 11.0};Server=localhost; Database=master;Trusted_Connection=yes;"
#"Driver={SQL Server};Server=localhost; Database=master;Trusted_Connection=yes;"
#"Driver={ODBC Driver 11 for SQL Server};Server=localhost; Database=master;Trusted_Connection=yes;"
"Driver={ODBC Driver 17 for SQL Server};Server=localhost; Database=master;Trusted_Connection=yes;"
$conn.Open()
$conn.State
$conn.Close();
..and an mfc button
void CMFCDBTestDlg::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
CDatabase database;
CString connectionstring = _T("Driver={SQL Server Native Client 10.0};Server=localhost;Trusted_Connection=yes;");
CString messagetext;
TRY{
//database.Open(NULL, FALSE, FALSE, connectionstring, FALSE); //ok
database.OpenEx(connectionstring, CDatabase::noOdbcDialog); //ok
if (database.IsOpen()){
messagetext = _T("open, database:") + database.GetDatabaseName();
database.Close();
}
}CATCH(CDBException, e) {
messagetext = _T("Database error: ")+e->m_strError;
}
END_CATCH;
AfxMessageBox(messagetext, 0, 0);
}
Create a file with udl extension. Example: test.udl
Double click the file. Use the GUI to connect to your database. Once done, open the UDL file using notepad and extract the connection string.
See https://www.dmxzone.com/go/312/how-to-generate-an-ado-connection-string/
The problem comes from the extra spaces in the connection string, after removing extra spaces from:
"Driver = {SQL Native Client}; Server = MYPC; Trusted_Connection = yes;"
to(and change the driver name as well):
"Driver={SQL Server Native Client 10.0};Server=MYPC;Trusted_Connection=yes;"
The connection will succeed.

Unable to connet to SQL server using soci library

I am beginner in c++,my problem on Linux for connecting to SQL Server with soci library, my code this but I have error and I don't found solution for my problem, my code this:
I have error:
[unixODBC][Driver Manager]Data source name not found, and no default driver specified (SQL state IM002)
Here is the code:
try{
soci::session sql("odbc","DSN=ODBC;UID=sa;PWD=sa123; Connection Driver=TDS;Database=ReportServer; Server=192.168.1.52;Port=1433;");
}
catch(soci::odbc_soci_error const & e){
cout<<"start error";
cout<<e.odbc_error_code()<<endl;
cout<<e.what();
}
Your ODBC connection string in incorrect, your first parameter specifies a datasource called "ODBC", which you haven't configured in your operating system/odbc manager.
So either you should configure a data source with the given parameters like UID=sa;PWD=sa123; Connection Driver=TDS;Database=ReportServer; Server=192.168.1.52;Port=1433; with the corresponding ODBC data source manager/linux administration program, with a useable name like "local_test_db" and just use "DSN=local_test_db" as your connection string
or (exclusive or)
remove the "dsn=ODBC" part from your connection string and try it again with "UID=sa;PWD=sa123; Connection Driver=TDS;Database=ReportServer; Server=192.168.1.52;Port=1433;"

FTPPutFile triguring firewall issues causing falure

I'm quite inexperienced in C++, and i'm trying to make a project, that can simply upload files from client PC's, to my plainFTP server. However, i'm noting that by default windows firewall is blocking this communication (I tested on both a PC in our active directory and outside to same result).
This is my code
void doUpload(char *LocFile, char *Rfile){
//LocFile must come with path e.g. C:\\helloworld.txt
//Rfile is the name of the file on the remote server. hi.txt
char *user="<FTPUSER>";
char *pass="<FTPPASS>";
char *ftpserver="<FTPIP>";
HINTERNET hInternet;
HINTERNET hFtpSession;
hInternet = InternetOpen(NULL,INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
hFtpSession = InternetConnect(hInternet,ftpserver , INTERNET_DEFAULT_FTP_PORT, user, pass, INTERNET_SERVICE_FTP, 0, 0);
//doupload
if(FtpPutFile(hFtpSession, LocFile, Rfile,FTP_TRANSFER_TYPE_BINARY,INTERNET_FLAG_PASSIVE)){
print("Upload Worked!");
Sleep(1000);
InternetCloseHandle(hFtpSession);
InternetCloseHandle(hInternet);
}
else{cout << "FAILED UPLOAD\n";cout << LocFile;cout << Rfile;}
}
The LocFile is the local file to be uploaded, and Rfile is the name to give it on the FTP server.
Interestingly even if i enable it in the firewall it seems to fail, but my main question is, is there a way to do this that will bypass the firewall/use an already permitted handle and shall not cause me to have to mess with the firewall rules in group policy (Even this would be an issue, as some computers are not in active directory)?
I know this is possibly with winsock, however in codeblocks i can't get winsock working, and i've never used it, and so would take more time than i have to code. If possible, i am looking for compatibility with windows XP up to 8.
EDIT:
I've added some more debug information, and the PC out of the Active directory is getting a timed out error, and my computer, in the AD is getting the following from internetgetlastmessage as error code 12 12003
200 Switching to Binary mode.
500 Illegal PORT command.
500 Unknown command.

can't connect to database by executable file

i wrote a program that need to connect to database to insert some data , my executable file not connect to database but when i checked with code connection established! i don't know what is problem , do you know what is problem?
i use Qt to connect to database and my database is on mySql and here is how i connect :
soccer_db = QSqlDatabase::addDatabase("QMYSQL" , "sss");
soccer_db.setHostName(addrrFile.c_str());
soccer_db.setDatabaseName("sss");
soccer_db.open();
if (!soccer_db.open()){
emit dsignal("ssss not opened. Ckech whether server is down or change config file");
return false;
}
You are getting a failure because you try to open the database twice. The first attempt succeeds but the second one fails. Remove the first call to open, like this
soccer_db = QSqlDatabase::addDatabase("QMYSQL" , "sss");
soccer_db.setHostName(addrrFile.c_str());
soccer_db.setDatabaseName("sss");
if (!soccer_db.open()){
emit dsignal("ssss not opened. Ckech whether server is down or change config file");
return false;
}
i want to answer my question, in qt you should address your files completely not relative address, if you need to address completely you can give current directory by QtDir