Is there a Windows API to detect if a laptop lid is closed (= integrated laptop screen is off)?
There's already the "same" question asked:
Get current laptop lid state
Though the (self-)accepted answer relies on an integrated screen "device" being removed, when the lid closes. But that does not happen on all laptops. Some keep the screen "available" to the system (while not displaying anything actually), even when the lid is closed. This means that the Windows desktop still stretches over the closed screen (if the "Multiple Displays" settings is set to "Extend these displays").
I have not determined yet, if this behavior can be configured or if it is driver-specific:
Remove closed laptop screen from Windows desktop
But even on such systems, the OS knows that the lid closes, as it can shutdown/sleep the machine when it does. And it broadcasts a notification (WM_POWERBROADCAST):
Detect laptop lid closure and opening
Background: I have an application that starts on the same display, where it was closed the last time. If it was closed on the integrated laptop screen and the lid is closed the next time the application starts (because the user is now using an external monitor), my application starts on the now-invisible integrated laptop screen.
Hence I want to detect that the lid is closed and force the application onto an external monitor.
So I'm looking either for a way to detect, if lid is closed. Or for a way to detect, that a particular screen is off (what would be a cleaner solution).
Sounds like you don't really care if the lid is closed or not and just want to know if the screen area where you are about to launch your application is available or not.
If the OS "still uses the shut off screen for its extended desktop" then that means (from the OS's point of view) that the screen is available to be used for applications. In other words - your application would not be the only one suffering from that issue. Though I have to say I have never observed that particular behavior first-hand.
If you need to move your application while it is running then you can register for the RegisterPowerSettingNotification and act on it.
However if you are launching and need to know if the screen is on or off you have two options:
EnumDisplayDevices
This will provide you with the information on whether your screen is attached to a desktop and is active. This is "system info" that you get from the API in User32.dll
DISPLAY_DEVICE ddi;
ddi.cb = sizeof(ddi);
DWORD iDevNum = 0; // or iterate 0..15
EnumDisplayDevices(NULL, iDevNum, &ddi, /*EDD_GET_DEVICE_INTERFACE_NAME*/0);
if( (ddi.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0 &&
(ddi.StateFlags & DISPLAY_DEVICE_ACTIVE) != 0 ){...}
DXGI (DX11)
This gives you basically the same info as above but with a more modern approach (and potentially fewer false positives). Of course that would require you to link-in DXGI for this to work and include the header which will increase your application size:
#include <atltypes.h>
IDXGIAdapter * pAdapter;
std::vector <IDXGIAdapter*> vAdapters;
IDXGIFactory* pFactory = NULL;
// Create a DXGIFactory object.
if(FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory) ,(void**)&pFactory)))
{
return;
}
for(UINT i = 0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; ++i){
DXGI_ADAPTER_DESC ad = {0};
if(SUCCEEDED(pAdapter->GetDesc(&ad))){
UINT j = 0;
IDXGIOutput * pOutput;
while(pAdapter->EnumOutputs(j, &pOutput) != DXGI_ERROR_NOT_FOUND)
{
DXGI_OUTPUT_DESC od = {0};
if(SUCCEEDED(pOutput->GetDesc(&od))){
// in here you can access od.DesktopCoordinates
// od.AttachedToDesktop tells you if the screen is attached
}
pOutput->Release();
++j;
}
}
pAdapter->Release();
}
if(pFactory)
{
pFactory->Release();
}
Hope that helps.
Direct3D9
This method also provides display information but in a slightly different way - via a list of adapters and monitors attached to those adapters. Remember to link-in d3d9 library for this to work:
void d3d_adapterInfo(IDirect3D9 * _pD3D9, UINT _n)
{
D3DADAPTER_IDENTIFIER9 id;
const DWORD flags = 0;
if(SUCCEEDED(_pD3D9->GetAdapterIdentifier(_n, flags, &id))){
// id provides info on Driver, Description, Name
HMONITOR hm = _pD3D9->GetAdapterMonitor(_n);
// and based on that hm you get the same monitor info as
// with the first method
}
}
void d3d_enumDisplays()
{
cout << endl << "--- Information by Direct3D9 ---" << endl;
IDirect3D9 * pD3D9 = Direct3DCreate9(D3D_SDK_VERSION);
const auto nAdapters = pD3D9->GetAdapterCount();
cout << "A total of " << nAdapters << " adapters are listed by Direct3D9" << endl;
for(UINT i = 0; i < nAdapters; ++i){
d3d_adapterInfo(pD3D9, i);
}
pD3D9->Release();
}
All 3 code snippets are from some of my projects so you can just copy-paste the code and it should work (baring some minor fixes for missing functions or variables as I was modifying the code on-the-fly to reduce its size when posted it here)
Related
Both QPrinterInfo::availablePrinters() and QPrinterInfo::availablePrinterNames() return an empty list on Windows PCs that nevertheless show printers when displayed in the Control Panel ➔ Devices & Printers.
The printers are not connected to the computer. I would at least expect Qt to display the "Microsoft Print to PDF". This is also failing on PCs with WiFi printer connections.
This works on PCs with printers, either connected directly, or over a network.
Any suggestions on how to get a Printer dialog to display, that is populated with the same list of printers as a native app?
QString buf;
QStringList allPrintersName = QPrinterInfo::availablePrinterNames();
QList <QString>::const_iterator sit;
for(sit = allPrintersName.cbegin(); sit != allPrintersName.cend(); sit++)
buf += *sit + "\n";
QMessageBox(QMessageBox::NoIcon, "Printer Names", buf).exec(); // empty message
buf = "";
QList<QPrinterInfo> allPrintersInfo = QPrinterInfo::availablePrinters();
QList <QPrinterInfo>::const_iterator pit;
for(pit = allPrintersInfo.cbegin(); pit != allPrintersInfo.cend(); pit++)
buf += pit->printerName() + "\n";
QMessageBox(QMessageBox::NoIcon, "QPrinterInfo", buf).exec(); // empty message
The problem was caused by not knowing that I needed to install the following in my app folder:
..\printsupport\windowsprintersupport.dll
Answered here:
https://forum.qt.io/topic/39319/solved-qprinterinfo-availableprinters-don-t-list-available-printers
https://forum.qt.io/post/197518
In our application that we've had for 15+ years, we have a type of progress bar.
This progress bar is for long lasting C++ operations and there is also the case for when we make a COM call and it takes a long time for the COM call to return.
In general, we want the user to know that something is taking a long time to complete and give him a chance to cancel if he thinks it is taking too much time.
For COM operations, many years ago we implemented a custom IMessageFilter for COM calls that take too long. We would like the user to be able to cancel but also for the prompt to cancel go away on its own when the operation completes. It has been working fine for years. Most of our customers are conservative and are still running Windows 7. Recently a customer using Windows 10 has found an issue where a COM call on Windows 10 never seems to never finish.
Our progress bar comes up and the progress control cycles and recycles, but the operation never seems to finish. After investigating it, it seems that the ICancelMethodCalls::TestCancel() method always returns RPC_S_CALLPENDING, it never returns RPC_E_CALL_COMPLETE. On Windows 7, previous versions of Windows, and Windows 8.1, it works fine, but not on Windows 10.
I created a minimal test solution in Visual Studio 2013 that demonstrates the problem. One project is an ATL server, and the other project is an MFC client application. A link to a zip file of a sample solution is here: https://www.dropbox.com/s/1dkchplsi7d6tda/MyTimeOutServer.zip?dl=0
Basically the ATL server has a property that sets a delay, and a method that just waits the delay length. The purpose is to simulate a COM operation that is taking too long.
interface IMyTimoutServer : IDispatch{
[propget, id(1), helpstring("Timeout value in milliseconds")] HRESULT TimeOut([out, retval] LONG* pVal);
[propput, id(1), helpstring("Timeout value in milliseconds")] HRESULT TimeOut([in] LONG newVal);
[id(2)] HRESULT DoTimeOut([out, retval] VARIANT_BOOL* Result);
};
The next important thing is the IMessageFilter in the client application. At some point, someone decided it was good to derive from COleMessageFilter, the default MFC implementation. (Let's not argue whether that is a good idea.)
The important methods of the the class are the MessagePending() and MyNotResponding().
DWORD CMyMessageFilter::XMyMessageFilter::MessagePending(HTASK htaskCallee, DWORD dwTickCount, DWORD dwPendingType)
{
METHOD_PROLOGUE_EX(CMyMessageFilter, MyMessageFilter);
ASSERT_VALID(pThis);
MSG msg;
if (dwTickCount > pThis->m_nTimeout && !pThis->m_bUnblocking && pThis->IsSignificantMessage(&msg))
{
if (pThis->m_bEnableNotResponding)
{
pThis->m_bUnblocking = TRUE; // avoid reentrant calls
// eat all mouse and keyboard messages in our queue
while (PeekMessage(&msg, NULL, WM_MOUSEFIRST, AFX_WM_MOUSELAST, PM_REMOVE | PM_NOYIELD));
while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE | PM_NOYIELD));
// show not responding dialog
pThis->m_dwTickCount = dwTickCount;
bool bCancel = pThis->MyNotResponding(htaskCallee) == RPC_E_CALL_CANCELED;
pThis->m_bUnblocking = FALSE;
return bCancel ? PENDINGMSG_CANCELCALL : PENDINGMSG_WAITNOPROCESS; // if canceled, the COM call will return RPC_E_CALL_CANCELED
}
}
// don't process re-entrant messages
if (pThis->m_bUnblocking)
return PENDINGMSG_WAITDEFPROCESS;
// allow application to process pending message
if (::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE | PM_NOYIELD))
pThis->OnMessagePending(&msg); // IK: could also return a value from extended OnMessagePending() to cancel the call
// by default we return pending MSG wait
return PENDINGMSG_WAITNOPROCESS;
}
After a timeout, we display a status type window that updates in the NotMyResponding() method.
int CMyMessageFilter::MyNotResponding(HTASK hTaskBusy)
{
TRY
{
CComPtr<ICancelMethodCalls> pCancel;
HRESULT hRes = ::CoGetCancelObject(0, IID_ICancelMethodCalls, (void**)&pCancel);
ATLASSERT(SUCCEEDED(hRes)); // COM should automatically create Cancel objects for pending calls [both on client and server]
if (pCancel == NULL)
{
return COleBusyDialog::retry;
}
m_pFrame->EnableWindow(FALSE);
CMyCancelDlg dlg;
dlg.Create(CMyCancelDlg::IDD);
dlg.ShowWindow(SW_SHOWNORMAL);
HWND hWndDlg = dlg.GetSafeHwnd();
do
{
MSG msg;
for (int i = 0; i < 100 && PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD); ++i)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (dlg.StepAndCheckCancel())
{
dlg.DestroyWindow();
m_pFrame->EnableWindow(TRUE);
return RPC_E_CALL_CANCELED; // signals to MessagePending() that the COM call should be cancelled
}
Sleep(250); // this call has been pending for many seconds now... sleep for some time to avoid CPU utilization by this loop and yield if needed
hRes = pCancel->TestCancel();
} while (hRes == RPC_S_CALLPENDING);
ATLASSERT(hRes == RPC_E_CALL_COMPLETE);
dlg.DestroyWindow();
m_pFrame->EnableWindow(TRUE);
}
END_TRY
return RPC_E_CALL_COMPLETE;
}
Basically, in MyNotResponding(), we create a Cancel object, create a window with a cancel button, pump messsages, and look for either a press on the cancel button or if TestCancel() returns something other than RPC_S_CALLPENDING.
Well, on Windows 10, it stays in the loop and RPC_S_CALLPENDING is always returned from TestCancel().
Has anyone seen anything like this on Windows 10? Are we doing something wrong that we are really only getting lucky on Windows 7?
The default implementation of the MFC puts up an OLEUIBusy dialog which pumps messages. It just never tests the cancel object.
I'm learning how to build OSX applications, and I was wondering if there is a way to check if there is some audio being outputted by any application on the system? Thanks
I think this can be checked with the kAudioDevicePropertyDeviceIsRunningSomewhere property.
From the header doc:
A UInt32 where 1 means that the AudioDevice is running in at least one process on the system and 0 means that it isn't running at all.
Pseudo-y code:
bool isRunningSomewhere(AudioDeviceID deviceId) {
uint32 val;
uint32 size = sizeof(val);
AudioObjectPropertyAddress pa = { kAudioDevicePropertyDeviceIsRunningSomewhere, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
AudioObjectGetPropertyData(deviceId, &pa, 0, NULL, &size, &val);
return val == 1;
}
This should tell you if the device is being used (i.e. has an active IOProc.) But it won't tell you if that IOProc is just sending silence.
This can't be done at the user application level. It might be possible by installing an OS X kext (kernel extension) or a custom audio device driver, which requires sudo privileges and possibly a reboot.
I am writing the driver that can directly write data to the frame buffer, so that I can show the secret message on the screen while the applications in user space can't get it. Below is my code that trying to write the value to the frame buffer, but after I write the value to the frame buffer, the values i retrieved from the frame buffer are all 0.
I am puzzled, anyone knows the reason? Or anyone knows how to display a message on the screen while the applications in the user space can't get the content of the message? Thanks a lot!
#define FRAME_BUFFER_PHYSICAL_ADDRESS 0xA0000
#define BUFFER_SIZE 0x20000
void showMessage()
{
int i;
int *vAddr;
PHYSICAL_ADDRESS pAddr;
pAddr.QuadPart = FRAME_BUFFER_PHYSICAL_ADDRESS;
vAddr = (int *)MmMapIoSpace(pAddr, BUFFER_SIZE, MmNonCached);
KdPrint(("Virtual address is %p", vAddr));
for(i = 0; i < BUFFER_SIZE / 4; i++)
{
vAddr[i] = 0x11223344;
}
for(i = 0; i < 0x80; i++)
{
KdPrint(("Value: %d", vAddr[i])); // output are all zero
}
MmUnmapIoSpace(vAddr, BUFFER_SIZE);
}
You must map the shared memory during device start up. I assume that showMessage isn't called during the start up. See more here.
Regarding displaying message on the screen - it must involve user-space interaction since GUI is a user-space component. I suppose you could notify some GUI listener without other applications involvement.
Memory mapped IO isn't designed to act exactly like memory (retrieving data that is placed there in the same form it was stored). The writes into the 0xA0000+ range are writes into PORTS in the video device's IO space (from its perspective); So long as the appropriate writes result in the appropriate pixels lighting up, then the video device has done its job from the perspective of people that write drivers for screen rendering (or old DOS code where memory was a free-for-all without a user-space/kernel-space division). But such code never had a need to store data that would later be retrieved from the video segment. Therefore typical memory semantics would generally not have been implemented (waste of hardware and effort). Here, these randoms talk about it:
Magic number with MmMapIoSpace
I'm trying to change my process' name as it appears in ps and Activity Monitor at runtime. I found several notes that there is no portable way to do this (which I don't care about).
Here's what I tried. None of these approaches worked for me.
Changing argv[0] (seems to be the way to go on some Unix systems)
Calling [[NSProcessInfo processInfo] setProcessName:#"someName"]
Calling setprogname (calling getprogname returns the name I set, but that is irrelevant)
I also read about a function called setproctitle which should be defined in stdlib.h if it is available, but it's not there.
There must be a way to accomplish this because QTKitServer - the faceless decoder for QuickTime Player X - has its corresponding QuickTime Player's PID in its process name.
Does anybody have a clue about how to accomplish this? I'd very much prefer a Core Foundation or POSIXy way over an Objective-C method to do this.
Thanks,
Marco
Edit: If it is in any way relevant, I'm using Mac OS X 10.6.5 and Xcode 3.2.5
There are good reasons to change the process name. Java software should change process names because when running different java tools I want to see which java process is for which tool.
Chromium does it: http://src.chromium.org/viewvc/chrome/trunk/src/base/mac/mac_util.mm.
Node.js uses same code to implement Process.title = 'newtitle': https://github.com/joyent/node/blob/master/src/platform_darwin_proctitle.cc
Note: This fails if someone does su to a different not logged-in user: https://github.com/joyent/node/issues/1727
Here the source code in its full complex glory. By the way, someone told me it also works for Mac OS X Lion and also fails with su.
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
void SetProcessName(CFStringRef process_name) {
if (!process_name || CFStringGetLength(process_name) == 0) {
NOTREACHED() << "SetProcessName given bad name.";
return;
}
if (![NSThread isMainThread]) {
NOTREACHED() << "Should only set process name from main thread.";
return;
}
// Warning: here be dragons! This is SPI reverse-engineered from WebKit's
// plugin host, and could break at any time (although realistically it's only
// likely to break in a new major release).
// When 10.7 is available, check that this still works, and update this
// comment for 10.8.
// Private CFType used in these LaunchServices calls.
typedef CFTypeRef PrivateLSASN;
typedef PrivateLSASN (*LSGetCurrentApplicationASNType)();
typedef OSStatus (*LSSetApplicationInformationItemType)(int, PrivateLSASN,
CFStringRef,
CFStringRef,
CFDictionaryRef*);
static LSGetCurrentApplicationASNType ls_get_current_application_asn_func =
NULL;
static LSSetApplicationInformationItemType
ls_set_application_information_item_func = NULL;
static CFStringRef ls_display_name_key = NULL;
static bool did_symbol_lookup = false;
if (!did_symbol_lookup) {
did_symbol_lookup = true;
CFBundleRef launch_services_bundle =
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
if (!launch_services_bundle) {
LOG(ERROR) << "Failed to look up LaunchServices bundle";
return;
}
ls_get_current_application_asn_func =
reinterpret_cast<LSGetCurrentApplicationASNType>(
CFBundleGetFunctionPointerForName(
launch_services_bundle, CFSTR("_LSGetCurrentApplicationASN")));
if (!ls_get_current_application_asn_func)
LOG(ERROR) << "Could not find _LSGetCurrentApplicationASN";
ls_set_application_information_item_func =
reinterpret_cast<LSSetApplicationInformationItemType>(
CFBundleGetFunctionPointerForName(
launch_services_bundle,
CFSTR("_LSSetApplicationInformationItem")));
if (!ls_set_application_information_item_func)
LOG(ERROR) << "Could not find _LSSetApplicationInformationItem";
CFStringRef* key_pointer = reinterpret_cast<CFStringRef*>(
CFBundleGetDataPointerForName(launch_services_bundle,
CFSTR("_kLSDisplayNameKey")));
ls_display_name_key = key_pointer ? *key_pointer : NULL;
if (!ls_display_name_key)
LOG(ERROR) << "Could not find _kLSDisplayNameKey";
// Internally, this call relies on the Mach ports that are started up by the
// Carbon Process Manager. In debug builds this usually happens due to how
// the logging layers are started up; but in release, it isn't started in as
// much of a defined order. So if the symbols had to be loaded, go ahead
// and force a call to make sure the manager has been initialized and hence
// the ports are opened.
ProcessSerialNumber psn;
GetCurrentProcess(&psn);
}
if (!ls_get_current_application_asn_func ||
!ls_set_application_information_item_func ||
!ls_display_name_key) {
return;
}
PrivateLSASN asn = ls_get_current_application_asn_func();
// Constant used by WebKit; what exactly it means is unknown.
const int magic_session_constant = -2;
OSErr err =
ls_set_application_information_item_func(magic_session_constant, asn,
ls_display_name_key,
process_name,
NULL /* optional out param */);
LOG_IF(ERROR, err) << "Call to set process name failed, err " << err;
}
Edit: It's a complex and confusing problem.
On OS X there is no setproctitle(3). One has to write into the argv array (ugly
and a bit dangerous because it is possible to overwrite some environment variables with bogus stuff). Done correctly it works very well.
Additionally Apple has the ActivityMonitor application, something like the Task Manager under Windows. The code above manipulates ActivityMonitor but this manipulation doesn't seem to be encouraged by Apple (hence the use of undocumented functions).
Important: ps and ActivityMonitor don't show the same information.
Also important: ActivityMonitor is not available if you don't have GUI. This can happen if you ssh in to a remote Apple box and there is nobody logged in by GUI. Sadly there is a bug by Apple IMO. Just querying if there is a GUI sends an annoying warning message to stderr.
Summary: If you need to change ActivityMonitor, use the code above. If you have GUI-less situations and and dislike warnings on stderr, redirect stderr temporarily to /dev/null during the call of SetProcessName. If you need to change ps information, write into argv.
You can use the lsappinfo tool which comes with macOS since at least 10.6 and up to present day (10.13.2):
Shell:
lsappinfo setinfo <PID> --name <NAME>
C++:
#include <sstream>
#include <string>
#include <stdlib.h>
void setProcessName (pid_t pid, std::string name)
{
std::ostringstream cmd;
cmd << "/usr/bin/lsappinfo setinfo " << pid;
cmd << " --name \"" << name << "\"";
system (cmd.str().c_str());
}