Problems getting SQLBindParameter to work in C++ - visual-c++

I downloaded a small sample program in C++ that opens an ODBC connection to SQL Server, issues a query, and prints the result.
When the query string includes a parameter and I call SQLBindParameter, the query execution returns SQL_SUCCESS but subsequentally fails to get any records.
If I do the equivalent query directly in SQL Management studio it works.
Here's the code. Note that to keep things short I have removed error checking in places where I've not been having problems. The real connection string is obfuscated.
SQLHANDLE sqlenvhandle = 0;
SQLHANDLE sqlconnectionhandle = 0;
SQLHANDLE sqlstatementhandle = 0;
SQLHANDLE sqlstatementhandle2 = 0;
SQLRETURN retcode = 0;
SQLWCHAR retconstring[1024];
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &sqlenvhandle);
retcode = SQLSetEnvAttr(sqlenvhandle,SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
retcode = SQLAllocHandle(SQL_HANDLE_DBC, sqlenvhandle, &sqlconnectionhandle);
retcode = SQLDriverConnect(sqlconnectionhandle, NULL, (SQLWCHAR*)_T("--connectionstring--"),
SQL_NTS, retconstring, 1024, NULL, SQL_DRIVER_NOPROMPT);
retcode = SQLAllocHandle(SQL_HANDLE_STMT, sqlconnectionhandle, &sqlstatementhandle2);
SQLWCHAR *query = _T("SELECT * FROM gbm_models WHERE stagename like ?");
SQLWCHAR *searchname = _T("Yuk%\0");
retcode = SQLPrepare (sqlstatementhandle2, query, SQL_NTS);
SQLINTEGER xxx = SQL_NTS;
retcode = SQLBindParameter( sqlstatementhandle2, 1, SQL_PARAM_INPUT, SQL_C_CHAR,
SQL_VARCHAR, 5, 0, searchname, 0, &xxx );
SQLWCHAR sqlbuffer[400];
SQLINTEGER buflen = 0;
retcode = SQLExecute (sqlstatementhandle2);
char name[512];
int id;
while(SQLFetch(sqlstatementhandle2) == SQL_SUCCESS)
{
SQLGetData(sqlstatementhandle2, 1, SQL_C_ULONG, &id, 0, NULL);
SQLGetData(sqlstatementhandle2, 4, SQL_C_CHAR, name, 500, NULL);
cout << id << " " << name << endl;
}
SQLFreeHandle(SQL_HANDLE_STMT, sqlstatementhandle2 );
SQLFreeHandle(SQL_HANDLE_STMT, sqlstatementhandle );
SQLDisconnect(sqlconnectionhandle);
SQLFreeHandle(SQL_HANDLE_DBC, sqlconnectionhandle);
SQLFreeHandle(SQL_HANDLE_ENV, sqlenvhandle);
None of these calls return an error. What happens is that the call to SQLFetch returns SQL_NO_DATA. If I replace the "?" in the initial query string with the actual name string, and comment out the SQLBindParameter call, it works fine and retrieves the expected data. So obviously, the search string is not making its way into the query correctly.
Any ideas what's wrong? Does anybody know a way to get the processed query string with the parameter substitution done? I thought the SQLNativeSql function did that, but when I call it, I just get back the original query, so I'm not sure if it's working right or what. Could it be a Unicode thing?

See the datatypes at http://msdn.microsoft.com/en-us/library/windows/desktop/ms714556(v=vs.85).aspx
SQL_C_CHAR is not compatible with the SQLWCHAR so your binding fails to do a proper job - it is using a pointer to double-byte wide characters and a resulting "C-string" is not what you'd expect it to be.
Use compatible datatypes, in your case just go with:
SQLCHAR *searchname = "Yuk%";

Related

Strange behaviour on MFC Thread

I'm new here, but always found help in the past.
I'm facing a strange problem with a simple block of code:
UINT ThreadMain(LPVOID pParam)
{
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
THREADDATA* pData = (THREADDATA*) pParam;
INT* pnEditBoxValue = pData->pnEditBoxValue;
UINT nEid = pData->nEditId;
PLC *parent = (PLC*)pParam;
bool trigger_basso = false;
m_thread_running = 1;
CDeCoMotorDlg* wnd = pData->pObjDlg;
while(m_keep_alive==1)
{
SleepEx(1, 0);
wnd->CheckDlgButton(nEid, TRUE);
}
m_thread_running = 0;
return 0;
}
The problem seems related to this line:
wnd->CheckDlgButton(nEid, TRUE);
The lines works well (a check box is set on the gui), BUT, if I press a button on my GUI that sets the
m_keep_alive = 0
then the function stop working immediately: I don't see the while loop terminating properly and I never reach this line:
m_thread_running = 0;
What's strange is the if I remove this line
wnd->CheckDlgButton(nEid, TRUE);
the while loop exits properly, the flag is set and the thread exit properly...
I'm getting crazy...any suggestion?
Many thanks

Calculate message digest for TSA for CMS_sign prior to CMS_final

I have code to create CMS signature. It worked well now I need to add trusted timestamping.
BIO *data_output = BIO_new(BIO_s_mem());
const EVP_MD *sign_md = EVP_get_digestbyname(digest_name);
cms = CMS_sign(NULL, NULL, NULL, bio_in, flags);
BOOST_ASSERT(cms);
for (size_t i = 0; i < m_signers.size(); i++) {
int tflags = flags;
SignerInfo si = m_signers[i];
CMS_SignerInfo *signer_info = CMS_add1_signer(cms,
si.m_x509, si.m_privateKey, sign_md, tflags);
BOOST_ASSERT(signer_info != NULL);
for (int c = 0; c < sk_X509_num(si.m_ca); c++) {
X509* cert = sk_X509_value(si.m_ca, c);
BOOST_ASSERT(CMS_add0_cert(cms, cert) != 0);
}
}
BOOST_ASSERT(CMS_final(cms, bio_in, NULL, flags) != 0);
BOOST_ASSERT(i2d_CMS_bio_stream(data_output, cms, bio_in, flags) != 0);
In order to talk to TSA, I need the digest value but there is no way to get the digest value until CMS_final is called. I could not locate the answer anywhere.
id-aa-timeStampToken is an unsigned attribute. If your implementation has no hooks to modify the message afterwards you can do it in two passes. Do call final, get the hash and send it to the TSA. Then build a second identical CMS and add an unsigned id-aa-timeStampToken attibute (OID 1.2.840.113549.1.9.16.2.14). Paste the timestampToken in there and call final.
Be aware that using a timestamp usually requires a SIGNED attribute signing-time Pkcs9SigningTime (OID 1.2.840.113549.1.9.5) so save the time used on the first pass to get two identical CMS messages.
It is a bit cheap but it does the job. If you neeed to ask for a pin on a Smart card it will ask two times.

Waitformultipleobjects returns invalid handle

The code is below and it is part of a thread. pFileChange->m_hDirectory is of type HANDLE and pFileChange->m_eventFileChange if of type CEvent. CreateFile and ReadDirectoryChangesW return with a success. I am not able to figure out why i am getting an invalid handle status, please help!
UINT CFileChange::FileMontiorThread(LPVOID pArgs)
{
CFileChange* pFileChange = NULL;
pFileChange = (CFileChange*)pArgs;
pFileChange = (CFileChange*)pArgs;
CString str = pFileChange->m_strDirectory;
LPSTR strDirectory;
strDirectory = str.GetBuffer(str.GetLength());
PathRemoveFileSpec(strDirectory);
DWORD dwBytes = 0;
vector<BYTE> m_Buffer;
BOOL m_bChildren;
OVERLAPPED m_Overlapped;
HANDLE arrHandles[2] = { pFileChange->m_hDirectory, pFileChange->m_eventFileChange };
::ZeroMemory(&m_Overlapped, sizeof(OVERLAPPED));
DWORD dwBufferSize = 16384;
m_Buffer.resize(dwBufferSize);
m_bChildren = false;
pFileChange->m_hDirectory = ::CreateFile(
(LPCSTR)(LPCTSTR)strDirectory,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OVERLAPPED,
NULL);
if (pFileChange->m_hDirectory == INVALID_HANDLE_VALUE)
{
return false;
}
BOOL success = ::ReadDirectoryChangesW(
pFileChange->m_hDirectory, // handle to directory
&m_Buffer[0], // read results buffer
m_Buffer.size(), // length of buffer
m_bChildren, // monitoring option
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_FILE_NAME, // filter conditions
&dwBytes, // bytes returned
&m_Overlapped, // overlapped buffer
NULL); // no completion routine
DWORD dwWaitStatus;
while (!pFileChange->m_bKillThread)
{
dwWaitStatus = WaitForMultipleObjects(2, arrHandles, FALSE, INFINITE);
Switch(dwWaitStatus)
{
case WAIT_FAILED:
{
ULONG rc = 0;
rc = ::GetLastError();
LPVOID lpMsgBuf = NULL;
::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
rc,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&lpMsgBuf,
0,
NULL);
CString strErrMsg;
strErrMsg.Format(_T("%s, %s, Reason:%s"), "", "", (LPTSTR)lpMsgBuf);
break;
}
}
}
return 0;
}
Note that, as it specifies in the documentation, you can't wait on any type of handle.
Waiting on a directory handle isn't going to do what you think it should. Read this related question and its answers for more information and background reading.
As it seems you're trying to create a folder monitor, perhaps read this blog post for the correct way to use ReadDirectoryChangesW.
The answer was provided by Hans Passant in a comment:
You copy the handles into arrHandles too soon, before they are created. That cannot work of course.

Resources getting deleted when trying to add at run time

When i am trying to add resources to another file at run time, some of the earlier resources are getting deleted. Please find the source code below:
void CResourceIncludeSampleDlg::OnBnClickedButton1()
{
CString strInputFile = _T("C:\\SampleData\\FileToInsert.zip"); // This File is 100 MB
HANDLE hFile = CreateFile(strInputFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD FileSize = GetFileSize(hFile, NULL);
BYTE *pBuffer = new BYTE[FileSize];
DWORD dwBytesRead;
ReadFile(hFile, pBuffer, FileSize, &dwBytesRead, NULL);
for (int iIndex = 1; iIndex <= 4; iIndex++)
{
InsertResource(FileSize, iIndex, pBuffer);
}
CloseHandle(hFile);
}
void CResourceIncludeSampleDlg::InsertResource(DWORD FileSize, int iIndex, BYTE *pBuffer)
{
CString strOutputFile = _T("C:\\SampleData\\ResourceIncludeSample_Source.exe");
int iResourceID = 300 + iIndex;
HANDLE hResource = BeginUpdateResource(strOutputFile, FALSE);
if (INVALID_HANDLE_VALUE != hResource)
{
if (UpdateResource(hResource, _T("VIDEOBIN"), MAKEINTRESOURCE(iResourceID), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
(LPVOID)pBuffer, FileSize) == TRUE)
{
EndUpdateResource(hResource, FALSE);
}
}
}
After completion of the execution, i am expecting output as 301, 302, 303 and 304 added under "VIDEOBIN" category. But only 2 (sometimes 3) resources are present. One resource is always deleted.
Could you please let me know what could be wrong or any fix for the same ?
Any help or sample source code is greatly appreciated.
Thanks and Regards,
YKK Reddy
You need delete[] pBuffer after closing the file. It should be RT_RCDATA instead of _T("VIDEOBIN") although custom resource name may not be the cause of this particular problem.

No sound output with WASAPI

I am having trouble with WASAPI. It do not output any sound and I have been checked the data that writing to the buffer.
Because of it does not output any sound, I haven't any idea to find out the problem.
It may have some problems in following code.
SoundStream::SoundStream() : writtenCursor(0), writeCursor(0), distroy(false)
{
IMMDeviceEnumerator * pEnumerator = nullptr;
HResult(CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, IID_PPV_ARGS(&pEnumerator)));
IMMDevice * pDevice = nullptr;
HResult(pEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &pDevice));
SafeRelease(&pEnumerator);
HResult(pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient));
SafeRelease(&pDevice);
WAVEFORMATEXTENSIBLE * pwfx = nullptr;
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC * 2;
HResult(pAudioClient->GetMixFormat((WAVEFORMATEX**)&pwfx));
HResult(pAudioClient->Initialize(
AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
hnsRequestedDuration,
0,
(WAVEFORMATEX*)pwfx,
NULL));
pAudioClient->SetEventHandle(hEvent);
channel = (size_t)pwfx->Format.nChannels;
bits = (size_t)pwfx->Format.wBitsPerSample;
validBits = (size_t)pwfx->Samples.wValidBitsPerSample;
frequency = (size_t)pwfx->Format.nSamplesPerSec;
buffer.reshape({ 0, channel, bits >> 3 });
CoTaskMemFree(pwfx);
HResult(pAudioClient->GetBufferSize(&bufferFrameCount));
HResult(pAudioClient->Start());
if (pAudioClient)
{
thread = std::thread([&]()
{
this->Sync();
});
}
}
You could look at my WASAPI.cpp code at http://jdmcox.com (which works fine).
You should also check if the expected wave format is float:
//SubFormat 00000003-0000-0010-8000-00aa00389b71 defines KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
//SubFormat 00000001-0000-0010-8000-00aa00389b71 defines KSDATAFORMAT_SUBTYPE_PCM
GUID G;
WORD V;
WAVEFORMATEX *pwfx = NULL;
bool itsfloat;
pAudioClient->GetMixFormat(&pwfx);
// Do we received a WAVEFORMATEXTENSIBLE?
if(pwfx.cbSize >= 22) {
G = ((WAVEFORMATEXTENSIBLE*)pwfx)->SubFormat;
V = ((WAVEFORMATEXTENSIBLE*)pwfx)->Samples.wValidBitsPerSample;
if (G.Data1 == 3) itsfloat = true;
else if (G.Data1 == 1) itsfloat = false;
}
You know you received a WAVEFORMATEXTENSIBLE and not a simple WAVEFORMATEX because the "pwfx.cbSize >= 22".
See more at:
IAudioClient::GetMixFormat
https://learn.microsoft.com/en-us/windows/win32/api/audioclient/nf-audioclient-iaudioclient-getmixformat
WAVEFORMATEXTENSIBLE
https://learn.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-waveformatextensible
You could look at my WASAPI.cpp code at http://jdmcox.com AGAIN.
Now it works in shared mode as well as exclusive mode.
I should note that no conversion of wave format or wave is necessary in shared mode -- Windows takes care of both converting to and from their format used to mix waves.

Resources