Is there a way to detect if a monitor is plugged in? - c++

I have a custom application written in C++ that controls the resolution and other settings on a monitor connected to an embedded system. Sometimes the system is booted headless and run via VNC, but can have a monitor plugged in later (post boot). If that happens he monitor is fed no video until the monitor is enabled. I have found calling "displayswitch /clone" brings the monitor up, but I need to know when the monitor is connected. I have a timer that runs every 5 seconds and looks for the monitor, but I need some API call that can tell me if the monitor is connected.
Here is a bit of psudocode to describe what I'm after (what is executed when the timer expires every 5 seconds).
if(If monitor connected)
{
ShellExecute("displayswitch.exe /clone);
}else
{
//Do Nothing
}
I have tried GetSystemMetrics(SM_CMONITORS) to return the number of monitors, but it returns 1 if the monitor is connected or not. Any other ideas?
Thanks!

Try the following code
BOOL IsDisplayConnected(int displayIndex = 0)
{
DISPLAY_DEVICE device;
device.cb = sizeof(DISPLAY_DEVICE);
return EnumDisplayDevices(NULL, displayIndex, &device, 0);
}
This will return true if Windows identifies a display device with index (AKA identity) 0 (this is what the display control panel uses internally). Otherwise, it will return false false. So by checking the first possible index (which I marked as the default argument), you can find out whether any display device is connected (or at least identified by Windows, which is essentially what you're looking for).

Seems that there is some kind of "default monitor" even if no real monitor is connected.
The function below works for me (tested on a Intel NUC and a Surface 5 tablet).
The idea is to get the device id and check if it contains the string "default_monitor".
bool hasMonitor()
{
// Check if we have a monitor
bool has = false;
// Iterate over all displays and check if we have a valid one.
// If the device ID contains the string default_monitor no monitor is attached.
DISPLAY_DEVICE dd;
dd.cb = sizeof(dd);
int deviceIndex = 0;
while (EnumDisplayDevices(0, deviceIndex, &dd, 0))
{
std::wstring deviceName = dd.DeviceName;
int monitorIndex = 0;
while (EnumDisplayDevices(deviceName.c_str(), monitorIndex, &dd, 0))
{
size_t len = _tcslen(dd.DeviceID);
for (size_t i = 0; i < len; ++i)
dd.DeviceID[i] = _totlower(dd.DeviceID[i]);
has = has || (len > 10 && _tcsstr(dd.DeviceID, L"default_monitor") == nullptr);
++monitorIndex;
}
++deviceIndex;
}
return has;
}

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.

what is the right approach to fire an event in a C++ DLL and handle it in a client(C++ or C# application that consumes the DLL)?

I am trying to build a DLL that reads Raw input, processes the data, and streams it to a client application that consumes this DLL. Both my DLL, and client application will be running in the background, or in the system tray. To achieve this behavior, I plan to use events. While I was trying to learn about the right approach to do this, I found conflicting guidance online and had trouble differentiating between these, and picking the right approach.
This article on event handling in native C++ suggests to setup an event source and event receiver using the event_source and event_receiver attributes. Though this approach might work in my situation, This documentation on event handling informs that event handling, though supported for native C++, is deprecated and will not be supported in future releases. This implies that I should not be using this approach. At the same time, This documentation on handling COM events looks like one potentially correct approach. I however am not able to fully understand the code here. Are there better examples or documentation that I could learn from?
Finally, This article on using C++ events in CLI discusses what I understand is a slightly different approach. The code below shows my approach for registering for input from a Precision Touchpad. I want to then override the WindowProc callback function to read input in the background. Finally, I want my DLL to raise my own events when a touch begins, is in progress, and ends. An application (running in the background) consuming this DLL should then be able to listen for the events I raise, and perform actions.
What is the right, and non-deprecated approach to fire events in a C++ DLL, and handle it in the client?
My Code
// skipping headers and error handeling for brevity.
static std::vector<RAWINPUTDEVICELIST> getRawInputDevices()
{
std::vector<RAWINPUTDEVICELIST> devices(64);
while (true) {
UINT numDevices = devices.size();
UINT ret = GetRawInputDeviceList(&devices[0], &numDevices, sizeof(RAWINPUTDEVICELIST));
if (ret != (UINT)-1) {
devices.resize(ret);
return devices;
}
else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
devices.resize(numDevices);
}
else {
throw win32_error();
}
}
}
static RID_DEVICE_INFO getDeviceInfo(HANDLE HDevice)
{
RID_DEVICE_INFO info;
info.cbSize = sizeof(RID_DEVICE_INFO);
UINT deviceSize;
deviceSize = sizeof(RID_DEVICE_INFO);
if (GetRawInputDeviceInfo(HDevice, RIDI_DEVICEINFO, &info, &deviceSize) == -1)
{
throw win32_error();
}
return info;
}
bool isPrecisionTouchAvailable()
{
bool isDigitizerAvailable = false;
std::vector<RAWINPUTDEVICELIST> devices = getRawInputDevices();
for (std::size_t i = 0; i < devices.size(); ++i)
{
RID_DEVICE_INFO info = getDeviceInfo(devices[i].hDevice);
if (info.dwType == RIM_INPUT && info.hid.usUsagePage == HID_USAGE_PAGE_DIGITIZER && info.hid.usUsage == HID_USAGE_DIGITIZER_TOUCH_PAD)
{
isDigitizerAvailable = true;
break;
}
else {
isDigitizerAvailable = false;
}
}
return isDigitizerAvailable;
}
bool registerTouchpadForInput()
{
bool registrationStatus = false;
bool precisionTouchStatus = isPrecisionTouchAvailable();
if (isPrecisionTouchAvailable != 0)
{
return registrationStatus;
}
else {
RAWINPUTDEVICE rid[1]; //one for precision touch when application is in background. Array because I plan to register for more devices like keyboard once I get things working.
rid[0].usUsagePage = HID_USAGE_PAGE_DIGITIZER; // for touchpad
rid[0].usUsage = HID_USAGE_DIGITIZER_TOUCH_PAD; // usage ID for touchpad
rid[0].dwFlags = RIDEV_INPUTSINK; //to receive events even in the background.
if (RegisterRawInputDevices(rid, 1, sizeof(rid[0])) == false)
{
GetLastError();
//throw "error registering touchpad to get data.";
}
else { registrationStatus = true; }
}
return registrationStatus;
}
When my application launches, I want to call registerTouchpadForInput and let the user know that they will not be able to use my application if they do not have a Precision Touchpad on their device.

libusb_get_string_descriptor_ascii() timeout error?

I'm trying to get the serial number of a USB device using libusb-1.0.
The problem I have is that sometimes the libusb_get_string_descriptor_ascii() function returns -7 (LIBUSB_ERROR_TIMEOUT) in my code, but other times the serial number is correctly written in my array and I can't figure out what is happening. Am I using libusb incorrectly? Thank you.
void EnumerateUsbDevices(uint16_t uVendorId, uint16_t uProductId) {
libusb_context *pContext;
libusb_device **ppDeviceList;
libusb_device_descriptor oDeviceDescriptor;
libusb_device_handle *hHandle;
int iReturnValue = libusb_init(&pContext);
if (iReturnValue != LIBUSB_SUCCESS) {
return;
}
libusb_set_debug(pContext, 3);
ssize_t nbUsbDevices = libusb_get_device_list(pContext, &ppDeviceList);
for (ssize_t i = 0; i < nbUsbDevices; ++i) {
libusb_device *pDevice = ppDeviceList[i];
iReturnValue = libusb_get_device_descriptor(pDevice, &oDeviceDescriptor);
if (iReturnValue != LIBUSB_SUCCESS) {
continue;
}
if (oDeviceDescriptor.idVendor == uVendorId && oDeviceDescriptor.idProduct == uProductId) {
iReturnValue = libusb_open(pDevice, &hHandle);
if (iReturnValue != LIBUSB_SUCCESS) {
continue;
}
unsigned char uSerialNumber[255] = {};
int iSerialNumberSize = libusb_get_string_descriptor_ascii(hHandle, oDeviceDescriptor.iSerialNumber, uSerialNumber, sizeof(uSerialNumber));
std::cout << iSerialNumberSize << std::endl; // Print size of serial number <--
libusb_close(hHandle);
}
}
libusb_free_device_list(ppDeviceList, 1);
libusb_exit(pContext);
}
I see nothing wrong with your code. I would not care to much about timeouts in the context of USB. It is a bus after all and can be occupied with different traffic.
As you may know there is depending on the version of USB a portion of the bandwidth reserved for control transfers. libusb_get_string_descriptor_ascii simply sends all the required control transfers to get the string. If any of those times out it will abort. You can try to send this control transfers yourself and use bigger timeout values but I guess the possibility of a timeout will always be there to wait for you (pun intended).
So it turns out my device was getting into weird states, possibly not being closed properly or the like. Anyway, calling libusb_reset_device(hHandle); just after the libusb_open() call seems to fix my sporadic timeout issue.
libusb_reset_device()

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;

enumdisplayDevices returns multiple instances for one display card

Hi I am using the following code fragment to get number of display adapters in my windows 7 system. I have a NVidia GT 120 which is connected to my monitor, and a NVidia Quadro 4000 which is acting as my GPU processor.
Because both display adapters have more than one output port, with following code, I actually get 2 Display_Device instances for GT120 and 2 for Quadro 4000. My work around of this problem is actually using the DeviceKey component (which MSDN says is not used, but it is in fact a registry key) of the DisplayDevice structure as criteria to remove the duplicate instance.
Did anyone has a better, or official solution to this problem?
FARPROC EnumDisplayDevices;
HINSTANCE hInstUser32;
DISPLAY_DEVICE DispDev;
char szSaveDeviceName[32];
BOOL bRet = TRUE;
hInstUser32 = LoadLibrary("User32.DLL");
if (!hInstUser32) return FALSE;
// Get the address of the EnumDisplayDevices function
EnumDisplayDevices = (FARPROC)GetProcAddress(hInstUser32,"EnumDisplayDevicesA");
if (!EnumDisplayDevices) {
FreeLibrary(hInstUser32);
return FALSE;
}
ZeroMemory(&DispDev, sizeof(DISPLAY_DEVICE));
DispDev.cb = sizeof(DISPLAY_DEVICE);
// After the first call to EnumDisplayDevices,
// DispDev.DeviceString is the adapter name
while (EnumDisplayDevices(NULL, nDeviceIndex++, &DispDev, 0)) {
//getdevice
}
FreeLibrary(hInstUser32);
return bRet;