GetFIleVersionInfoSize() succeeds but returns incorrect size - c++

I am trying to get the version of a file. I want to look at the version number of this file to determine which OS is installed on a non-booted drive (I'll actually be doing this from a Win PE environment and trying to determine if the main drive has Windows XP or Windows 7 installed). Anyway, I have the following
wchar_t *fileName;
fileName = new wchar_t[255];
lstrcpy(fileName, hdds[HardDriveIndexes::SystemDrive].driveLetter.c_str());
lstrcat(fileName, L"Windows\\System32\\winload.exe");
TCHAR *versionInfoBuffer;
DWORD versionDataSize;
if (versionDataSize = GetFileVersionInfoSize(fileName, NULL) != 0)
{
versionInfoBuffer = new TCHAR[versionDataSize];
BOOL versionInfoResult = FALSE;
versionInfoResult = GetFileVersionInfo(fileName, NULL, versionDataSize, versionInfoBuffer);
if (versionInfoResult == FALSE)
{
wprintf(L"The last error associated with getting version info is: %d\n", GetLastError());
}
}
else
{
wprintf(L"The last error associated with gettting version info size is: %d\n", GetLastError());
}
The problem is that GetFileVersionInfoSize() succeeds but always returns 1 as the size. This causes GetFileVersionInfo() to fail with error 122. So far I have only tested this on a Windows 7 system. There is another function GetFileVersionInfoSizeEx() that works as expected, but it is only supported from Vista onwards. I would like to keep XP support if possible (some of our old Win PE images are still based on XP).
Is GetFileVersionInfoSize() deprecated and I somehow can't find that information, am I using it incorrectly, etc.?

The problem isn't with the call, it's with your assignment; you need parens around it:
if ( ( versionDataSize = GetFileVersionInfoSize(fileName, NULL) ) != 0)
What you had written assigns the value of the expression size != 0, which is 1 for true.

Related

WNetOpenEnum returns ERROR_NETWORK_UNREACHABLE for the "Microsoft Windows Network" node

Our program has a piece of code that calculates the list of computers on our local network. It uses the Windows Networking API (WNetOpenEnum/WNetEnumResource) to unwind the network. For many years, the resulting list was identical to the one that can be seen in Windows Explorer under the "Network" entry. However, recently we have noticed that the same code returns an empty list. During debugging I found that WNetOpenEnum returns error 1231 (ERROR_NETWORK_UNREACHABLE) when it is called for the "Microsoft Windows Network" under the root node.
I have to mention, though I'm pretty sure it has nothing to do with the matter, that the network unwinding is done multithreaded, to avoid possible delays in the main GUI thread. Each time a node of type RESOURCEUSAGE_CONTAINER is encountered, a new worker thread is launched. The thread function calls the following procedure:
DWORD WINAPI EnumNetwork(NETRESOURCE_M* lpNR)
{
const int BUF_SIZE = 16384; // 16K is a good size.
HANDLE hEnum;
DWORD Result;
// Call the WNetOpenEnum function to begin the enumeration.
Result = ::WNetOpenEnum(RESOURCE_GLOBALNET, // all network
RESOURCETYPE_ANY, // all resource types
0, // enumerate all
(LPNETRESOURCE)lpNR,// parent resource
&hEnum); // enumeration handle
if (Result != NO_ERROR) // -> for "Microsoft Windows Network" Result = 1231
return Result;
std::vector<std::wstring> SrvList;
// Allocate buffer for enumeration.
LPNETRESOURCE lpEnumNR = (LPNETRESOURCE)new char[BUF_SIZE];
if (lpEnumNR == 0)
Result = ERROR_OUTOFMEMORY;
else
{
while (1)
{
::ZeroMemory(lpEnumNR, BUF_SIZE); // Initialize the buffer.
DWORD NumEntries = -1; // Enumerate all entries.
DWORD BufSize = BUF_SIZE;
// Call WNetEnumResource to continue the enumeration.
Result = ::WNetEnumResource(hEnum, // enumeration handle
&NumEntries,// number of entries to enumerate
lpEnumNR, // array of resources to return
&BufSize); // buffer size
if (Result == NO_ERROR)
{
// If the call succeeds, loop through the array.
for (unsigned i = 0; i < NumEntries; ++i)
{
if (lpEnumNR[i].dwDisplayType == RESOURCEDISPLAYTYPE_SERVER)
{
// Collect servers.
LPCWSTR SrvName = lpEnumNR[i].lpRemoteName;
if (PathHelpers::IsFullPath(SrvName))
SrvList.push_back(SrvName);
}
else if ((lpEnumNR[i].dwUsage & RESOURCEUSAGE_CONTAINER) &&
lpEnumNR[i].lpRemoteName != 0)
{
TCHAR PathBuf[1024] = {0};
if (lpNR && lpNR->Path)
{
_tcscpy(PathBuf, lpNR->Path);
::PathAddBackslash(PathBuf);
}
_tcscat(PathBuf, lpEnumNR[i].lpRemoteName);
if (RegisterServer(PathBuf))
{
// Start new thread for recursive enumeration.
NETRESOURCE_M* lpChildNR = DeepCopyNR(&lpEnumNR[i], PathBuf);
ExploreNetwork(lpChildNR); // -> this starts a worker thread
}
else
{
GetLogger().LogMessage(
_T("Cycles found while unwinding network: %s"), PathBuf);
}
}
}
}
else
{
if (Result == ERROR_NO_MORE_ITEMS)
Result = NO_ERROR;
break;
}
} // end while
delete [] (char*)lpEnumNR;
} // end if
::WNetCloseEnum(hEnum);
if (!SrvList.empty())
NotifyServerAdded(SrvList);
return Result;
}
where NETRESOURCE_M is the structure
struct NETRESOURCE_M
{
NETRESOURCE NR;
LPTSTR Path;
};
Trying to figure out what could have caused such a sudden change in behavior, I found in Google that a few years ago Microsoft disabled the SMB1 protocol, which could affect Network Discovery. However, I can't believe they could have damaged their own API without saying a word in the documentation.
EDIT: At the same time, Windows Explorer has a bunch of computers under its "Network" node. In the network settings, the network type is "Domain", and the network discovery is ON. Services "Function Discovery Provider Host" and "Function Discovery Resources Publication" are running. Windows OS build is 19042.685.
Edit 2: The Sysinternals' "ShareEnum" tool also fails with the error: "No domains or workgroups where found on your network". Because of this, and also because some time ago our company moved all of its computers to a different network, I got the feeling that the problem is in the network configuration. Such as though the network is declared as "Domain", the computers were not enrolled to this domain. I do not understand much in that, but something like this.

SetupDiEnumDriverInfo returns different results on Windows 7 and Windows 8 / 10

I am debugging an application that should retrieve information about all smart card reader drivers installed on a Windows system.
The code below works on Windows 7 (64 bit):
QSet<QString> getSmartCardDriverModuleNames()
{
QSet<QString> moduleNames;
// the GUID for the smart card reader device setup class
wchar_t deviceClassGuidString[] = L"{50dd5230-ba8a-11d1-bf5d-0000f805f530}";
GUID deviceClass;
CLSIDFromString(deviceClassGuidString, &deviceClass);
HDEVINFO deviceInfoSet = SetupDiGetClassDevs(&deviceClass, NULL, NULL, 0);
if (deviceInfoSet == INVALID_HANDLE_VALUE)
{
return moduleNames;
}
SP_DEVINFO_DATA deviceInfoData;
deviceInfoData.cbSize = sizeof(deviceInfoData);
for (DWORD deviceIndex = 0;
SetupDiEnumDeviceInfo(deviceInfoSet, deviceIndex,
&deviceInfoData);
deviceIndex++)
{
if (SetupDiBuildDriverInfoList(deviceInfoSet, &deviceInfoData,
SPDIT_COMPATDRIVER))
{
SP_DRVINFO_DATA_W driverInfoData;
driverInfoData.cbSize = sizeof(driverInfoData);
for (DWORD driverIndex = 0;
SetupDiEnumDriverInfo(deviceInfoSet, &deviceInfoData,
SPDIT_COMPATDRIVER, driverIndex,
&driverInfoData);
driverIndex++)
{
// Omitted: get service name and add to moduleNames.
}
SetupDiDestroyDriverInfoList(deviceInfoSet, &deviceInfoData,
SPDIT_COMPATDRIVER);
}
}
SetupDiDestroyDeviceInfoList(deviceInfoSet);
return moduleNames;
}
This code correctly finds the installed drivers when run on Windows 7, but finds no driver at all on Windows 8 or Windows 10 (both 64 bit), even though some drivers are installed.
It turns out (by adding extra logging and debug code) that under Windows 8 and 10 the first call to SetupDiEnumDriverInfo fails. In this case, by adding a call to GetLastError() I get ERROR_NO_MORE_ITEMS, which is the normal behaviour expected when the end of the list is reached (see the documentation).
So, no errors are detected, but the result is empty.
In the documentation of the Windows API I have found no changes from Windows 7 to Windows 8, 10, so no adaptation to the above code should be needed.
Have I overlooked something? Do you have any hint as to what I should check next?

How come GetDefaultCommConfig fails on windows 10

I use the following code to verify that a serial port name is valid on the computer:
typedef std::pair<StrAsc const, bool> port_pair_type;
typedef std::list<port_pair_type> port_pairs_type;
port_pairs_type pairs;
StrBin config_buffer;
config_buffer.fill(0,sizeof(COMMCONFIG));
while(!pairs.empty())
{
port_pair_type pair(pairs.front());
pairs.pop_front();
if(!pair.second)
{
// we need to get the default configuration for the port. This may
// require some fudging on the buffer size. That is why two calls
// are being made.
uint4 config_size = config_buffer.length();
StrUni temp(pair.first);
COMMCONFIG *config(reinterpret_cast<COMMCONFIG *>(config_buffer.getContents_writable()));
config->dwSize = sizeof(COMMCONFIG);
rcd = GetDefaultCommConfigW(
temp.c_str(), config, &config_size);
if(!rcd && config_buffer.length() < config_size)
{
config_buffer.fill(0, config_size);
config = reinterpret_cast<COMMCONFIG *>(config_buffer.getContents_writable());
config->dwSize = sizeof(COMMCONFIG);
rcd = GetDefaultCommConfigW(
temp.c_str(),
reinterpret_cast<COMMCONFIG *>(config_buffer.getContents_writable()),
&config_size);
}
// if the call succeeded, we can go ahead and look at the
// configuration structure.
if(rcd)
{
COMMCONFIG const *config = reinterpret_cast<COMMCONFIG const *>(
config_buffer.getContents());
if(config->dwProviderSubType == PST_RS232)
port_names.push_back(pair.first);
}
else
{
OsException error("GetDefaultCommConfig Failed");
trace("\"%s\"", error.what());
}
}
else
port_names.push_back(pair.first);
}
On windows 10, when trying to confirm a serial port that uses usbser.sys, the call to GetDefaultCommConfig() is failing and the error code returned by GetLastError() is 87 (invalid parameter). As I am aware, the usbser.sys driver has been rewritten on windows 10 and I suspect that this is a problem with that driver. Does anyone else have an idea of what might be going wrong?
This had been a bug in usbser.sys and was fixed with the Windows 10 Update KB3124262 from 27.01.2016.
The Microsoft employee explained:
The COM port name in the HKLM\HARDWARE\DEVICEMAP\SERIALCOMM registry is not NULL terminated.
Related discussion on MSDN
Because of Windows 10's update policies this issue should not appear in the future anymore.
When you call GetDefaultCommConfigW the second time you probably need to config->dwSize to the new size the structure. Eg:
config->dwSize = config_size;

FILE_NOT_FOUND when trying to open COM port C++

I am trying to open a com port for reading and writing using C++ but I can't seem to pass the first stage of actually opening it. I get an INVALID_HANDLE_VALUE on the handle
with GetLastError FILE_NOT_FOUND. I have searched around the web for a couple of days I'm fresh out of ideas. I have searched through all the questions regarding COM on this website too.
I have scanned through the existing ports (or so I believe) to get the name of the port right.
I also tried combinations of _T("COM1") with the slashes, without the slashes, with colon, without colon and without the _T
I'm using windows 7 on 64 bit machine.
this is the code i got
I'll be glad for any input on this
void SendToCom(char* data, int len)
{
DWORD cbNeeded = 0;
DWORD dwPorts = 0;
EnumPorts(NULL, 1, NULL, 0, &cbNeeded, &dwPorts);
//What will be the return value
BOOL bSuccess = FALSE;
LPCSTR COM1 ;
BYTE* pPorts = static_cast<BYTE*>(malloc(cbNeeded));
bSuccess = EnumPorts(NULL, 1, pPorts, cbNeeded, &cbNeeded, &dwPorts);
if (bSuccess){
PORT_INFO_1* pPortInfo = reinterpret_cast<PORT_INFO_1*>(pPorts);
for (DWORD i=0; i<dwPorts; i++)
{
//If it looks like "COMX" then
size_t nLen = _tcslen(pPortInfo->pName);
if (nLen > 3)
{
if ((_tcsnicmp(pPortInfo->pName, _T("COM"), 3) == 0) ){
COM1 =pPortInfo->pName;
//COM1 ="\\\\.\\COM1";
HANDLE m_hCommPort = CreateFile( COM1 ,
GENERIC_READ|GENERIC_WRITE, // access ( read and write)
0, // (share) 0:cannot share the COM port
NULL, // security (None)
OPEN_EXISTING, // creation : open_existing
FILE_FLAG_OVERLAPPED, // we want overlapped operation
NULL // no templates file for COM port...
);
if (m_hCommPort==INVALID_HANDLE_VALUE)
{
DWORD err = GetLastError();
if (err == ERROR_FILE_NOT_FOUND) {
MessageBox(hWnd,"ERROR_FILE_NOT_FOUND",NULL,MB_ABORTRETRYIGNORE);
}
else
if(err == ERROR_INVALID_NAME) {
MessageBox(hWnd,"ERROR_INVALID_NAME",NULL,MB_ABORTRETRYIGNORE);
}
else
{
MessageBox(hWnd,"unkown error",NULL,MB_ABORTRETRYIGNORE);
}
}
else{
WriteAndReadPort(m_hCommPort,data);
}
}
pPortInfo++;
}
}
}
}
The Solution is to use
The Problem is, if your port is Bigger then 9 then you have to use the Syntax
LPCWSTR szPortName = L"\\\\.\\COM11";.
If you are on Windows 10 - running all system updates might help !
I had the same issue that opening port "COM4" returned an error ERROR_FILE_NOT_FOUND. When running the program as "Administrator" it worked. Now after a updating to 1511 the program can open "COM4" even not running as "Administrator".
http://www.cplusplus.com/forum/windows/163855/
Use CreateFileA(...) instead of CreateFile(...)
ERROR_FILE_NOT_FOUND can be produced from CreateFile(L"\\\\.\\COM1", ...) and CreateFile(L"COM1:", ...) after using the Device Manager to change the assigned COM Port number. Disabling and re-enabling the device, or unplugging and reconnecting the USB adapter resolves the issue.
A useful test to confirm whether it is your program or the system is to send data to the port in command prompt. A successful test will show an empty line. A failed test will show an error message.
C:\drop>echo > \\.\COM1
The system cannot find the file specified.
C:\drop>echo > \\.\COM1
C:\drop>

windows C++ opening printer with documentproperties get C6836 "Write Overrun" Code analysis warning

In the following code:
// If GetPrinter didn't fill in the DEVMODE, try to get it by calling
// DocumentProperties...
if (pi2->pDevMode == NULL)
{
dwNeeded = DocumentProperties(NULL, hPrinter,
printerName,
NULL, NULL, 0);
if (dwNeeded <= 0)
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
return FALSE;
}
pDevMode = (DEVMODE *)GlobalAlloc(GPTR, dwNeeded);
if (pDevMode == NULL)
{
GlobalFree(pi2);
ClosePrinter(hPrinter);
return FALSE;
}
lFlag = DocumentProperties(NULL, hPrinter,
printerName,
pDevMode, NULL,
DM_OUT_BUFFER);
if (lFlag != IDOK || pDevMode == NULL)
{
GlobalFree(pDevMode);
GlobalFree(pi2);
ClosePrinter(hPrinter);
return FALSE;
}
pi2->pDevMode = pDevMode;
}
On the line
lFlag = DocumentProperties(NULL, hPrinter,
printerName,
pDevMode, NULL,
DM_OUT_BUFFER);
When I run Visual Studio 2012 "Code analysis" feature it throws warning:
C6386 Write overrun Buffer overrun while writing to 'pDevMode': the writable size is 'dwNeeded' bytes, but '220' bytes might be written. Invalid write to 'pDevMode', (outside its writable range)
The code functions fine, but wondering how to fix this warning from occurring (preferably without disabling warning)
The help page for this error does not seem to apply (or I can't figure how it does) http://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&l=EN-US&k=k(C6386)&rd=true
The SAL annotation for DocumentProperties cannot express that DEVMODE is a structure than might be larger than its declared size. The function doesn't also take an argument that states the passed size of the DEVMODE. Nor does the structure have a single field that states the size. So an annotation like __out_bcount_opt or __out_bcount_part could not be used.
It is an issue with all winapi functions that take a DEVMODE. It is a structure that dates from the stone age, long before SAL was ever on the horizon. If Microsoft could do it all over again then they would do this differently. Too late now.
Nothing you can do about it beyond knowing that you got it right and the tool got it wrong. It is just a warning.