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

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.

Related

What is the preferred way to get a device path for CreateFile() in a UWP C++ App?

I am converting a project to a UWP App, and thus have been following guidelines outlined in the MSDN post here. The existing project heavily relies on CreateFile() to communicate with connected devices.
There are many posts in SO that show us how to get a CreateFile()-accepted device path using SetupAPI's SetupDiGetDeviceInterfaceDetail() Is there an alternative way to do this using the PnP Configuration Manager API? Or an alternative, user-mode way at all?
I had some hope when I saw this example in Windows Driver Samples github, but quickly became dismayed when I saw that the function they used in the sample is ironically not intended for developer use, as noted in this MSDN page.
function GetDevicePath in general correct and can be used as is. about difference between CM_*(..) and CM_*_Ex(.., HMACHINE hMachine) - the CM_*(..) simply call CM_*_Ex(.., NULL) - so for local computer versions with and without _Ex suffix the same.
about concrete GetDevicePath code - call CM_Get_Device_Interface_List_Size and than CM_Get_Device_Interface_List only once not 100% correct - because between this two calls new device with this interface can be arrived to system and buffer size returned by CM_Get_Device_Interface_List_Size can be already not enough for CM_Get_Device_Interface_List. of course possibility of this very low, and you can ignore this. but i prefer make code maximum theoretical correct and call this in loop, until we not receive error other than CR_BUFFER_SMALL. also need understand that CM_Get_Device_Interface_List return multiple, NULL-terminated Unicode strings - so we need iterate here. in [example] always used only first returned symbolic link name of an interface instance. but it can be more than 1 or at all - 0 (empty). so better name function - GetDevicePaths - note s at the end. i be use code like this:
ULONG GetDevicePaths(LPGUID InterfaceClassGuid, PWSTR* pbuf)
{
CONFIGRET err;
ULONG len = 1024;//first try with some reasonable buffer size, without call *_List_SizeW
for(PWSTR buf;;)
{
if (!(buf = (PWSTR)LocalAlloc(0, len * sizeof(WCHAR))))
{
return ERROR_NO_SYSTEM_RESOURCES;
}
switch (err = CM_Get_Device_Interface_ListW(InterfaceClassGuid, 0, buf, len, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
case CR_BUFFER_SMALL:
err = CM_Get_Device_Interface_List_SizeW(&len, InterfaceClassGuid, 0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
default:
LocalFree(buf);
if (err)
{
return CM_MapCrToWin32Err(err, ERROR_UNIDENTIFIED_ERROR);
}
continue;
case CR_SUCCESS:
*pbuf = buf;
return NOERROR;
}
}
}
and usage example:
void example()
{
PWSTR buf, sz;
if (NOERROR == GetDevicePaths((GUID*)&GUID_DEVINTERFACE_VOLUME, &buf))
{
sz = buf;
while (*sz)
{
DbgPrint("%S\n", sz);
HANDLE hFile = CreateFile(sz, FILE_GENERIC_READ, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
// do something
CloseHandle(hFile);
}
sz += 1 + wcslen(sz);
}
LocalFree(buf);
}
}
so we must not simply use in returned DevicePathS (sz) only first string, but iterate it
while (*sz)
{
// use sz
sz += 1 + wcslen(sz);
}
I got a valid Device Path to a USB Hub Device, and used it successfully to get various device descriptors by sending some IOCTLs, by using the function I posted in my own answer to another question
I'm reporting the same function below:
This function returns a list of NULL-terminated Device Paths (that's what we get from CM_Get_Device_Interface_List())
You need to pass it the DEVINST, and the wanted interface GUID.
Since both the DEVINST and interface GUID are specified, it is highly likely that CM_Get_Device_Interface_List() will return a single Device Path for that interface, but technically you should be prepared to get more than one result.
It is responsibility of the caller to delete[] the returned list if the function returns successfully (return code 0)
int GetDevInstInterfaces(DEVINST dev, LPGUID interfaceGUID, wchar_t**outIfaces, ULONG* outIfacesLen)
{
CONFIGRET cres;
if (!outIfaces)
return -1;
if (!outIfacesLen)
return -2;
// Get System Device ID
WCHAR sysDeviceID[256];
cres = CM_Get_Device_ID(dev, sysDeviceID, sizeof(sysDeviceID) / sizeof(sysDeviceID[0]), 0);
if (cres != CR_SUCCESS)
return -11;
// Get list size
ULONG ifaceListSize = 0;
cres = CM_Get_Device_Interface_List_Size(&ifaceListSize, interfaceGUID, sysDeviceID, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cres != CR_SUCCESS)
return -12;
// Allocate memory for the list
wchar_t* ifaceList = new wchar_t[ifaceListSize];
// Populate the list
cres = CM_Get_Device_Interface_List(interfaceGUID, sysDeviceID, ifaceList, ifaceListSize, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cres != CR_SUCCESS) {
delete[] ifaceList;
return -13;
}
// Return list
*outIfaces = ifaceList;
*outIfacesLen = ifaceListSize;
return 0;
}
Please note that, as RbMm already said in his answer, you may get a CR_BUFFER_SMALL error from the last CM_Get_Device_Interface_List() call, since the device list may have been changed in the time between the CM_Get_Device_Interface_List_Size() and CM_Get_Device_Interface_List() calls.

GetFIleVersionInfoSize() succeeds but returns incorrect size

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.

Directory relative ZwCreateFile

I have to implement cross view file integrity checker for my University project. For that how do I list the files of a Directory in Kernel Mode??
Your starting point would be ZwCreateFile - which has options such as "FILE_LIST_DIRECTORY".
You will then use ZwQueryDirectoryFile to get the information about the file(s) within that directory.
Make SURE that you are not forgetting to ZwClose after you open something - it's not so critical in a user-mode application that closes again after it's been used. But the kernel doesn't know when a driver stops using a file (or, for that matter, if some other driver has been given that filehandle, and will be using it at some point), so even if your driver is unloaded, files that it opened will remain open until the system restarts - I quite like to "not restart" my systems, and with a good set of drivers, running a machine for more than a year should be possible. If your driver so much as leaks one handle a day, that's 365 handles leaked.
So, the code would look something like this:
HANDLE h;
NTSTATUS status;
OBJECT_ATTRIBUTES oa = { sizeof(OBJECT_ATTRIBUTES), NULL, L"mydir",
OPEN_CASE_INSENSITIVE, NULL, NULL };
IO_STATUS_BLOCK iosb = {};
status = ZwCreateFile(&h, FILE_LIST_DIRECTORY, &oa, &iosb, NULL,
FILE_ATTRIBUTE_NORMAL, FILE_OPEN, FILE_DIRECTORY_FILE,
NULL, 0);
if (status != STATUS_SUCCESS)
{
... do something...
return errorcode;
}
else
{
FILE_DIRECTORY_INFORMATION info;
for(;;)
{
status = ZwQueryDirectoryFile(h, NULL, NULL, &iosb, &info, sizeof(info),
FileDirectoryInformation, TRUE, L"*.*",
FALSE);
if (status != STATUS_SUCCESS)
{
... check error code and perhaps print if unexpected error ...
break;
}
... do soemthing with `info` ...
}
}
ZwClose(h);
This is just a "rough sketch". I don't have a setup to compile this right now, and I may have missed something important. But it should give you some idea. There are LOTS of optional parameters and optional choices here, and some I've "guessed" what you'd want, but I think I've made reasonable choices. There may be details missing that make this not work, but as a rough starting point, it should give you an idea at least.

read from serial port c++

I have the following C++ code and when I run the program sometimes it works and sometimes it does not!
I think the problem occurs when I try to open the serial port while there is data left to be read.
Sometimes after running this program, it makes Windows XP restart unexpectedly! It does not Blue Screen, it justs restarts.
I am using Visual Studio 2010 to compile it.
main()
{
while(0) { // BIG FAT WARNING: MIGHT SUDDEN REBOOT YOUR MACHINE IF ENABLED
read_from_serial(_data);
}
}
bool read_from_serial(octed_string &_data)
{
HANDLE hSerial;
hSerial = CreateFile(TEXT("COM2"),
GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if (hSerial == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
cout << "1:";
return false;
//serialportdoesnotexist.Informuser.
}
cout << "2:";
return false;
//someothererroroccurred.Informuser.
}
DCB dcbSerialParams = {0};
dcbSerialParams.DCBlength=sizeof(dcbSerialParams);
if(!GetCommState(hSerial,&dcbSerialParams))
{
cout<<"3:";
return false;
//errorgettingstate
}
dcbSerialParams.BaudRate=CBR_9600;
dcbSerialParams.ByteSize=7;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=EVENPARITY;
if (!SetCommState(hSerial,&dcbSerialParams))
{
cout<<"4:";
return false;
//errorsettingserialportstate
}
COMMTIMEOUTS timeouts={0};
timeouts.ReadIntervalTimeout=50;
timeouts.ReadTotalTimeoutConstant=10;
timeouts.ReadTotalTimeoutMultiplier=10;
timeouts.WriteTotalTimeoutConstant=50;
timeouts.WriteTotalTimeoutMultiplier=10;
if (!SetCommTimeouts(hSerial,&timeouts))
{
cout<<"5:";
return false;
//erroroccureed.Informuser
}
const int n=1;
DWORD dwBytesRead=0;
char_t tmp_receive[255]={0};
char_t buff[255];
int len=255;
if (!ReadFile(hSerial,tmp_receive,len,&dwBytesRead,NULL))
{
cout<<"6:";
CloseHandle(hSerial);
return false;
}
CloseHandle(hSerial);
tmp_receive[dwBytesRead+1]=END_OF_STRING;
string tmp_buff_str=tmp_receive;
_data.append(tmp_buff_str);
return true;
}
Cause
I have a suspicion that your program is crashing on this line
tmp_receive[dwBytesRead+1]=END_OF_STRING;
You defined the tmp_receive array with 255 elements, which makes the possible indexes 0 to 254. You then initialized len to 255. If there are 255 bytes available to read on the call to ReadFile(...), then dwBytesRead will be equal to 255 and the line I mentioned above will effectively be as follows, and would mean you're attempting to write to memory outside of the scope of the tmp_receive array.
tmp_receive[256] = END_OF_STRING;
As for the rebooting, I don't know for sure, but maybe your program is causing a system crash when it attempts to write to invalid memory and you have Windows XP configured to reboot instead of displaying a BSOD.
Solutions
In order to keep your program from crashing I see that you have 2 options. I can't say which one is better since I don't know what the format of the data you're expecting to receive is, so you will have to analyize the outcomes of each option and decide for yourself.
Option #1
Use an element count of 257 when defining the tmp_receive array.
Option #2
Subtract 2 from len when making the call to ReadFile(...)
if (!ReadFile(hSerial,tmp_receive,len-2,&dwBytesRead,NULL))
Additional Information
Have a look at the MSDN documentation on ReadFile(...) for more information on the behaviour of the ReadFile(...) Windows API.
If you would like to learn more about how strings are stored in memory, I would suggest having a look at the Character Sequences article on www.cplusplus.com.

How do I read from a version resource in Visual C++

I have a version resource in my resources in a C++ project which contains version number, copyright and build details. Is there an easy way to access this at run-time to populate my help/about dialog as I am currently maintaining seperate const values of this information. Ideally, the solution should work for Windows/CE mobile and earlier versions of Visual C++ (6.0 upwards).
This is an edited version of my original answer.
bool GetProductAndVersion(CStringA & strProductName, CStringA & strProductVersion)
{
// get the filename of the executable containing the version resource
TCHAR szFilename[MAX_PATH + 1] = {0};
if (GetModuleFileName(NULL, szFilename, MAX_PATH) == 0)
{
TRACE("GetModuleFileName failed with error %d\n", GetLastError());
return false;
}
// allocate a block of memory for the version info
DWORD dummy;
DWORD dwSize = GetFileVersionInfoSize(szFilename, &dummy);
if (dwSize == 0)
{
TRACE("GetFileVersionInfoSize failed with error %d\n", GetLastError());
return false;
}
std::vector<BYTE> data(dwSize);
// load the version info
if (!GetFileVersionInfo(szFilename, NULL, dwSize, &data[0]))
{
TRACE("GetFileVersionInfo failed with error %d\n", GetLastError());
return false;
}
// get the name and version strings
LPVOID pvProductName = NULL;
unsigned int iProductNameLen = 0;
LPVOID pvProductVersion = NULL;
unsigned int iProductVersionLen = 0;
// replace "040904e4" with the language ID of your resources
if (!VerQueryValue(&data[0], _T("\\StringFileInfo\\040904e4\\ProductName"), &pvProductName, &iProductNameLen) ||
!VerQueryValue(&data[0], _T("\\StringFileInfo\\040904e4\\ProductVersion"), &pvProductVersion, &iProductVersionLen))
{
TRACE("Can't obtain ProductName and ProductVersion from resources\n");
return false;
}
strProductName.SetString((LPCSTR)pvProductName, iProductNameLen);
strProductVersion.SetString((LPCSTR)pvProductVersion, iProductVersionLen);
return true;
}
To get a language independent result to Mark's answer change :
// replace "040904e4" with the language ID of your resources
!VerQueryValue(&data[0], _T("\\StringFileInfo\\040904e4\\ProductVersion"), &pvProductVersion, &iProductVersionLen))
{
TRACE("Can't obtain ProductName and ProductVersion from resources\n");
return false;
}
To
UINT uiVerLen = 0;
VS_FIXEDFILEINFO* pFixedInfo = 0; // pointer to fixed file info structure
// get the fixed file info (language-independent)
if(VerQueryValue(&data[0], TEXT("\\"), (void**)&pFixedInfo, (UINT *)&uiVerLen) == 0)
{
return false;
}
strProductVersion.Format("%u.%u.%u.%u",
HIWORD (pFixedInfo->dwProductVersionMS),
LOWORD (pFixedInfo->dwProductVersionMS),
HIWORD (pFixedInfo->dwProductVersionLS),
LOWORD (pFixedInfo->dwProductVersionLS));
Something like might get you started, perhaps:
TCHAR moduleName[MAX_PATH+1];
(void)GetModuleFileName(AfxGetInstanceHandle(), moduleName, MAX_PATH);
DWORD dummyZero;
DWORD versionSize = GetFileVersionInfoSize(moduleName, &dummyZero);
if(versionSize == 0)
{
return NULL;
}
void* pVersion = malloc(versionSize);
if(pVersion == NULL)
{
return NULL;
}
if(!GetFileVersionInfo(moduleName, NULL, versionSize, pVersion))
{
free(pVersion);
return NULL;
}
UINT length;
VS_FIXEDFILEINFO* pFixInfo;
VERIFY(VerQueryValue(pVersionInfo, const_cast<LPTSTR>("\\"), (LPVOID*)&pFixInfo, &length));
Something like this will give you raw access to the resource data and get you started:
HRSRC res = ::FindResource(NULL, MAKEINTRESOURCE(MY_VERSION_ID), RT_VERSION);
DWORD size = ::SizeofResource(NULL, res);
HGLOBAL mem = ::LoadResource(NULL, res);
LPVOID raw_data = ::LockResource(mem);
...
::FreeResource(mem);
Beware!
Using FindResource..LockResource is not correct. It will sometimes work (as it did in my small demo program) and sometimes cause access violations (example: the production code I was making the demo for).
The VerQueryValue() documentation states that you should call GetFileVersionInfoSize and GetFileVersionInfo instead.
Raymond Chen explains, see http://blogs.msdn.com/oldnewthing/archive/2006/12/26/1365215.aspx
Ok, a bit more googleing found the following on CodeGuru. Basically this approach uses the CFileVersionInfo object to get on any given file. It should be interesting to see if it works on the currently running .EXE file and on Windows CE.
Sometimes I receive Access Violation when use VerQueryValueA. But I never got this error when use VerQueryValueW. I think something wrong with VerQueryValueA in version.dll. Therefore I use VerQueryValueW instead of VerQueryValueA even in projects Multi-byte Character Encoding. Here is my code of ReadVersion function