How to detect USB speed on Windows - c++

I use setup API functions to find a USB device then use createfile to communicate with it. i.e. using SetupDiGetClassDevs, SetupDiEnumDeviceInterfaces, SetupDiGetDeviceInterfaceDetail, etc.
I would like to be able to determine if the device is connected at USB2 speeds or USB3 speeds ie. SuperSpeed or not
How can I do this through the Windows APIs?

This is what I ended up going with. It's convoluted. Cant believe there isn't an easier way:
#include "stdafx.h"
#include <Windows.h>
#include <Setupapi.h>
#include <winusb.h>
#undef LowSpeed
#include <Usbioctl.h>
#include <iostream>
#include <string>
#include <memory>
#include <vector>
class Usb_Device
{
private:
std::wstring _driverKey;
char _speed;
public:
Usb_Device(int adapterNumber, std::wstring devicePath, char speed);
virtual char GetSpeed(std::wstring driverKey);
};
class Usb_Hub : public Usb_Device
{
private:
bool _isRootHub;
std::wstring _deviceDescription;
std::wstring _devicePath;
std::vector<std::unique_ptr<Usb_Device>> _devices;
public:
Usb_Hub(std::wstring devicePath, char speed);
virtual char GetSpeed(std::wstring driverKey) override;
};
class Usb_Controller
{
private:
GUID _interfaceClassGuid;
std::wstring _devicePath;
std::wstring _deviceDescription;
std::wstring _driverKey;
std::vector<std::unique_ptr<Usb_Device>> _devices;
public:
Usb_Controller();
char GetSpeed(std::wstring driverKey);
};
static std::unique_ptr<Usb_Device> BuildDevice(int portCount, std::wstring devicePath)
{
std::unique_ptr<Usb_Device> ret;
HANDLE handle = INVALID_HANDLE_VALUE;
DWORD bytes = -1;
DWORD bytesReturned = -1;
BOOL isConnected = FALSE;
char speed;
// Open a handle to the Hub device
handle = CreateFile(devicePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (handle != INVALID_HANDLE_VALUE)
{
bytes = sizeof(USB_NODE_CONNECTION_INFORMATION_EX);
PUSB_NODE_CONNECTION_INFORMATION_EX nodeConnection = (PUSB_NODE_CONNECTION_INFORMATION_EX)(new char[bytes]);
nodeConnection->ConnectionIndex = portCount;
if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, nodeConnection, bytes, nodeConnection, bytes, &bytesReturned, 0))
{
isConnected = nodeConnection->ConnectionStatus == USB_CONNECTION_STATUS::DeviceConnected;
speed = nodeConnection->Speed;
}
if (isConnected)
{
if (nodeConnection->DeviceDescriptor.bDeviceClass == 0x09 /*HubDevice*/)
{
bytes = sizeof(USB_NODE_CONNECTION_NAME);
PUSB_NODE_CONNECTION_NAME nodeConnectionName = (PUSB_NODE_CONNECTION_NAME)(new char[bytes]);
nodeConnectionName->ConnectionIndex = portCount;
if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_NAME, nodeConnectionName, bytes, nodeConnectionName, bytes, &bytesReturned, 0))
{
bytes = nodeConnectionName->ActualLength;
delete[] nodeConnectionName;
nodeConnectionName = (PUSB_NODE_CONNECTION_NAME)(new char[bytes]);
nodeConnectionName->ConnectionIndex = portCount;
if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_NAME, nodeConnectionName, bytes, nodeConnectionName, bytes, &bytesReturned, 0))
{
std::wstring name = std::wstring(L"\\\\?\\") + std::wstring(nodeConnectionName->NodeName);
ret = std::unique_ptr<Usb_Device>(new Usb_Hub(name, speed));
}
}
delete[] nodeConnectionName;
}
else
{
ret = std::unique_ptr<Usb_Device>(new Usb_Device(portCount, devicePath, speed));
}
}
else
{
// Chuck this device
}
delete[] nodeConnection;
CloseHandle(handle);
}
return ret;
}
Usb_Controller::Usb_Controller()
{
BOOL success = TRUE;
for (int index = 0; success; index++)
{
GUID guid;
HRESULT hr = CLSIDFromString(L"{3abf6f2d-71c4-462a-8a92-1e6861e6af27}", (LPCLSID)&guid);
unsigned char* ptr = new unsigned char[2048]; // Should really do two calls, but that's more effort
HDEVINFO deviceInfoHandle = SetupDiGetClassDevs(&guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
// Create a device interface data structure
SP_DEVICE_INTERFACE_DATA deviceInterfaceData = { 0 };
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
// Start the enumeration.
success = SetupDiEnumDeviceInterfaces(deviceInfoHandle, 0, &guid, index, &deviceInterfaceData);
if (success)
{
_interfaceClassGuid = deviceInterfaceData.InterfaceClassGuid;
// Build a DevInfo data structure.
SP_DEVINFO_DATA deviceInfoData = { 0 };
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
// Now we can get some more detailed informations.
DWORD nRequiredSize = 0;
SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterfaceData, 0, 0, &nRequiredSize, 0);
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(new char[nRequiredSize]);
memset(deviceInterfaceDetailData, 0, nRequiredSize);
deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterfaceData, deviceInterfaceDetailData, nRequiredSize, &nRequiredSize, &deviceInfoData))
{
_devicePath = deviceInterfaceDetailData->DevicePath;
// Get the device description and driver key name.
DWORD requiredSize = 0;
DWORD regType = REG_SZ;
if (SetupDiGetDeviceRegistryProperty(deviceInfoHandle, &deviceInfoData, SPDRP_DEVICEDESC, &regType, ptr, 2048, &requiredSize))
{
_deviceDescription = reinterpret_cast<wchar_t*>(ptr);
}
if (SetupDiGetDeviceRegistryProperty(deviceInfoHandle, &deviceInfoData, SPDRP_DRIVER, &regType, ptr, 2048, &requiredSize))
{
_driverKey = reinterpret_cast<wchar_t*>(ptr);
}
}
delete[] deviceInterfaceDetailData;
}
SetupDiDestroyDeviceInfoList(deviceInfoHandle);
std::unique_ptr<Usb_Device> hub(new Usb_Hub(_devicePath, -1));
_devices.push_back(std::move(hub));
}
else
{
success = false;
}
delete[] ptr;
}
}
char Usb_Controller::GetSpeed(std::wstring driverKey)
{
char speed = -1;
for (auto it = _devices.begin(); it != _devices.end() && speed == -1; ++it)
{
if (*it != nullptr)
{
speed = (*it)->GetSpeed(driverKey);
}
}
return speed;
}
Usb_Hub::Usb_Hub(std::wstring devicePath, char speed) :
Usb_Device(-1, devicePath, speed)
{
HANDLE handle1 = INVALID_HANDLE_VALUE;
HANDLE handle2 = INVALID_HANDLE_VALUE;
_deviceDescription = L"Standard-USB-Hub";
_devicePath = devicePath;
DWORD bytesReturned = -1;
DWORD bytes = -1;
BOOL success = TRUE;
// Open a handle to the host controller.
handle1 = CreateFile(devicePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (handle1 != INVALID_HANDLE_VALUE)
{
USB_ROOT_HUB_NAME rootHubName;
memset(&rootHubName, 0, sizeof(USB_ROOT_HUB_NAME));
// Get the root hub name.
if (DeviceIoControl(handle1, IOCTL_USB_GET_ROOT_HUB_NAME, nullptr, 0, &rootHubName, sizeof(USB_ROOT_HUB_NAME), &bytesReturned, 0))
{
if (rootHubName.ActualLength > 0)
{
PUSB_ROOT_HUB_NAME actualRootHubName = (PUSB_ROOT_HUB_NAME)(new char[rootHubName.ActualLength]);
if (DeviceIoControl(handle1, IOCTL_USB_GET_ROOT_HUB_NAME, nullptr, 0, actualRootHubName, rootHubName.ActualLength, &bytesReturned, 0))
{
_isRootHub = true;
_deviceDescription = L"RootHub";
_devicePath = std::wstring(L"\\\\?\\") + std::wstring(actualRootHubName->RootHubName);
}
delete[] actualRootHubName;
}
}
// Now let's open the hub (based upon the hub name we got above).
int PortCount = 0;
handle2 = CreateFile(_devicePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (handle2 != INVALID_HANDLE_VALUE)
{
bytes = sizeof(USB_NODE_INFORMATION);
PUSB_NODE_INFORMATION nodeInfo = (PUSB_NODE_INFORMATION)(new char[bytes]);
memset(nodeInfo, 0, sizeof(USB_NODE_INFORMATION));
nodeInfo->NodeType = USB_HUB_NODE::UsbHub;
// Get the hub information.
if (DeviceIoControl(handle2, IOCTL_USB_GET_NODE_INFORMATION, nodeInfo, bytes, nodeInfo, bytes, &bytesReturned, 0))
{
DWORD d = GetLastError();
PortCount = nodeInfo->u.HubInformation.HubDescriptor.bNumberOfPorts;
}
delete[] nodeInfo;
CloseHandle(handle2);
}
CloseHandle(handle1);
for (int index = 1; index <= PortCount; index++)
{
std::unique_ptr<Usb_Device> device = BuildDevice(index, _devicePath);
_devices.push_back(std::move(device));
}
}
else
{
success = FALSE;
}
}
char Usb_Hub::GetSpeed(std::wstring driverKey)
{
char speed = Usb_Device::GetSpeed(driverKey);
if (speed == -1)
{
for (auto it = _devices.begin(); it != _devices.end() && speed == -1; ++it)
{
if (*it != nullptr)
{
speed = (*it)->GetSpeed(driverKey);
}
}
}
return speed;
}
Usb_Device::Usb_Device(int adapterNumber, std::wstring devicePath, char speed)
{
_speed = speed;
HANDLE handle = CreateFile(devicePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (handle != INVALID_HANDLE_VALUE)
{
// Get the Driver Key Name (usefull in locating a device)
DWORD bytesReturned = -1;
DWORD bytes = sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME);
PUSB_NODE_CONNECTION_DRIVERKEY_NAME driverKey = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)(new char[bytes]);
driverKey->ConnectionIndex = adapterNumber;
// Use an IOCTL call to request the Driver Key Name
if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, driverKey, bytes, driverKey, bytes, &bytesReturned, 0))
{
bytes = driverKey->ActualLength;
delete[] driverKey;
driverKey = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)(new char[bytes]);
driverKey->ConnectionIndex = adapterNumber;
if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, driverKey, bytes, driverKey, bytes, &bytesReturned, 0))
{
_driverKey = driverKey->DriverKeyName;
}
}
delete[] driverKey;
CloseHandle(handle);
}
}
char Usb_Device::GetSpeed(std::wstring driverKey)
{
return _speed;
}
int main()
{
Usb_Controller controller;
GUID guid;
HRESULT hr = CLSIDFromString(L"{AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA}", (LPCLSID)&guid);
HDEVINFO deviceInfoHandle = SetupDiGetClassDevs(&guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (deviceInfoHandle != INVALID_HANDLE_VALUE)
{
int deviceIndex = 0;
while (true)
{
SP_DEVICE_INTERFACE_DATA deviceInterface = { 0 };
deviceInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (SetupDiEnumDeviceInterfaces(deviceInfoHandle, 0, &guid, deviceIndex, &deviceInterface))
{
DWORD cbRequired = 0;
SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface, 0, 0, &cbRequired, 0);
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(new char[cbRequired]);
memset(deviceInterfaceDetail, 0, cbRequired);
deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetail(deviceInfoHandle, &deviceInterface, deviceInterfaceDetail, cbRequired, &cbRequired, 0))
{
deviceIndex++;
continue;
}
// Initialize the structure before using it.
memset(deviceInterfaceDetail, 0, cbRequired);
deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
// Call the API a second time to retrieve the actual
// device path string.
BOOL status = SetupDiGetDeviceInterfaceDetail(
deviceInfoHandle, // Handle to device information set
&deviceInterface, // Pointer to current node in devinfo set
deviceInterfaceDetail, // Pointer to buffer to receive device path
cbRequired, // Length of user-allocated buffer
&cbRequired, // Pointer to arg to receive required buffer length
NULL); // Not interested in additional data
BOOL success = TRUE;
for (int i = 0; success; i++)
{
SP_DEVINFO_DATA deviceInterfaceData = { 0 };
deviceInterfaceData.cbSize = sizeof(SP_DEVINFO_DATA);
// Start the enumeration.
success = SetupDiEnumDeviceInfo(deviceInfoHandle, i, &deviceInterfaceData);
DWORD RequiredSize = 0;
DWORD regType = REG_SZ;
unsigned char* ptr = new unsigned char[2048];
if (SetupDiGetDeviceRegistryProperty(deviceInfoHandle, &deviceInterfaceData, SPDRP_DRIVER, &regType, ptr, 2048, &RequiredSize))
{
char speed = controller.GetSpeed(reinterpret_cast<wchar_t*>(ptr));
std::wcout << std::wstring(reinterpret_cast<wchar_t*>(ptr)) << std::endl;
std::wcout << L"Speed: " << (int)speed << std::endl;
}
delete[] ptr;
}
auto hDeviceHandle = CreateFile(
deviceInterfaceDetail->DevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
CloseHandle(hDeviceHandle);
delete[] deviceInterfaceDetail;
}
}
else
{
break;
}
++deviceIndex;
}
SetupDiDestroyDeviceInfoList(deviceInfoHandle);
}
return 0;
}

I guess you will have to try WinUSB in the link there's a sample code of detecting the speed of USB. If you want the description of WinUSB you will find it here.

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.

WriteFile returns invalid handle

I am attempting to use Windows WriteFile API as follows:
class FileWriter
{
public:
FileWriter(const std::string & path);
~FileWriter();
bool write(unsigned char * buffer, int num_bytes, unsigned __int64 offset);
private:
HANDLE file_h;
};
The implementation is simple as:
FileWriter::FileWriter(const std::string & path)
{
file_h = CreateFileA(path.c_str(), GENERIC_WRITE,
FILE_SHARE_READ, 0, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0);
if (file_h == INVALID_HANDLE_VALUE) {
throw std::runtime_error("Could not open the output file");
}
}
FileWriter::~FileWriter()
{
if (file_h != INVALID_HANDLE_VALUE) {
CloseHandle(file_h);
}
}
bool FileWriter::write(unsigned char * buffer, int num_bytes,
unsigned __int64 offset)
{
if (file_h != INVALID_HANDLE_VALUE && buffer) {
OVERLAPPED overlapped;
overlapped.Offset = offset & 0xFFFFFFFF;
overlapped.OffsetHigh = offset >> 32;
BOOL e = WriteFile(file_h, buffer, num_bytes,
0, &overlapped);
DWORD c = GetLastError();
LPSTR messageBuffer = nullptr;
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, c, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
std::string message(messageBuffer, size);
//Free the buffer.
LocalFree(messageBuffer);
if (e == FALSE && c == ERROR_IO_PENDING) {
return true;
}
else {
if ((e == TRUE) && (c == ERROR_SUCCESS))
return true;
}
}
return false;
}
This always fails with The handle is invalid error. However, the file handle is always valid. I even check for it. So, I am not sure what I am doing wrong.

Getting md5 hash code for dll file in c++

Hi guys i am trying to get dll md5 hash but it is returning same value all the time, what i did wrong?
this dll is already loaded when i am trying to getHash
i am getting hash with getHash() method and calculating it with CalcHash
thnks in advanced.
#define BUFSIZE 1024
#define MD5LEN 16
int CalcHash(HANDLE hFile, char *md5sum)
{
BOOL bResult = FALSE;
HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
BYTE rgbFile[BUFSIZE];
DWORD cbRead = 0;
BYTE rgbHash[MD5LEN];
DWORD cbHash = 0;
CHAR rgbDigits[] = "0123456789abcdef";
char byt[3];
int rc, err;
rc = CryptAcquireContext(&hProv, NULL, MS_STRONG_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
if(!rc)
{
err = GetLastError();
if(err==0x80090016)
{
//first time using crypto API, need to create a new keyset
rc=CryptAcquireContext(&hProv, NULL, MS_STRONG_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET);
if(!rc)
{
err=GetLastError();
return 0;
}
}
}
CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);
while(bResult = ReadFile(hFile, rgbFile, BUFSIZE, &cbRead, NULL))
{
if (0 == cbRead)
{
break;
}
CryptHashData(hHash, rgbFile, cbRead, 0);
}
cbHash = MD5LEN;
CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0);
md5sum[0] = 0;
for (DWORD i = 0; i < cbHash; i++)
{
sprintf(byt, "%c%c", rgbDigits[rgbHash[i] >> 4], rgbDigits[rgbHash[i] & 0xf]);
strcat(md5sum, byt);
}
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return 1;
}
char *getHash()
{
CalcHash(L"dsetup.dll", md5sum);
Logger(md5sum);
return md5sum;
}

Thread not completing properly, preventing application close

I'm writing a win32 form application and drawing it with Direct2D. I have a few cross threaded functions to do animations on it and I'm doing web requests with WinHTTP. The issue is, when I use any WinHttp functions (even just opening an HINTERNET session), it will cause the thread not to terminate properly. After I run the 'login' process once, the program cannot exit calmly. I've posted the relevant code below:
//the login process
void __cdecl processloginasync(void* arg)
{
//getting text from textboxes, etc.
if(usernamestr.find(L'#') != wstring::npos && usernamestr.find(L".") != wstring::npos) {
swapdrawmode(1);
_beginthread(loadwheel,NULL,arg);
void* result = NULL;
unsigned sz = 0;
int rescode = web_request(L"appurl.mywebsite.com/func.php",ss.str().c_str(),result,sz);
//other code to handle the reply...
swapdrawmode(0);
}
else {
error_str = L"Invalid email address.";
err = TRUE;
}
if(err == TRUE) {
textopacity = 0;
animatemode = 0;
_beginthread(animatetext,NULL,arg);
}
//I realize I haven't called 'free' on result, I'll fix that.
}
//the web_request function
int web_request (const wchar_t* server, const wchar_t* object, void*& dest, unsigned& size)
{
vector<void*> retval;
vector<unsigned> szs;
HINTERNET hSess = NULL, hConn = NULL, hReq = NULL;
int res = 0;
DWORD dwDownloaded = 0;
DWORD dwSize = 0;
DWORD retcode = NULL;
short err = FALSE;
const wchar_t* accepted_types[] = {
L"image/*",
L"text/*",
NULL
};
hSess = WinHttpOpen(L"smartCARS2 Web/1.1",WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if(hSess)
hConn = WinHttpConnect(hSess,server,INTERNET_DEFAULT_HTTP_PORT, NULL);
else {
err = TRUE;
retcode = HTTP_OPEN_FAILED;
}
if(hConn)
hReq = WinHttpOpenRequest(hConn, NULL, object, NULL, WINHTTP_NO_REFERER,accepted_types,NULL);
else {
err = TRUE;
retcode = HTTP_CONN_FAILED;
}
if(hReq)
res = WinHttpSendRequest(hReq, WINHTTP_NO_ADDITIONAL_HEADERS, NULL, WINHTTP_NO_REQUEST_DATA, NULL, NULL, NULL);
else {
err = TRUE;
retcode = HTTP_OPENREQ_FAILED;
}
if(res)
res = WinHttpReceiveResponse(hReq, NULL);
else {
err = TRUE;
retcode = HTTP_SEND_REQ_FAILED;
}
DWORD tsize = 0;
if(res) {
do {
dwSize = 0;
if(!WinHttpQueryDataAvailable(hReq, &dwSize)) {
retcode = HTTP_COULD_NOT_QUERY_SIZE;
err = TRUE;
break;
}
if(!dwSize)
break;
tsize += dwSize;
void* rets = malloc(dwSize + 1);
if(!rets) {
break;
}
if(!WinHttpReadData(hReq, (void*)rets, dwSize, &dwDownloaded)) {
retcode = HTTP_COULD_NOT_READ_DATA;
err = TRUE;
break;
}
if(!dwDownloaded) {
retcode = HTTP_COULD_NOT_DOWNLOAD;
err = TRUE;
break;
}
szs.push_back(dwSize);
retval.push_back(rets);
} while(dwSize > 0);
}
size = tsize;
unsigned int sz = retval.size();
dest = malloc(tsize);
tsize = 0;
for(unsigned i = 0; i < sz; i++) {
memcpy((BYTE*)dest + tsize,retval[i],szs[i]);
free(retval[i]);
tsize += szs[i];
}
if(hSess)
WinHttpCloseHandle(hSess);
if(hConn)
WinHttpCloseHandle(hConn);
if(hReq)
WinHttpCloseHandle(hReq);
if(err == TRUE)
return retcode;
return 0;
}
As far as I know, as soon as the main thread terminates, the others are not waited for. So the problem is probably in your main thread. You just need to attach a debugger if not already being debugged (Debug | Attach to process in VS) to a zombie process and press "Break all", then use "Threads" and "Call stack" windows to figure what's happening.

Heap allocation problems

I am running into memory errors when I try to run my C++ program in Visual Studio 2012. I am thinking that this code is the cause (since when I remove it, it runs fine):
void GetMachineHash(CString &strHashHex) {
CMD5 cMD5;
BYTE *szHash = (BYTE*)malloc(48);
LPBYTE szMachineNameHash, szNetworkAddressHash, szVolumeIdHash;
TCHAR szMachineId[100];
DWORD nMachineIdLen = 100;
TCHAR szNetworkAddress[13];
IP_ADAPTER_INFO *pAdapterInfo, *pAdapter = NULL;
DWORD dwRetVal = 0;
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
TCHAR szVolumeId[20];
TCHAR szVolumeName[MAX_PATH];
TCHAR szFileSystemName[MAX_PATH];
DWORD dwSerialNumber = 0;
DWORD dwMaxComponentLen = 0;
DWORD dwFileSystemFlags = 0;
ZeroMemory(szHash, 48);
ZeroMemory(szMachineId, 100);
ZeroMemory(szVolumeId, 20);
ZeroMemory(szVolumeName, MAX_PATH);
ZeroMemory(szFileSystemName, MAX_PATH);
ZeroMemory(szNetworkAddress, 13);
GetComputerName(szMachineId, &nMachineIdLen);
cMD5.Calculate(szMachineId);
szMachineNameHash = cMD5.Hash();
pAdapterInfo = (IP_ADAPTER_INFO *) malloc(sizeof(IP_ADAPTER_INFO));
if (pAdapterInfo == NULL) {
TRACE(_T("Error allocating memory needed to call GetAdaptersinfo()"));
szNetworkAddressHash = NULL;
}
// Make an initial call to GetAdaptersInfo to get the necessary size into the ulOutBufLen variable
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
if (pAdapterInfo == NULL) {
TRACE(_T("Error allocating memory needed to call GetAdaptersinfo()"));
szNetworkAddressHash = NULL;
}
}
if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
pAdapter = pAdapterInfo;
while (pAdapter) {
if (pAdapter->Type != MIB_IF_TYPE_LOOPBACK) {
_stprintf_s(szNetworkAddress, 13, _T("%.2X%.2X%.2X%.2X%.2X%.2X"),
pAdapter->Address[0],
pAdapter->Address[1],
pAdapter->Address[2],
pAdapter->Address[3],
pAdapter->Address[4],
pAdapter->Address[5]
);
break;
}
pAdapter = pAdapter->Next;
}
} else {
TRACE(_T("GetAdaptersInfo() call failed"));
szNetworkAddressHash = NULL;
}
cMD5.Calculate(szNetworkAddress);
szNetworkAddressHash = cMD5.Hash();
if (GetVolumeInformation(
NULL,
szVolumeName,
sizeof(szVolumeName),
&dwSerialNumber,
&dwMaxComponentLen,
&dwFileSystemFlags,
szFileSystemName,
sizeof(szFileSystemName))) {
_stprintf_s(szVolumeId, 20, _T("%lu"), dwSerialNumber);
}
cMD5.Calculate(szVolumeId);
szVolumeIdHash = cMD5.Hash();
// Calculate hash from hashes
memcpy(szHash, szMachineNameHash, 16);
memcpy(szHash+16, szNetworkAddressHash, 16);
memcpy(szHash+32, szVolumeIdHash, 16);
cMD5.Calculate(szHash, 48);
strHashHex.Preallocate(33);
strHashHex = cMD5.HexHash();
free(szHash);
free(pAdapterInfo);
return;
}
And then if I leave the function and just remove this code:
strHashHex.Preallocate(33);
strHashHex = cMD5.HexHash();
Then it will work fine as well. So I am wondering if that is the code that's causing the memory problems, and if it is, how can I fix it?
Here's the CMD5 class (which utilizes the Windows API to generate a MD5 sum):
class CMD5
{
public:
CMD5() {
if(CryptAcquireContext(&m_hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET) == 0){
if(GetLastError() == NTE_EXISTS){
CryptAcquireContext(&m_hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0);
}
}
}
~CMD5() {
if(m_hCryptProv)
CryptReleaseContext(m_hCryptProv, 0);
m_hCryptProv = NULL;
free(m_szHash);
}
bool Calculate(LPCTSTR szText) {
DWORD dwLen = sizeof(TCHAR) * _tcslen(szText);
DWORD dwHashLen;
DWORD dwHashLenSize = sizeof(DWORD);
if (CryptCreateHash(m_hCryptProv, CALG_MD5, 0, 0, &m_hHash)) {
if (CryptHashData(m_hHash, (const BYTE*)szText, dwLen, 0)) {
if (CryptGetHashParam(m_hHash, HP_HASHSIZE, (BYTE *)&dwHashLen, &dwHashLenSize, 0)) {
if(m_szHash = (BYTE*)malloc(dwHashLen)) {
if (CryptGetHashParam(m_hHash, HP_HASHVAL, (BYTE*)m_szHash, &dwHashLen, 0)) {
CryptDestroyHash(m_hHash);
}
}
}
}
}
return false;
}
bool Calculate(const LPBYTE szText, DWORD dwLen) {
DWORD dwHashLen;
DWORD dwHashLenSize = sizeof(DWORD);
if (CryptCreateHash(m_hCryptProv, CALG_MD5, 0, 0, &m_hHash)) {
if (CryptHashData(m_hHash, (const BYTE*)szText, dwLen, 0)) {
if (CryptGetHashParam(m_hHash, HP_HASHSIZE, (BYTE *)&dwHashLen, &dwHashLenSize, 0)) {
if(m_szHash = (BYTE*)malloc(dwHashLen)) {
if (CryptGetHashParam(m_hHash, HP_HASHVAL, (BYTE*)m_szHash, &dwHashLen, 0)) {
CryptDestroyHash(m_hHash);
}
}
}
}
}
return false;
}
LPBYTE Hash() const {
LPBYTE szHash = new BYTE[16];
ZeroMemory(szHash, 16);
memcpy(szHash, m_szHash, 16);
return szHash;
}
LPTSTR HexHash() const {
LPTSTR szBuf = new TCHAR[33];
ZeroMemory(szBuf, 33);
for (int i=0; i<16; i++)
_stprintf_s(szBuf+i*2, 33, _T("%02X"), m_szHash[i]);
szBuf[32]=0;
return szBuf;
}
private:
BYTE *m_szHash;
DWORD m_hHash;
HCRYPTPROV m_hCryptProv;
};
Also, the error I get from VS2012 is Critical error detected c0000374 and the call stack ends with a call to HeapAlloc() from _heap_alloc. Not sure if it matters but this code is being called in a DLL.
It looks like I was able to solve the memory allocation problems by changing the CMD5::HexHash() function to
void HexHash(CString &strHash) {
for (int i=0; i<16; i++)
strHash += StringFormat(_T("%02X"), m_szHash[i]);
return;
}
and call it via cMD5.HexHash(strHashHex);