Download image from HTTP request triggering a breakpoint - c++

I am trying to download an image onto the user's desktop from a URL using Win32. I have taken care of all the HTTP request stuff and know for a fact that it is all working well. When I go to call CreateFile() the Visual Studios debugger just says "Exception: Application.exe has triggered a breakpoint" and that it will resume on the CreateFile() line. Also there is an error code "Critical error detected c0000374"
Here is my code:
VARIANT varResponse;
VariantInit(&varResponse);
...
hr = pIWinHttpRequest->get_ResponseBody(&varResponse);
...
if (SUCCEEDED(hr)) {
long upperBounds;
long lowerBounds;
unsigned char* buff;
//Make sure that varResponse is an array of unsigned bytes
if (varResponse.vt == (VT_ARRAY | VT_UI1)) {
long Dims = SafeArrayGetDim(varResponse.parray);
//It should only have one dimension
if (Dims == 1) {
//Get Array lower and upper bounds
SafeArrayGetLBound(varResponse.parray, 1, &lowerBounds);
SafeArrayGetUBound(varResponse.parray, 1, &upperBounds);
upperBounds++;
SafeArrayAccessData(varResponse.parray, (void**)&buff);
HANDLE hFile;
DWORD dwBytesWritten;
PWSTR filepath[MAX_PATH];
HRESULT hr = SHGetKnownFolderPath(FOLDERID_Desktop, 0, NULL, &*filepath);
if (SUCCEEDED(hr)) {
//PathCombine(filepathForImage, filepathToDesktop, L"\\todaysDailyImage.jpg");
PathAppend(*filepath, L"todaysDailyImage.jpg");
MessageBox(NULL, *filepath, L"Check if filepath works", MB_OK);
}
hFile = CreateFile(*filepath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
//File failed
}
else {
WriteFile(hFile, buff, upperBounds - lowerBounds, &dwBytesWritten, NULL);
//File was written
}
CloseHandle(hFile);
CoTaskMemFree(filepath);
SafeArrayUnaccessData(varResponse.parray);
MessageBox(NULL, L"Everything was cleaned up", L"Update:", MB_OK);
}
}
}
Am I doing anything wrong?

The way you are using filepath is all wrong.
You are declaring it as an array of MAX_PATH (260) number of PWSTR pointers.
When you refer to an array by its name alone, you end up with a pointer to the 1st element of the array. So, &*filepath is the same as &*(&filepath[0]), which is effectively &filepath[0]. And *filepath is the same as *(&filepath[0]), which is effectively filepath[0]. So, as far as SHGetKnownFolderPath() and MessageBox() are concerned, they are only operating on the 1st PWSTR pointer in the array, and the other 259 array elements are ignored. That part is ok, but wasteful.
However, PathAppend() requires a destination buffer that is an array of MAX_PATH number of WCHAR elements. You are appending to the WCHAR[] array that SHGetKnownFolderPath() allocates as its output, which is not large enough to hold the filename you are trying to append to it. So, you are triggering errors because you are trying to modify memory that hasn’t been allocated to hold that modification.
You don’t need the PWSTR array at all. Try something more like this instead:
PWSTR folderpath;
HRESULT hr = SHGetKnownFolderPath(FOLDERID_Desktop, 0, NULL, &folderpath);
if (FAILED(hr)) {
// ...
}
else {
PWSTR filepath;
hr = PathAllocCombine(folderpath, L"todaysDailyImage.jpg", 0, &filepath);
if (FAIlED(hr)) {
// ...
}
else {
MessageBoxW(NULL, filepath, L"Check if filepath works", MB_OK);
hFile = CreateFileW(filepath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
//File failed
}
else {
WriteFile(hFile, buff, upperBounds - lowerBounds, &dwBytesWritten, NULL);
//File was written
CloseHandle(hFile);
}
LocalFree(filepath);
}
CoTaskMemFree(folderpath);
}

Related

How do you compare the content of an edit control to the text in a file?

I am writing a simple text editor using the Win32 API and I am trying to write a function to compare the content of the file to the content of an edit control. I currently have this:
BOOL checkForModification (PCWSTR pszFileName, HWND hEdit) {
BOOL bSuccess = FALSE;
DWORD dwTextLength = GetWindowTextLengthA(hEdit);
hFile = CreateFile(pszFileName, GENERIC_READ,
FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
DWORD dwFileSize;
dwFileSize = GetFileSize(hFile, NULL);
if (dwFileSize != 0xFFFFFFFF)
{
PSTR pszFileText;
pszFileText = (PSTR)GlobalAlloc(GPTR, dwFileSize + 1);
if (pszFileText != NULL) {
DWORD dwRead;
if (ReadFile(hFile, pszFileText, dwFileSize + 1, &dwRead, NULL))
{
bSuccess = TRUE;
pszFileText[dwFileSize] = 0;
LPSTR pszEditText = (LPSTR)GlobalAlloc(GPTR, dwTextLength + 1);
GetWindowTextA(hEdit, pszEditText, dwTextLength);
int res = CompareStringA(LOCALE_SYSTEM_DEFAULT, NULL, pszFileText, -1, pszEditText, -1);
if (res != CSTR_EQUAL) {
MessageBox(NULL, L"You changed the text!", L"Alert", MB_OK | MB_ICONINFORMATION);
}
GlobalFree(pszEditText);
}
else {
MessageBox(NULL, L"Oh no! Something went wrong!\nError code: 2", L"Error", MB_OK | MB_ICONERROR);
}
GlobalFree(pszFileText);
}
}
CloseHandle(hFile);
}
else {
MessageBox(NULL, L"Oh no! Something went wrong!\nError code: 1", L"Error", MB_OK | MB_ICONERROR);
}
return bSuccess;
}
The problem that I am having is that the result of CompareStringA is always returning CSTR_LESS_THAN, even when I don't change the text in the edit control. The encoding of the file is UTF-8. Why is this happening?
Seriously, use a debugger and test it with a file that contains simple text like ABCDE. You should be able to figure out the problem in less than 30 seconds just by inspecting a few variables!
You can trivially determine that the problem is not reading the documentation of function GetWindowTextA (https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowtexta).
The size you pass include the null terminating charaters. Assuming that the edit also contains ABCDE, then the length is 5.
Calling GetWindowTextA(hEdit, pszEditText, dwTextLength); where dwTextLength will returns a buffer that contains ABCD plus the null character.
Obviously ABCD is before ABCDE using usual sorting rules.
Actually, for my purposes, I have found it to be easiest to just use the Edit_GetModify macro to see if any edits have been made to the text in the edit control. While this doesn't do exactly what I want (it will return TRUE even if you undo your changes), it is more efficient than having to read the entire file then compare its entire contents to that of the edit control.

Downloading data via WinInet

And so there is a code, that can download data with size not higher than 1024*100 bytes. Code brought from https://rsdn.org/article/inet/inetapi.xml.
As far as I understand, InternetReadFile after every call should move on the read characters count, or it's sensless, because it'll return the same data. I red, that there is a function,that moves reading start pointer. Have I to use it?
HINTERNET hInternetSession;
HINTERNET hURL;
char cBuffer[1024*100]; // I'm only going to access 1K of info.
BOOL bResult;
DWORD dwBytesRead;
// Make internet connection.
hInternetSession = InternetOpen(
L"tes", // agent
INTERNET_OPEN_TYPE_PRECONFIG, // access
NULL, NULL, 0); // defaults
// Make connection to desired page.
hURL = InternetOpenUrl(
hInternetSession, // session handle
L"https://www.google.com.ua/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", // URL to access
NULL, 0, 0, 0); // defaults
// Read page into memory buffer.
while(bResult = InternetReadFile(
hURL, // handle to URL
(LPSTR)cBuffer, // pointer to buffer
(DWORD)1024 * 100, // size of buffer
&dwBytesRead)==TRUE&&dwBytesRead>0) // pointer to var to hold return value
// Close down connections.
InternetCloseHandle(hURL);
InternetCloseHandle(hInternetSession);
DWORD dwTemp;
HANDLE hFile = CreateFile(L"googlelogo_color_272x92dp.png", GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hFile) {
return 0;
}
WriteFile(hFile, cBuffer, sizeof(cBuffer), &dwTemp, NULL);
Issue: I can't read more than 1024*1024 bytes, program crashes, when creates char[1024*1024]
Here is a complete program. Thanks to #RbMm
#include <windows.h>
#include <wininet.h>
#pragma comment(lib,"wininet")
int main(int argc, char* argv[])
{
HINTERNET hInternetSession;
HINTERNET hURL;
// I'm only going to access 1K of info.
BOOL bResult;
DWORD dwBytesRead=1;
// Make internet connection.
hInternetSession = InternetOpen(
L"tes", // agent
INTERNET_OPEN_TYPE_PRECONFIG, // access
NULL, NULL, 0); // defaults
// Make connection to desired page.
hURL = InternetOpenUrl(
hInternetSession, // session handle
L"http://wallpapers-images.ru/1920x1080/nature/wallpapers/wallpapers-nature-1.jpg", // URL to access
NULL, 0, 0, 0); // defaults
// Read page into memory buffer.
char buf[1024];
DWORD dwTemp;
HANDLE hFile = CreateFile(L"пример.jpg", GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hFile) {
return 0;
}
for (;dwBytesRead>0;)
{
InternetReadFile(hURL, buf, (DWORD)sizeof(buf), &dwBytesRead);
WriteFile(hFile, buf, dwBytesRead, &dwTemp, NULL);
}
// Close down connections.
InternetCloseHandle(hURL);
InternetCloseHandle(hInternetSession);
CloseHandle(hFile);
return 0;
}

Resource Data Doesnt Write to TextFile

void Extract(WORD wResId , LPSTR lpszOutputPath)
{
HRSRC hrsrc = FindResource(NULL, MAKEINTRESOURCE(wResId) , RT_RCDATA);
HGLOBAL hLoaded = LoadResource( NULL,hrsrc);
LPVOID lpLock = LockResource( hLoaded);
DWORD dwSize = SizeofResource(NULL, hrsrc);
HANDLE hFile = CreateFile("C://Windows//Darek//mylo.txt",GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
DWORD dwByteWritten;
char* cRes = (char*)malloc (dwSize);
memset(cRes,0,dwSize);
memcpy (cRes, cData, dwSize);
cRes[dwSize] = '\0';
FreeResource(hLoaded);
WriteFile(hFile, lpLock , dwSize , &dwByteWritten , NULL);
CloseHandle(hFile);
FreeResource(hLoaded);
}
Ok this creates the file correctly, but the extracted data doesnt seem to extract and write to the textFile,Any problems? i do not seem to understand why it doesnt extract and Write the data to the file.
Please Help.
You are allocating a memory block that is as large as the resource, zeroing it out (which is redundant), and copying something (what is cData pointing at? Maybe you meant lpLock instead?) into that memory, but then you are ignoring the allocated memory and leaking it. You are trying to write the content of lpLock to the file as-is, which is what you should be doing, but you are not doing any error handling at all. Chances are, your resource is missing, or otherwise not available for reading. That would account for your file being empty.
Try this instead:
void Extract(WORD wResId, LPSTR lpszOutputPath)
{
HRSRC hrsrc = FindResource(NULL, MAKEINTRESOURCE(wResId), RT_RCDATA);
if (!hrsrc)
{
// GetLastError() tells you why it failed...
return;
}
HGLOBAL hLoaded = LoadResource(NULL, hrsrc);
if (!hLoaded)
{
// GetLastError() tells you why it failed...
return;
}
DWORD dwSize = SizeofResource(NULL, hrsrc);
if ((dwSize == 0) && (GetLastError() != 0))
{
// GetLastError() tells you why it failed...
return;
}
LPVOID lpLock = LockResource(hLoaded);
if (!lpLock)
{
// GetLastError() tells you why it failed...
return;
}
HANDLE hFile = CreateFileA(lpszOutputPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
// GetLastError() tells you why it failed...
return;
}
DWORD dwByteWritten;
if (!WriteFile(hFile, lpLock, dwSize, &dwByteWritten, NULL))
{
// GetLastError() tells you why it failed...
CloseHandle(hFile);
DeleteFileA(lpszOutputPath);
return;
}
CloseHandle(hFile);
}
If I had to guess (and please don't make people guess), FindResource() is most likely returning NULL. Make sure the second parameter actually matches the correct resource type for wResId. You cannot load any arbitrary resource using RT_RCDATA, you have to use the correct resource type. Only resources using the RCDATA type can be accessed using the RT_RCDATA parameter value. String resources might be stored using the RT_MESSAGETABLE or RT_STRING type instead, for instance. You can use EnumResourceTypes() and EnumResourceNames(), or an external resource editor/viewer tool, to find out what type the wResId resource is actually using.

Unable to open file using CreateFile function

Ok so I've been following this tutorial: http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=4422&lngWId=3
And so far I've gotten everything to work, up until I need the program to load in a .raw audio file.
Here's the relevant code:
LPSTR loadAudioBlock(const char* filename, DWORD* blockSize)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD size = 0;
DWORD readBytes = 0;
void* block = NULL;
//open the file
if((hFile = CreateFile((LPCWSTR)filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
return NULL;
// get it's size, allocate memory, and then read it into memory
size = GetFileSize(hFile, NULL);
block = HeapAlloc(GetProcessHeap(), 0, size);
ReadFile(hFile, block, size, &readBytes, NULL);
CloseHandle(hFile);
*blockSize = size;
return (LPSTR)block;
}
And then my main function which calls it:
int _tmain(int argc, _TCHAR* argv[])
{
HWAVEOUT hWaveOut; //device handle
WAVEFORMATEX wfx; //struct for format info
MMRESULT result; // for waveOut return values
LPSTR block;
DWORD blockSize;
// first let's set up the wfx format struct
wfx.nSamplesPerSec = 44100; // rate of the sample
wfx.wBitsPerSample = 16; //sample size
wfx.nChannels = 2; // 2 channels = stereo
wfx.cbSize = 0; // no extra info
wfx.wFormatTag = WAVE_FORMAT_PCM; //PCM format
wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;
wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
// then let's open the device
if(waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR)
{
fprintf(stderr, "unable to open Wave Mapper device.\n");
Sleep(1000);
ExitProcess(1);
}
// if no errors then close it
printf("The Wave Mapper device was opened successfully!\n");
//load and play file
if((block = loadAudioBlock("ding.raw", &blockSize)) == NULL)
{
fprintf(stderr, "Unable to load file\n");
Sleep(1000);
ExitProcess(1);
}
writeAudioBlock(hWaveOut, block, blockSize);
Sleep(1000);
waveOutClose(hWaveOut);
return 0;
}
Everytime I run the program I get the: "Unable to load file" output. I've got the "ding.raw" file in the same directory as my exe. I've also tried doing the full path as "C://path" and "C:/path" but then the compiler just gives me more errors about being unable to load a pdb file.
Any ideas? I'm using the Visual Studio 2012 Professional IDE and compiler.
Instead of using the standard char you should be using e.g. _TCHAR and LPCTSTR everywhere. This will make all string and string pointers you pass around be correct.
Look at the argv argument to _tmain and you will see that it uses _TCHAR instead of char. This is because Windows support both normal characters and Unicode characters depending on a couple of macros. See e.g. here for some more information.
So to solve what is likely your problem (since you don't get the actual error code, see my comment about GetLastError) you should change the function like this:
void *loadAudioBlock(LPCTSTR filename, DWORD* blockSize)
{
// ...
if((hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
return NULL;
// ...
}
And call it like this:
// ...
void *block;
if((block = loadAudioBlock(_T("C:\\path\\ding.raw"), &blockSize)) == NULL)
{
fprintf(stderr, "unable to open Wave Mapper device, error code %ld.\n", GetLastError());
Sleep(1000);
ExitProcess(1);
}
// ...
As you can see I also changed the return type, as the file is binary and won't have any readable text.
LPSTR loadAudioBlock(const char* filename, DWORD* blockSize)
{
if((hFile = CreateFile(CA2T(filename), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
return NULL;
}
See ATL conversion macros: http://msdn.microsoft.com/en-us/library/87zae4a3%28v=vs.80%29.aspx Just casting const char* LPCWSTR doesn't work.

Trouble using ReadFile() to read a string from a text file

How can I make the code below to read correct text. In my text file has Hello welcome to C++, however at the end of the text, it has a new line. With the code below, my readBuffer always contains extra characters.
DWORD byteWritten;
int fileSize = 0;
//Use CreateFile to check if the file exists or not.
HANDLE hFile = CreateFile(myFile, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile != INVALID_HANDLE_VALUE)
{
BOOL readSuccess;
DWORD byteReading;
char readBuffer[256];
readSuccess = ReadFile(hFile, readBuffer, byteReading, &byteReading, NULL);
if(readSuccess == TRUE)
{
TCHAR myBuffer[256];
mbstowcs(myBuffer, readBuffer, 256);
if(_tcscmp(myBuffer, TEXT("Hello welcome to C++")) == 0)
{
FindClose(hFile);
CloseHandle(hFile);
WriteResultFile(TRUE, TEXT("success!"));
}
}
}
Thanks,
There are a few problems:
You're passing uninitialized data (byteReading) as the "# of bytes to read" parameter to ReadFile().
Depending on how you created the file, the file's contents may not have a terminating 0 byte. The code assumes that the terminator is present.
FindClose(hFile) doesn't make sense. CloseHandle(hFile) is all you need.
You need to call CloseHandle if CreateFile() succeeds. Currently, you call it only if you find the string you're looking for.
This isn't a bug, but it's helpful to zero-initialize your buffers. That makes it easier to see in the debugger exactly how much data is being read.
HANDLE hFile = CreateFile(myfile, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile != INVALID_HANDLE_VALUE)
{
BOOL readSuccess;
DWORD byteReading = 255;
char readBuffer[256];
readSuccess = ReadFile(hFile, readBuffer, byteReading, &byteReading, NULL);
readBuffer[byteReading] = 0;
if(readSuccess == TRUE)
{
TCHAR myBuffer[256];
mbstowcs(myBuffer, readBuffer, 256);
if(_tcscmp(myBuffer, TEXT("Hello welcome to C++")) == 0)
{
rv = 0;
}
}
CloseHandle(hFile);
}
I see two things:
byteReading isn't initialized
you are reading bytes so you have to terminate the string by 0.
CloseHandle is sufficient
Either remove the new line character from the file or use _tcsstr for checking the existence of the string "Hello Welcome to C++".