I am developing a cross platform platform that is suppose to run on the following platform
Windows x64
Linux x64
Windows ARM
Linux ARM
Android ARM
The program is used in interfacing with multiple Serial Ports (up to 20) and server connectivity using MQTT or ReST-JSON.
I am extensively suing asynchronous operation and threading in my application
I have couple question regarding error handling
Can I handle WIN API error in libc errno integer variable or do I have to use GetLastError in windows and errno in Linux + Android.
Is GetLastError() thread safe?
Is strerror_s thread safe?
Will strerror_s be available in Linux and Android if I select C11 or greater during program build?
My current implementation
//Returns the last error, in string format. Returns an empty string if there is no error.
std::string GetLastErrorAsString(void)
{
#ifdef _WIN64
//Get the error message ID, if any.
DWORD errorMessageID = ::GetLastError();
if (errorMessageID == 0)
{
return std::string(); //No error message has been recorded
}
LPSTR message_buffer = nullptr;
//Ask Win64 to give us the string version of that message ID.
//The parameters we pass in, tell Win64 to create the buffer that holds the message for us (because we don't yet know how long the message string will be).
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&message_buffer, 0, NULL);
//Copy the error message into a std::string.
std::string error_message(message_buffer, size);
//Free the Win64's string's buffer.
LocalFree(message_buffer);
return error_message;
#elif __linux__ || __ANDROID__
if (errno == 0)
{
return std::string(); //No error message has been recorded
}
size_t error_message_length = strerrorlen_s(errno) + 1;
std::array<char, error_message_length> error_message;
//char errmsg[errmsglen];
strerror_s(error_message.data(), error_message_length, errno);
return std::string(error_message.data());
#endif
}
Can I handle WIN API error in libc errno integer variable or do I have to use GetLastError in windows and errno in Linux + Android.
No, if you are calling Win APIs you will need to use GetLastError() to get the last error.
Is GetLastError() thread safe?
Yes. "Retrieves the calling thread's last-error code value. The last-error code is maintained on a per-thread basis.". Always search MSDN for information about Win API.
Is strerror_s thread safe?
In general, I don't know. A quick search found that it may be on Windows:
https://github.com/MicrosoftDocs/cpp-docs/issues/2281
Will strerror_s be available in Linux and Android if I select C11 or greater during program build?
Yes.
Always search cppreference.com for C and C++ library reference information. It clearly indicates the answer with the "since C11" in the header.
Related
Using Bluetooth socket programming on Windows.
I am calling the Win32 BluetoothSdpEnumAttributes() API. The callback function (PFN_BLUETOOTH_ENUM_ATTRIBUTES_CALLBACK pfnCallback) is then calling the Win32 BluetoothSdpGetElementData() API.
I can see the following attributes coming back from the services from the Android device:
ServiceClassIds (0x1)
ProtocolDescriptorList (0x4)
BrowseGroupList (0x5)
BluetoothProfileDescriptorList (0x9)
AdditionalProtocolDescriptorList (0xD)
All of these attributes are of type SDP_TYPE_SEQUENCE (0x6).
Based on the attribute name, can I assume that they are all one or more Bluetooth UUIDs (GUIDS on Windows)?
If yes, I think the code below will get the list of UUIDs into memory.
case SDP_TYPE_SEQUENCE: {
ULONG l_ULONGSequenceLength = SDP_ELEMENT_DATA_in.data.sequence.length + 1;
BYTE* l_pBYTESequence = new BYTE[l_ULONGSequenceLength];
ZeroMemory(l_pBYTESequence, l_ULONGSequenceLength);
memcpy(l_pBYTESequence,
SDP_ELEMENT_DATA_in.data.sequence.value,
SDP_ELEMENT_DATA_in.data.sequence.length);
// TODO: handle the memory
delete[] l_pBYTESequence;
break;
}
I can see that there are helper functions (specifically PRETRIEVEUUID128()) for Bluetooth device driver programming in <bthsdpddi.h>, but our code is running in user mode.
I took a stab at getting <bthsdpddi.h> into our current code, but was not successful.
Does anyone have any sample code on how to parse the SDP_TYPE_SEQUENCE memory?
OK, the way to iterate/loop over the bluetooth sequence data is to use the Win32 API named BluetoothSdpGetContainerElementData (see code snippet below).
case SDP_TYPE_SEQUENCE: {
HBLUETOOTH_CONTAINER_ELEMENT l_HBLUETOOTH_CONTAINER_ELEMENT = NULL;
SDP_ELEMENT_DATA l_SDP_ELEMENT_DATA;
DWORD l_DWORD =
BluetoothSdpGetContainerElementData(
SDP_ELEMENT_DATA_in.data.sequence.value,
SDP_ELEMENT_DATA_in.data.sequence.length,
&l_HBLUETOOTH_CONTAINER_ELEMENT,
&l_SDP_ELEMENT_DATA);
while (l_DWORD == ERROR_SUCCESS)
{
// recursive method call...
const _variant_t l_variant_t =
ConvertAttributeToVariant(
ULONGAttributeId_in,
pTCHARAttributeName_in,
l_SDP_ELEMENT_DATA);
l_DWORD =
BluetoothSdpGetContainerElementData(
SDP_ELEMENT_DATA_in.data.sequence.value,
SDP_ELEMENT_DATA_in.data.sequence.length,
&l_HBLUETOOTH_CONTAINER_ELEMENT,
&l_SDP_ELEMENT_DATA);
}
break;
}
I have been using the FormatMessage function within the Windows API to generate message strings from system error codes. I noticed that for some error codes the full message doesn't appear to be created.
Take this sample program as an example:
int main()
{
wchar_t * buffer = nullptr;
FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
ERROR_SYSTEM_PROCESS_TERMINATED,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&buffer),
0,
nullptr);
std::wcout << buffer << std::endl;
return 0;
}
According to MSDN I should see the following:
{Fatal System Error}
The %hs system process terminated unexpectedly with a status of 0x%08x (0x%08x 0x%08x). The system has been shut down.
However, in the sample program I will see:
{Fatal System Error}
The %hs system process terminated unexpectedly with a status of 0x
I noticed that ERROR_UNHANDLED_EXCEPTION also doesn't create the full message (when compared to the list on MSDN). Both of the expected messages contain 0x%08 placeholders, but the message ends after 0x.
From what I can see, other error messages appear to match the lists on MSDN (i.e. the issue appears to be restricted to ERROR_UNHANDLED_EXCEPTION and ERROR_SYSTEM_PROCESS_TERMINATED).
Credit to engf-010 - you get the same if you use the Error Lookup tool in Visual Studio (Tools - Error Lookup). The error codes are 574 and 591.
Does anyone know why these messages are being cropped?
Is there anyway to get the full message?
The messages you mention (ERROR_UNHANDLED_EXCEPTION and ERROR_SYSTEM_PROCESS_TERMINATED) have printf-style inserts (%08x). However, FormatMessage uses %0 to terminate a message.
My guess is that there's another avenue where these messages are returned by the system with the printf-style placeholders already populated; these messages, in their raw form, are not meant to be handled by FormatMessage.
Given that these messages contain the text (Fatal System Error) or (Application Error), it is not altogether surprising that Windows handles these message specially.
I am tring to create a Remote thread that will load a DLL I wrote, and run a function from it.
The DLL is working fine (Checked) but from some reason, the Remote thread fails and the proccess in which it was created stop responding.
I used ollyDebug to try and see what is going wrong and I noticed two things...
My strings (dll name and function name) are passed to the remote thread correctly
The thread fails on LoadLibrary with lasterror code 87 "ERROR_INVALID_PARAMETER"
My best guess is that somehow, The remote thread can't find LoadLibrary (Is this because the linker is done with repspect to my proccess???, Just a guess...)
What am I doing wrong?
This is the code to the remote function:
static DWORD WINAPI SetRemoteHook (DATA *data)
{
HINSTANCE dll;
HHOOK WINAPI hook;
HOOK_PROC hookAdress;
dll = LoadLibrary(data->dll);
hookAdress = (HOOK_PROC) GetProcAddress(dll,data->func);
if (hookAdress != NULL)
{
(hookAdress)();
}
return 1;
}
Edit:
This is the part in which I allocate the memory to the remote proccess:
typedef struct
{
char* dll;
char* func;
} DATA;
char* dllName = "C:\\Windows\\System32\\cptnhook.dll";
char* funcName = "SetHook";
char* targetPrgm = "mspaint.exe";
Data lData;
lData.dll = (char*) VirtualAllocEx( explorer, 0, sizeof(char)*strlen(dllName), MEM_COMMIT, PAGE_READWRITE );
lData.func = (char*) VirtualAllocEx( explorer, 0, sizeof(char)*strlen(funcName), MEM_COMMIT, PAGE_READWRITE );
WriteProcessMemory( explorer, lData.func, funcName, sizeof(char)*strlen(funcName), &v );
WriteProcessMemory( explorer, lData.dll, dllName, sizeof(char)*strlen(dllName), &v );
rDataP = (DATA*) VirtualAllocEx( explorer, 0, sizeof(DATA), MEM_COMMIT, PAGE_READWRITE );
WriteProcessMemory( explorer, rDataP, &lData, sizeof(DATA), NULL );
Edit:
It looks like the problem is that the remote thread is calling a "garbage" address
instead of LoadLibrary base address. Is there a possibily Visual studio linked
the remote proccess LoadLibrary address wrong?
Edit:
when I try to run the same exact code as a local thread (I use a handle to the current procces in CreateRemoteThread) the entire thing works just fine. What can cause this?
Should I add the calling function code? It seems to be doing its job as
the code is being executed in the remote thread with the correct parameters...
The code is compiled under VS2010.
data is a simple struct with char* 's to the names. (As explicetly writing the strings in code would lead to pointers to my original proccess).
What am I doing wrong?
Failing with ERROR_INVALID_PARAMETER indicates that there is a problem with the parameters passed.
So one should look at data->dll which represents the only parameter in question.
It is initialised here:
lData.dll = VirtualAllocEx(explorer, 0, sizeof(char) * (strlen(dllName) + 1), MEM_COMMIT, PAGE_READWRITE);
So let's add a check whether the allocation of the memory which's reference should be store into lData.dll really succeded.
if (!lData.dll) {
// do some error logging/handling/whatsoever
}
Having done so, you might have detected that the call as implemented failed because (verbatim from MSDN for VirtualAllocEx()):
The function fails if you attempt to commit a page that has not been
reserved. The resulting error code is ERROR_INVALID_ADDRESS.
So you might like to modifiy the fourth parameter of the call in question as recommended (again verbatim from MSDN):
To reserve and commit pages in one step, call VirtualAllocEx with
MEM_COMMIT | MEM_RESERVE.
PS: Repeat this exercise for the call to allocate lData.func. ;-)
It's possible that LoadLibrary is actually aliasing LoadLibraryW (depending on project settings), which is the Unicode version. Whenever you use the Windows API with "char" strings instead of "TCHAR", you should explicitly use ANSI version names. This will prevent debugging hassles when the code is written, and also in the future for you or somebody else in case the project ever flips to Unicode.
So, in addition to fixing that horrible unterminated string problem, make sure to use:
LoadLibraryA(data->dll);
I need to implement an application that streams data from disk. It is important that the data throughput is fairly constant and is not interupted by any other activity on the disk.
From Windows Vista onwards, the GetFileBandwidthReservation() and SetFileBandwidthReservation() functions have been introduced specifically for this purpose. However, I cannot get this to work. I've searched the internet but I cannot find much information on this (and no working code samples seem to exist online).
Code to reproduce:
HANDLE h = ::CreateFile(L"D:\\testfile", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
DWORD periodMilliseconds, bytesPerPeriod, transferSize, numOutstandingRequests;
BOOL discardable;
BOOL result = ::GetFileBandwidthReservation(h, &periodMilliseconds, &bytesPerPeriod,
&discardable, &transferSize, &numOutstandingRequests);
if (result == FALSE) // result is always false!
{
DWORD reason = ::GetLastError(); // reason is always 1!
std::cout << "Error: " << reason << std::endl;
}
result = ::CloseHandle(h);
The call to GetFileBandwidthReservation always returns FALSE which indicates a failure. GetLastError returns 1 which isn't very helpfull. If a try to invoke *Set*FileBandwithReservation I get the same result.
I am testing this on a PC with Windows Server 2008 SP2 (32-bit).
Does anybody have any idea of what I am doing wrong? Any help will be greatly appreciated.
This requires support from the disk device driver. The kind of driver that you'd find in an upscale server, not a consumer level machine. Ask more questions about this at serverfault.com
I feel like there is an obvious answer to this, but it's been eluding me. I've got some legacy code in C++ here that breaks when it tries to call OpenThread(). I'm running it in Visual C++ 2008 Express Edition. The program first gets the ThreadID of the calling thread, and attempts to open it, like so:
ThreadId threadId = IsThreaded() ? thread_id : ::GetCurrentThreadId();
HANDLE threadHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, threadId);
Now here's what I don't understand: if the thread ID is the current thread's ID, isn't it already open? Could that be why it's returning NULL?
Any feedback would be appreciated.
Maybe you're asking for too much access (THREAD_ALL_ACCESS), though I'd think that you'd have pretty much all permissions to your own thread. Try reducing the access to what you really need.
What does GetLastError() return?
Update:
Take a look at this comment from MSDN:
Windows Server 2003 and Windows
XP/2000: The size of the
THREAD_ALL_ACCESS flag increased on
Windows Server 2008 and Windows Vista.
If an application compiled for Windows
Server 2008 and Windows Vista is run
on Windows Server 2003 or Windows
XP/2000, the THREAD_ALL_ACCESS flag is
too large and the function specifying
this flag fails with
ERROR_ACCESS_DENIED. To avoid this
problem, specify the minimum set of
access rights required for the
operation. If THREAD_ALL_ACCESS must
be used, set _WIN32_WINNT to the
minimum operating system targeted by
your application (for example,
#define _WIN32_WINNT _WIN32_WINNT_WINXP ). For more information, see Using the Windows
Headers
Try using _beginthreadex instead of OpenThread.
Example:
HANDLE hThread;
UINT uiThreadId = 0;
hThread = (HANDLE)_beginthreadex(NULL, // Security attributes
0, // stack
&this->ThreadProc, // Thread proc
this, // Thread param
CREATE_SUSPENDED, // creation mode
&uiThreadId); // Thread ID
if (hThread != NULL){
//SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);
ResumeThread(hThread);
m_hThread = hThread;
}
else{
eRetVal = err_ThreadStartErr;
}