mciSendString, searching something similar to command "wait" - c++

I´m trying to play a mp3 song after another from a list, the problem is that "wait" command "freeze" all the program until all the songs finish, and what I want is the other functions, as "pause" or "stop", to still work while the song is playing. I don´t have any trouble when I play one song individually.
I read some documentation and it looks like "status" command is the solution, but I don´t understand how to use it.
Here is the code of "case IDC_Play:"
if ((SendDlgItemMessage(hDlg, IDC_CHECK1, BM_GETSTATE, NULL, NULL)) == BST_CHECKED)
{//here goes the code for play only one song}
else {
int cuenta = SendDlgItemMessage(hDlg, IDC_LIST1, LB_GETCOUNT, NULL, NULL);
int indice = 0;
while (indice != cuenta) {
char auxi[10] = "";
UINT index = SendDlgItemMessage(hDlg, IDC_LIST1, LB_GETCURSEL, 0);
SendDlgItemMessage(hDlg, IDC_LIST1, LB_GETTEXT, index, (LPARAM)auxi);
if (strcmp(auxi, "") == 0) {
MessageBox(NULL, "No se selecciono cancion", "ERROR", MB_ICONERROR);
}
else {
char Cnum[10];
aux = inicio;
aux = aux->sig;
do {
_itoa_s(aux->folio, Cnum, 10);
if (strcmp(auxi, Cnum) == 0) {
strcpy_s(szFileName, aux->mptres);
bmp1 = (HBITMAP)SendDlgItemMessage(hDlg, IDC_Imagen1, STM_GETIMAGE, IMAGE_BITMAP, 0);
bmp2 = (HBITMAP)LoadImage(NULL, aux->imagen, IMAGE_BITMAP, 140, 120, LR_LOADFROMFILE);
SendDlgItemMessage(hDlg, IDC_Imagen1, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bmp2);
}
else {
aux = aux->sig;
}
} while (strcmp(auxi, Cnum) == -1 || strcmp(auxi, Cnum) == 1);
ShowWindow(GetDlgItem(hDlg, IDC_Play1), SW_HIDE);
ShowWindow(GetDlgItem(hDlg, IDC_Pause1), SW_SHOW);
char comillas[MAX_PATH] = "\"";
char comillas2[MAX_PATH] = "\"";
strcat_s(comillas, szFileName);
strcat_s(comillas, comillas2);
char musica[MAX_PATH] = "open ";
strcat_s(musica, comillas);
strcat_s(musica, " type mpegvideo");
mciSendString(musica, NULL, 0, 0);
char musica1[MAX_PATH] = "play ";
char esperar[MAX_PATH] = " wait";
strcat_s(musica1, comillas);
strcat_s(musica1, esperar);
mciSendString(musica1, NULL, 0, 0);
char parar[MAX_PATH] = "stop ";
strcat_s(parar, comillas);
mciSendString(parar, NULL, 0, 0);
char cerrar[MAX_PATH] = "close ";
strcat_s(cerrar, comillas);
mciSendString(cerrar, NULL, 0, 0);
index++;
SendDlgItemMessage(hDlg, IDC_LIST1, LB_SETCURSEL, index, NULL);
SendDlgItemMessage(hDlg, IDC_LIST2, LB_SETCURSEL, index, NULL);
SendDlgItemMessage(hDlg, IDC_LIST3, LB_SETCURSEL, index, NULL);
SendDlgItemMessage(hDlg, IDC_LIST4, LB_SETCURSEL, index, NULL);
SendDlgItemMessage(hDlg, IDC_LIST5, LB_SETCURSEL, index, NULL);
indice = index;
} //else
} //while
}//else

Maybe you should use MM_MCINOTIFY flag and callback to avoid the blocking call that freezes the whole application?
Please see an example of using the callback and flag there at CodeProject: http://www.codeproject.com/Articles/17279/Using-mciSendString-to-play-media-files

Related

How to write and calculate hash of a file without closing it in between

I'm trying to calculate MD5 of a file right after writing it:
std::wstring filePath = L"file.txt";
auto hFile = CreateFile(
filePath.c_str(),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
//writing to file with WriteFile(hFile, buffer, DWORD(size), &written, NULL))
Now if I close it and reopen it's OK.
But I'm trying to calculate MD5 without closing it.
To be sure that pointer is set to correct position, I also tried to save a pointer to file's end:
LARGE_INTEGER liOfs = {0};
LARGE_INTEGER liNew = {0};
SetFilePointerEx(hFile, liOfs, &liNew, FILE_CURRENT);
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
auto md5 = CalculateMd5(hFile); // md5 is correct here
// restore pointer
SetFilePointerEx(hFile, liNew, NULL, FILE_BEGIN);
CloseHandle(hFile);
So, I'm getting exception at CloseHandle(hFile): 0xC0000008: An invalid handle was specified.
And there is MD5 calculating:
std::string GetMD5HashOfFile(HANDLE hFile)
{
if (INVALID_HANDLE_VALUE == hFile) {
return {};
}
HCRYPTPROV hProv = 0;
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
return {};
}
HCRYPTHASH hHash = 0;
if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
CryptReleaseContext(hProv, 0);
return {};
}
static constexpr int BUFSIZE = 1024;
DWORD cbRead = 0;
BYTE rgbFile[BUFSIZE];
BOOL bResult = FALSE;
while (bResult = ReadFile(hFile, rgbFile, BUFSIZE, &cbRead, NULL)) {
if (0 == cbRead) {
break;
}
if (!CryptHashData(hHash, rgbFile, cbRead, 0)) {
CryptReleaseContext(hProv, 0);
CryptDestroyHash(hHash);
return {};
}
}
if (!bResult) {
CryptReleaseContext(hProv, 0);
CryptDestroyHash(hHash);
return {};
}
static constexpr int MD5LEN = 16;
CHAR rgbDigits[] = "0123456789abcdef";
BYTE rgbHash[MD5LEN];
DWORD cbHash = MD5LEN;
if (CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0)) {
std::ostringstream oss;
for (auto c : rgbHash) {
oss.fill('0');
oss.width(2);
oss << std::hex << static_cast<int>(c);
}
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return oss.str();
}
else {
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return {};
}
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return {};
}
Here is the test program:
#include <Windows.h>
#include <wincrypt.h>
#include <iostream>
#include <sstream>
int main()
{
const std::wstring filePath = L"test.txt";
auto r = DeleteFile(filePath.c_str());
if (!r) {
auto e = GetLastError();
if (e != ERROR_FILE_NOT_FOUND) {
std::cout << e << '\n';
return -1;
}
}
auto hFile = CreateFile(filePath.c_str(),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if (hFile == INVALID_HANDLE_VALUE) {
return -1;
}
DWORD written = 0;
const std::wstring buffer = L"Hello, world.";
const auto size = buffer.length() * sizeof(wchar_t);
if (!WriteFile(hFile, buffer.c_str(), size, &written, NULL)) {
CloseHandle(hFile);
return -1;
}
if (size != written) {
CloseHandle(hFile);
return -1;
}
/*CloseHandle(hFile);
hFile = CreateFile(filePath.c_str(),
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);*/
LARGE_INTEGER liOfs = { 0 };
LARGE_INTEGER liNew = { 0 };
SetFilePointerEx(hFile, liOfs, &liNew, FILE_CURRENT);
auto md5 = GetMD5HashOfFile(hFile);
std::cout << "MD5: " << md5 << '\n';
SetFilePointerEx(hFile, liNew, NULL, FILE_BEGIN);
CloseHandle(hFile);
return 0;
}
It doesn't throw exception. But it somehow calculates incorrect hash: app's MD5 is d41d8cd98f00b204e9800998ecf8427e, and cmd tool shows another - 1207b6ae90980a5b039d57384b8bbd26. If I uncomment lines in the middle hashes are equal, but still no exception. Command to check hash is:
certutil -hashfile test.txt MD5
UPDATE: I'm really sorry. It's a third question where I cann't debug my app properly. Actually, the file was closed twice, hence the exception. I swear, I'll try to do something with myself).
The only question left: is it possible to calculate file hash properly, because without closing the file handle in between gives a wrong hash.

How to get files on the whole drive

I have written a code to iterate over the drive to find the file of specific extension and if the file is fount it'll be added to the list box but the code fails its iteration when it finds a directory. The iteration stops with the files not the directories. I want my program to search the file with a given extension even in the directories and sub-directories what shall I do?
here is my code
The variable buffer seen in my code is nothing but the drive string e.g H:\
count = 0;
int Class::countOfDocuments(wchar_t buffer[10])
{
wchar_t driveString[MAX_PATH + 1] = { 0 };
wcsncat_s(driveString,260,buffer,260);
wcsncat_s(driveString, 260, L"*doc", 260);
WIN32_FIND_DATA documents;
HANDLE hFind; bool var = true;
hFind = FindFirstFile(driveString, &documents);
if (INVALID_HANDLE_VALUE == hFind)
{
wchar_t* no = L"No documents found";
SendMessage(list1, LB_ADDSTRING, NULL, (LPARAM)no);
for (int i = 0; i <= 10; i++)
{
SendMessage(cprogress, PBM_SETRANGE, 0, i);
SendMessage(cprogress, PBM_SETSTEP, (WPARAM)1, 0);
SendMessage(cprogress, PBM_STEPIT, 0, 1);
}
return count = -1;
}
else
{
wchar_t* Yes = L"Document found";
perform = true;
SendMessage(list1, LB_ADDSTRING, NULL, (LPARAM)Yes);
while (var = FindNextFile(hFind, &documents) == TRUE)
{
count++;
}
for (int i = 0; i <= count; i++)
{
SendMessage(cprogress, PBM_SETRANGE, 0, i);
SendMessage(cprogress, PBM_SETSTEP, (WPARAM)1, 0);
SendMessage(cprogress, PBM_STEPIT, 0, 1);
wchar_t* doc = L"Document found";
SendMessage(list1, LB_ADDSTRING, NULL, (LPARAM)doc);
}
wchar_t* z = L"search complete";
SendMessage(list1, LB_ADDSTRING, NULL, (LPARAM)z);
}
return count;
}

Manipulating Windows Registry

I want every time my program runs make this process:
1- Check if there is a windows registry key called "foo"
2- If it not exists create with the value 10
3- If it exists decrement its value
4- If its value == 0 close de program
I know that i will use this functions, but i don't know how to use them:
RegCreateKeyA, RegSetValueExA
The function to create the key worked, but I can not to set the values and do not know how to do what I need.
HKEY key;
RegCreateKeyA(HKEY_CURRENT_USER,"foo",&key);
RegOpenKeyExA(HKEY_CURRENT_USER,"foo", 0, KEY_ALL_ACCESS, &key);
RegSetValueExA(key,"bar",0,REG_DWORD,(LPBYTE)10,sizeof(10));
Try something like this:
HKEY key;
DWORD disposition;
LONG lRet = RegCreateKeyEx(HKEY_CURRENT_USER, TEXT("foo"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, &key, &disposition);
if (lRet != 0)
{
// error handling...
}
else
{
DWORD value;
if (disposition == REG_CREATED_NEW_KEY)
{
value = 10;
lRet = RegSetValueEx(key, TEXT("bar"), 0, REG_DWORD, (LPBYTE)&value, sizeof(value));
if (lRet != 0)
{
// error handling...
}
}
else
{
DWORD size = sizeof(value);
lRet = RegQueryValueEx(key, TEXT("bar"), NULL, NULL, (LPBYTE)&value, &size);
if (lRet != 0)
{
// error handling...
}
else
{
if (value != 0)
{
--value;
lRet = RegSetValueEx(key, TEXT("bar"), 0, REG_DWORD, (LPBYTE)&value, sizeof(value));
if (lRet != 0)
{
// error handling...
}
}
if (value == 0)
{
// signal app to terminate...
}
}
}
RegCloseKey(key);
}

How to copy such bitmap to a DC?

I'm writing a remote controlling program with GUI.
Here's a part of the server code:
HDC desktopHdc = GetDC(NULL);
int bm_x = GetDeviceCaps(desktopHdc, HORZRES);
int bm_y = GetDeviceCaps(desktopHdc, VERTRES);
DWORD bmSize = ((bm_x * 32 + 31) / 32) * bm_y * 4;
HDC memHdc = CreateCompatibleDC(desktopHdc);
HBITMAP bitmap = CreateCompatibleBitmap(desktopHdc, bm_x, bm_y);
while(TRUE)
{
SelectObject(memHdc, (HGDIOBJ)bitmap);
HANDLE hDIB = GlobalAlloc(GHND, bmSize);
char* bmbits = (char*)GlobalLock(hDIB);
BitBlt(memHdc, 0, 0, bm_x, bm_y, desktopHdc, 0, 0, SRCCOPY);
GetBitmapBits(bitmap, bmSize, bmbits);
int bytes = send(secondarySocket, bmbits, bmSize, 0);
if(bytes == 0 || bytes == -1)
{
MessageBox(NULL, "disconnected", "", 0);
break;
}
GlobalUnlock(hDIB);
GlobalFree(hDIB);
Sleep(1000);
}
And here's some client code:
HDC windowHdc = GetDC(hwnd);
HDC memHdc = CreateCompatibleDC(windowHdc);
// bm_x and bm_y are sent by the server and received by the client
DWORD bmSize = ((bm_x * 32 + 31) / 32) * bm_y * 4;
while(TRUE)
{
HANDLE hDIB = GlobalAlloc(GHND, bmSize);
char* buf = (char*)GlobalLock(hDIB);
int bytes = recv(mainSocket, buf, bmSize, 0);
if(bytes == 0 || bytes == -1)
{
MessageBox(NULL, "disconnected", "", 0);
break;
}
else
{
buf[bytes] = '\0';
HBITMAP bmp = CreateCompatibleBitmap(memHdc, bm_x, bm_y);
SetBitmapBits(bmp, bmSize, buf);
SelectObject(memHdc, bmp);
BitBlt(windowHdc, 0, 0, bm_x, bm_y, memHdc, 0, 0, SRCCOPY); // should copy received bitmap to the window DC
}
GlobalUnlock(hDIB);
GlobalFree(hDIB);
}
I receive whole buffer in the client correctly. I make a bitmap from it. And then I just can't copy it to the window DC - nothing appears. How can I do that?
EDIT
Here's my new code:
DWORD thServerSend(LPVOID param)
{
HDC memHdc = CreateCompatibleDC(desktopHdc);
HBITMAP bitmap;
while(TRUE)
{
BITMAPINFO bmi;
ZeroMemory(&bmi,sizeof(BITMAPINFO));
bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth=bm_x;
bmi.bmiHeader.biHeight=bm_y;
bmi.bmiHeader.biPlanes=1;
bmi.bmiHeader.biBitCount=32;
char* bmbits;
bitmap = CreateDIBSection(memHdc, &bmi, DIB_RGB_COLORS, (void**)&bmbits, NULL, 0);
HBITMAP restore = (HBITMAP)SelectObject(memHdc, (HGDIOBJ)bitmap);
BitBlt(memHdc, 0, 0, bm_x, bm_y, desktopHdc, 0, 0, SRCCOPY);
int bytes = send(secondarySocket, bmbits, bmSize, 0);
if(bytes == 0 || bytes == -1)
{
MessageBox(NULL, "disconnected", "", 0);
break;
}
std::cout << "bmsize: " << bmSize << " bytes: " << bytes << " bmbits: " << bmbits << std::endl; // for debugging
SelectObject(memHdc, restore);
DeleteObject(bitmap);
Sleep(1000);
}
DeleteDC(memHdc);
DeleteObject(bitmap);
shutdown(mainSocket, SD_BOTH);
shutdown(secondarySocket, SD_BOTH);
return 0;
}
DWORD thClient(LPVOID param) // window handle is passed through "param" parameter
{
HDC windowHdc = GetDC((HWND)param);
HDC memHdc = CreateCompatibleDC(windowHdc);
HBITMAP restore;
while(TRUE)
{
BITMAPINFO bmi;
ZeroMemory(&bmi,sizeof(BITMAPINFO));
bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth=bm_x;
bmi.bmiHeader.biHeight=bm_y;
bmi.bmiHeader.biPlanes=1;
bmi.bmiHeader.biBitCount=32;
char* buffer;
HBITMAP bitmap = CreateDIBSection(windowHdc, &bmi, DIB_RGB_COLORS, (void**)&buffer, NULL, 0);
int bytes = recv(mainSocket, buffer, bmSize, 0);
if(bytes == 0 || bytes == -1)
{
MessageBox(NULL, "Disconnected.", "", 0);
break;
}
else
{
restore = (HBITMAP)SelectObject(memHdc,bitmap);
BitBlt(windowHdc, 0, 0, bm_x, bm_y, memHdc, 0, 0, SRCCOPY);
std::cout << "bmsize: " << bmSize << " bytes: " << bytes << " bmbits: " << buffer << std::endl; // for debugging
SelectObject(memHdc, restore);
}
}
DeleteDC(memHdc);
return 0;
}
EDIT 2
Problem solved:
That is, how I called the threads:
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thClient, (PVOID)&hwnd, 0, NULL);
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thServerSend, (PVOID)hwnd, 0, NULL);
As you can see, I used reference to the window handle in the argument of the thread calling function. This secretly caused stupid errors. Nobody could solve it without full code.
Don't create a compatible bitmap.
Create a DIB section: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183494%28v=vs.85%29.aspx
BITMAPINFO bi;
ZeroMemory(&bi,sizeof(BITMAPINFO));
bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth=Width;
bi.bmiHeader.biHeight=Height;
bi.bmiHeader.biPlanes=1;
bi.bmiHeader.biBitCount=32;
char* buffer;
HBITMAP bitmap=CreateDIBSection(dc,&bi,DIB_RGB_COLORS,&buffer,NULL,0);
// copy pixels to buffer
SelectObject(dc,bitmap);
BitBlt(....

Downloading HTML page with C++

Here is my code. I have attached wininet.lib to additional dependencies.
#include <iostream>
#include <Windows.h>
#include <WinInet.h>
using namespace std;
int main()
{
HINTERNET hSession, hURL;
char* Buffer = new char[1024];
DWORD BufferLen, BytesWritten;
HANDLE FileHandle;
hSession = InternetOpen(NULL, 0, NULL, NULL, 0);
hURL = InternetOpenUrl(hSession, "http://www.google.co.uk", NULL, 0, 0, 0);
FileHandle = CreateFile("C:\temp.txt", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
if (FileHandle == NULL) { cout << "FileHandle == NULL" << endl; }
BytesWritten = 0;
do
{
InternetReadFile(hURL, Buffer, 1024, &BufferLen);
WriteFile(FileHandle, Buffer, BufferLen, &BytesWritten, NULL);
} while (BufferLen != 0);
CloseHandle(FileHandle);
InternetCloseHandle(hURL);
InternetCloseHandle(hSession);
ShellExecute(0, "open", "C:\\temp.txt", NULL, NULL, 1);
cout << "Operation complete!" << endl;
system("PAUSE");
return 0;
}
My output file C:\temp.txt is not created even though the handle is non-null. I would like to know why this is the case and if the rest of my code is correct. Thank you.