Problem with FtpFindFirstFile - c++

I want to download all file from ftp directory i want use for that FtpFindFirstFile and FtpGetFile;
LPWIN32_FIND_DATA FileData;
TCHAR* APP_NAME = TEXT("ftpcli");
TCHAR* PATH_FTP = TEXT("ftp://127.0.01");
TCHAR* ADR_FTP = TEXT("127.0.0.1");
TCHAR* LC_FILE = TEXT("C:\\!");
TCHAR* PATH_FILE = TEXT("/Soft/DVD_Players/WinDVD6");
UINT a;
HINTERNET opn;
HINTERNET conn;
a = InternetAttemptConnect(0);
if (a == ERROR_SUCCESS ) {
if(InternetCheckConnection(PATH_FTP,FLAG_ICC_FORCE_CONNECTION, NULL)) {
opn = InternetOpen(APP_NAME, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, INTERNET_FLAG_ASYNC);
conn = InternetConnect(opn, ADR_FTP, INTERNET_DEFAULT_FTP_PORT, NULL, NULL, INTERNET_SERVICE_FTP, NULL, NULL);
FtpSetCurrentDirectory(conn, PATH_FILE);
FtpFindFirstFile(conn, NULL, &FileData, INTERNET_FLAG_NEED_FILE, NULL);
FtpGetFile(conn, FileData->cFileName, LC_FILE, FALSE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_BINARY, NULL);
}
}
That code return error i know that because i do not identified memory on LPWIN32_FIND_DATA. But i do not know how do it.

You've declared a pointer to WIN32_FIND_DATA, you need a concrete instance of that structure. Fix:
WIN32_FIND_DATA FileData; // NOTE: not LP

At a minimum:
FileData->cFileName
should be
FileData.cFileName
I misread LPWIN32_FIND_DATA as WIN32_FIND_DATA; nobugs is right that this is just a pointer (and if using the pointer my advice here is wrong, but then there's no struct allocated.)

Related

Download image from HTTP request triggering a breakpoint

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);
}

Windows , WinInet C++ API

I am trying to use FTP to read some files from my local FTP filezilla server. However I struggle a bit, here is my code:
#include<Windows.h>
#include<WinInet.h>
#include<iostream>
using namespace std;
HINTERNET hOpener, hCon, hFinder;
Handle hFile;
char buffer[2000] = "\0";
WIN32_FIND_DATA findData;
hOpener = InternetOpen(TEXT("Chrome"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, NULL);
hCon = InternetConnect(hOpener, TEXT("127.0.0.1"), INTERNET_DEFAULT_FTP_PORT, TEXT("anonymous"), TEXT("adminn"), INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, NULL);
hFinder = FtpFindFirstFile(hCon, NULL, &findData, INTERNET_FLAG_RELOAD, 0);
hFile = FtpOpenFile(hOpener, findData.cFileName, GENERIC_READ, FTP_TRANSFER_TYPE_ASCII, 0);
LPDWORD x = 0;
cout << InternetReadFile(hFile, buffer, 280, x);
However, it prints 0 when it should print 1(basically there's a problem reading). What am I doing wrong here?
You are passing a NULL DWORD* pointer to the lpdwNumberOfBytesRead parameter of InternetReadFile(). You need to pass a pointer to a DWORD instead.
Change:
LPDWORD x = 0;
InternetReadFile(..., x);
to:
DWORD x = 0;
InternetReadFile(..., &x);

HInternet works only one time

This code is in a C++ DLL injected in a game. (This is on a private server so it is legal). The code has to be executed multiple times. However, it works only the first time. It could be on the WCF end but I managed to send 2 and 5 successful requests from a .net dll loaded from the c++ dll before.
Since I didn't figure out why it was blocked after 2 and 5 requests, I decided to go all native but now I'm blocked after one request. I have a feeling it now has to do with the way I'm parsing the response.
The first execution gets a 200 code status and the second one gets a 0.
edit : my fire wall is turned off.
HINTERNET hInternet = InternetOpen(_T("MyApp"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
HINTERNET hConnect = InternetConnect(hInternet, _T("localhost"), INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
LPCSTR rgpszAcceptTypes[] = { _T("application/json"), NULL };
HINTERNET hRequest = HttpOpenRequest(hConnect, _T("POST"), _T("/xxxBackend/service1.svc/SaveDataVoid"), NULL, NULL, rgpszAcceptTypes, 0, 0);
HttpAddRequestHeaders(hRequest, _T("Content-Type: application/json\r\n"), -1, HTTP_ADDREQ_FLAG_ADD);
char *JsonData = "{\"data\":{\"AccountName\":\"\",\"CharName\":\"SilverDeth-IV\",\"GameDiff\":\"1\",\"CompressedData\":[8228138568842941382,8247906688399250381,8244242016143283142]}}";
HttpSendRequest(hRequest, NULL, 0, JsonData, strlen(JsonData));
DWORD StatusCode = 0;
DWORD StatusCodeLen = sizeof(StatusCode);
HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &StatusCode, &StatusCodeLen, NULL);
if (StatusCode == 200)
{
char *lpBuffer[2000];
DWORD lpdwNumberOfBytesRead = 0;
InternetQueryDataAvailable(hRequest, &StatusCodeLen, 0, 0);
bool bRetval = InternetReadFile(hRequest, lpBuffer, 2000, &lpdwNumberOfBytesRead);
}
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
The code you have shown is not doing ANY error handling at all. Add that in, and then see where the failure is really occurring. The fact that StatusCode is 0 means HttpQueryInfo() is failing, which could happen if you did not obtain a valid hRequest to begin with.
BTW, rgpszAcceptTypes needs to be declared as LPCTSTR instead of LPCSTR, and you should be using the TEXT() macro instead of the _T() macro. TEXT() belongs to the Win32 API, but _T() belongs to the C runtime library, which you are not using in this code.
Try this:
void InetError(LPCTSTR msg)
{
DWORD dwErr = GetLastError();
if (dwErr == ERROR_INTERNET_EXTENDED_ERROR)
{
DWORD dwInetErr = 0;
LPTSTR szResp = NULL;
DWORD dwLength = 0;
InternetGetLastResponseInfo(&dwInetErr, NULL, &dwLength);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
szResp = new TCHAR[dwLength+1];
InternetGetLastResponseInfo(&dwInetErr, szResp, &dwLength);
}
// use msg, szResp, and dwInetErr as needed...
delete[] szResp;
}
else
{
// use msg and dwErr as needed...
}
}
...
HINTERNET hInternet = NULL;
HINTERNET hConnect = NULL;
HINTERNET hRequest = NULL;
hInternet = InternetOpen(TEXT("MyApp"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (!hInternet)
{
InetError(TEXT("InternetOpen failed"));
goto done;
}
hConnect = InternetConnect(hInternet, TEXT("localhost"), INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (!hConnect)
{
InetError(TEXT("InternetConnect failed"));
goto done;
}
LPCTSTR rgpszAcceptTypes[] = { TEXT("application/json"), NULL };
hRequest = HttpOpenRequest(hConnect, TEXT("POST"), TEXT("/xxxBackend/service1.svc/SaveDataVoid"), NULL, NULL, rgpszAcceptTypes, 0, 0);
if (!hRequest)
{
InetError(TEXT("HttpOpenRequest failed"));
goto done;
}
if (!HttpAddRequestHeaders(hRequest, TEXT("Content-Type: application/json\r\n"), -1, HTTP_ADDREQ_FLAG_ADD))
{
InetError(TEXT("HttpAddRequestHeaders failed"));
goto done;
}
char *JsonData = "{\"data\":{\"AccountName\":\"\",\"CharName\":\"SilverDeth-IV\",\"GameDiff\":\"1\",\"CompressedData\":[8228138568842941382,8247906688399250381,8244242016143283142]}}";
if (!HttpSendRequest(hRequest, NULL, 0, JsonData, strlen(JsonData)))
{
InetError(TEXT("HttpSendRequest failed"));
goto done;
}
DWORD StatusCode = 0;
DWORD StatusCodeLen = sizeof(StatusCode);
if (!HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &StatusCode, &StatusCodeLen, NULL))
{
InetError(TEXT("HttpQueryInfo failed"));
goto done;
}
if (StatusCode == 200)
{
BYTE Buffer[2000];
DWORD dwNumberOfBytes = 0;
DWORD dwNumberOfBytesRead = 0;
if (!InternetQueryDataAvailable(hRequest, &dwNumberOfBytes, 0, 0))
{
InetError(TEXT("InternetQueryDataAvailable failed"));
goto done;
}
if (!InternetReadFile(hRequest, Buffer, min(dwNumberOfBytes, sizeof(Buffer)), &dwNumberOfBytesRead))
{
InetError(TEXT("InternetReadFile failed"));
goto done;
}
//...
}
done:
if (hRequest) InternetCloseHandle(hRequest);
if (hConnect) InternetCloseHandle(hConnect);
if (hInternet) InternetCloseHandle(hInternet);

Send JSON data via HttpOpenRequest

I'm not programming at C++, but i'm asking for someone who does, so i'm sorry if my question is simple or stupid.
I need a simple example of using HttpOpenRequest/HttpSendRequest objects in order to send JSON data to some web service/site.
Thank you
Here is a very bare bones example to send a JSON string to http://hostname/path/scriptname. You will have to add proper error checking, status code checking, etc as needed:
HINTERNET hInternet = InternetOpen(_T("MyApp"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
HINTERNET hConnect = InternetConnect(hInternet, _T("hostname"), INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
LPTSTR rgpszAcceptTypes[] = {_T("application/json"), NULL};
HINTERNET hRequest = HttpOpenRequest(hConnect, _T("POST"), _T("/path/scriptname"), NULL, NULL, rgpszAcceptTypes, 0, 0);
HttpAddRequestHeaders(hRequest, _T("Content-Type: application/json\r\n"), -1, HTTP_ADDREQ_FLAG_ADD);
char *JsonData = "..."; // your actual JSON data here
HttpSendRequest(hRequest, NULL, 0, JsonData, strlen(JsonData))
DWORD StatusCode = 0;
DWORD StatusCodeLen = sizeof(StatusCode);
HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &StatusCode, &StatusCodeLen, NULL);
if (StatusCode == 200)
{
// use InternetQueryDataAvailable() and InternetReadFile()
// to read any response data as needed...
}
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);

WCHAR to String, how do i do it?

String* Adder::downloadUrl(String* url)
{
DWORD dwSize = 0;
LPVOID lpOutBuffer = NULL;
BOOL bResults = FALSE;
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
// Use WinHttpOpen to obtain a session handle.
hSession = WinHttpOpen( L"A WinHTTP Example Program/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
// Specify an HTTP server.
if (hSession)
hConnect = WinHttpConnect( hSession, L"www.google.com",
INTERNET_DEFAULT_HTTP_PORT, 0);
// Create an HTTP request handle.
if (hConnect)
hRequest = WinHttpOpenRequest( hConnect, L"GET", NULL,
NULL, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
0);
// Send a request.
if (hRequest)
bResults = WinHttpSendRequest( hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS,
0, WINHTTP_NO_REQUEST_DATA, 0,
0, 0);
// End the request.
if (bResults)
bResults = WinHttpReceiveResponse( hRequest, NULL);
// First, use WinHttpQueryHeaders to obtain the size of the buffer.
if (bResults)
{
WinHttpQueryHeaders( hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF,
WINHTTP_HEADER_NAME_BY_INDEX, NULL,
&dwSize, WINHTTP_NO_HEADER_INDEX);
// Allocate memory for the buffer.
if( GetLastError( ) == ERROR_INSUFFICIENT_BUFFER )
{
lpOutBuffer = new WCHAR[dwSize/sizeof(WCHAR)];
// Now, use WinHttpQueryHeaders to retrieve the header.
bResults = WinHttpQueryHeaders( hRequest,
WINHTTP_QUERY_RAW_HEADERS_CRLF,
WINHTTP_HEADER_NAME_BY_INDEX,
lpOutBuffer, &dwSize,
WINHTTP_NO_HEADER_INDEX);
}
}
// Print the header contents.
if (bResults)
printf("Header contents: \n%S",lpOutBuffer);
// Free the allocated memory.
delete [] lpOutBuffer;
// Report any errors.
if (!bResults)
printf("Error %d has occurred.\n",GetLastError());
// Close any open handles.
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
String* retOne;
return retOne;
}
I want to get response as string i am using dll in C#, dont know vc++ at all, please suggest a way.
String* retOne //how to get response;
return retOne;
UPDATE
// Convert a wide Unicode string to an UTF8 string
std::string utf8_encode(const std::wstring &wstr)
{
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
std::string strTo( size_needed, 0 );
WideCharToMultiByte (CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
return strTo;
}
String* retOne = utf8_encode(lpOutBuffer);
Gives error: 'utf8_encode' : cannot convert parameter 1 from 'LPVOID' to 'const std::wstring
Please don't post comments suggesting use of .net libraries.
Looks like you need the WideCharToMultiByte function
Whats hard in this process is to understand the function WideCharToMultiByte.
Basically what you need to do in order to get the whole string (and avoid garbage as a result of not having a null terminating string) is first use:
int size_needed = WideCharToMultiByte(CP_UTF8, 0, (LPCWCH)lpOutBuffer, -1, NULL, 0, NULL, NULL);
char *stringMe = new char[size_needed + 1];
While size_needed will be the required buffer size for lpMultiByteStr in the WideCharToMultiByte function.
Afterwards you just need to use that function again, since now you have the complete size:
WideCharToMultiByte(CP_UTF8, 0, (LPCWCH)lpOutBuffer, -1, stringMe, size_needed, NULL, NULL);
stringMe[size_needed + 1] = NULL;
Now you can also convert it to String:
std::string serverOutput(stringMe);
Try this:
String* retOne = utf8_encode(std::wstring(lpOutBuffer));
or
String* retOne = utf8_encode(std::wstring((WCHAR*)lpOutBuffer));