Is there a way to programmatically launch the "Force Quit Applications" app that can be launched from the 'Apple menu' or by pressing Command-Option-Esc.
I haven't been able to find out whether it's a separate app or perhaps something that can be invoked by a command line parameter to Activity Monitor.
I've tried the simulating the keystrokes but it doesn't seem to work:
CGEventFlags flags = kCGEventFlagMaskAlternate | kCGEventFlagMaskCommand;
CGKeyCode virtualKey = kVK_Escape;
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
CGEventRef KbdEvent = CGEventCreateKeyboardEvent(source, virtualKey, YES);
CGEventSetFlags(KbdEvent, (CGEventFlags)flags);
CGEventTapLocation location = kCGHIDEventTap;
CGEventPost(location, KbdEvent);
CFRelease(KbdEvent);
CFRelease(source);
I also noticed that CGEvents cannot trigger the "Force Quit Applications" window, perhaps it works only on the lower IOHID level (like the Xcode Simulator).
The only way to invoke the window I have found is to use System Events:
system("osascript -l JavaScript -e \"Application('System Events').processes['Finder'].menuBars[0].menus['Apple'].menuItems['Force Quit…'].click()\"");
You can check to see if the window is open with the following:
#include <Carbon/Carbon.h>
int IsForceQuitOpen() {
int found = 0;
CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
CFIndex numWindows = CFArrayGetCount(windowList);
for (int i = 0; i < (int)numWindows; i++) {
CFDictionaryRef info = (CFDictionaryRef)CFArrayGetValueAtIndex(windowList, i);
CFStringRef appName = (CFStringRef)CFDictionaryGetValue(info, kCGWindowOwnerName);
if (CFEqual(appName, CFSTR("loginwindow"))) {
found = 1;
}
}
return found;
}
Related
GetOpenFileName fails with access violation. File must be on DESKTOP and have long name.
Problem occurs only after first successful open of the file. Problem occurs when mouse cursor hovers over file as tool tip about to be displayed.
See the answer below. I'm leaving the original problem description below.
Mike D.
=======================
I'm using GetOpenFileName. I sometimes get a access violation deep inside shell32. The violation never occurs the first time this code is used, it often takes five or six tries. Also it appears that if one selects a file in second or two after the open file window pops up, the violation does not occur. Also, the call stack displayed when I debug this does not include any of my code. It's as if some independent thread is waking up to do something.
Any insights into how I might debug this greatly appreciated!
I made a "hello" world app exhibiting the same behavior. It, however, requires many more tries before it fails. It also seems that one has to switch directories before it will fail.
The GOFN is done from a thread created just for that purpose. Below is the code from the "hello world" app.
typedef struct
{
public:
HWND hWnd;
HINSTANCE hInst;
} def_params, *p_params;
DWORD WINAPI ReadLogFile_DataRecorderThread (PVOID pvoid);
void ReadLogFile_DataRecorder (HWND hWnd, HINSTANCE hInst) // ***************************
{
static def_params Params;
Params.hWnd = hWnd;
Params.hInst = hInst;
HANDLE T = CreateThread (NULL,0,ReadLogFile_DataRecorderThread,&Params,0,NULL);
CloseHandle (T);
return;
}
DWORD WINAPI ReadLogFile_DataRecorderThread (PVOID pvoid)
{
p_params P = (p_params) pvoid;
HWND hWnd = P->hWnd;
HINSTANCE hInst = P->hInst;
char ReadLogFileLastDir[256];
// static def_OpenFileHook Hook;
OPENFILENAME ofn;
char fn[MAX_PATH]="\0";
char filter[32]="Text Files\0*.TXT;\0\0";
char title[]="Open IMC Data Recorder Log File";
char defext[]="TXT";
int status;
// Get File Name
fn[0] = '\0';
ReadLogFileLastDir[0] = '\0';
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWnd;
ofn.hInstance = hInst;
ofn.hInstance = (HINSTANCE) GetWindowLong (hWnd, GWL_HINSTANCE);
ofn.lpstrFilter = filter;
ofn.nFilterIndex = 0;
ofn.lpstrCustomFilter = NULL ;
ofn.nMaxCustFilter = 0 ;
ofn.lpstrFile = fn;
ofn.nMaxFile = sizeof(fn);
ofn.lpstrFileTitle = NULL;
if (ReadLogFileLastDir[0] == '\0')
{
SHGetSpecialFolderPath (NULL,ReadLogFileLastDir,0x0005,false);
};
ofn.lpstrInitialDir = ReadLogFileLastDir;
ofn.lpstrTitle = title;
ofn.Flags = OFN_FILEMUSTEXIST |
OFN_PATHMUSTEXIST |
OFN_EXPLORER |
// OFN_ENABLETEMPLATE |
OFN_ENABLESIZING |
// OFN_ENABLEHOOK |
OFN_READONLY;
ofn.lpstrDefExt = NULL;
ofn.lpfnHook = NULL; // Hook.DialogHook; // hook routine
ofn.lCustData = NULL; // (long) &Hook; // data for hook routine
ofn.lpTemplateName = NULL; // MAKEINTRESOURCE(IDD_HOOKFILEOPEN);
ofn.nFileOffset = 0 ;
ofn.nFileExtension = 0 ;
ofn.lpstrDefExt = defext;
status = GetOpenFileName (&ofn);
int S;
S = CommDlgExtendedError();
return 0;
}
When it fails, the call stack looks like this...
SHELL32! 7ca4e035()
SHELL32! 7cb2dc16()
SHELL32! 7cb2dd5a()
SHELL32! 7cb27361()
SHELL32! 7c9f40a3()
BROWSEUI! 75f81b9a()
SHLWAPI! 77f69548()
NTDLL! 7c927545()
NTDLL! 7c927583()
NTDLL! 7c927645()
NTDLL! 7c92761c()
KERNEL32! 7c80b50b()
Sorry but I am unable to get symbols for these as I have an old Visual C++ :-(
It appears to me that the problem occurs when the GOFN stuff is about to open the popup describing the file as the mouse cursor hovers over the file name.
The set of circumstances causing the problem are somewhat weird. Experiments show one has to do the following in the GOFN window:
Open a file on the DESKTOP
Hover over a long file name
If I do this twice, it always fails. The file name I used was
IMCLOG_20120323_1658_-_20120324_0653_CST_+DST_E2_2_second.TXT
I tried the same thing with NOTEPAD and the same problem occurs!
I found numerous reports of the same problem. For example:
Social.MSDN Problem report
CodeProject question
CodeGuru thread
There was also a Google cached link to a since-deleted MS Connect bug report. As you discovered, the problem seems to be particular to files in the Desktop.
The only suggested solution I found is to call CoInitializeEx(NULL) at the start of the thread, and call CoUninitialize() at the end, so that's worth trying.
Also, the MSDN documentation for GetOpenFileName() says:
Starting with Windows Vista, the Open and Save As common dialog boxes have been superseded by the Common Item Dialog.
So it may be worth discarding GetOpenFileName() completely.
is it possible to create a program that works as console application if started from the console and works as windows program (with GUI) when started otherwise?
If it is possible - how can I do that?
regards
Tobias
If you set the program up to build as a GUI program you can then attempt to attach to the console using AttachConsole(). You you attach OK then you were started from a console and you can proceed to redirect your standard handles to the newly attached console.
In this way you can start up and see if you are being started from a console that you can attach to and if so become a console program. If you cant attach you can show a GUI.
I've had some success with this, the main problem I have is redisplaying the command window's prompt when my program exits (which is how normal console programs operate), but I expect you could do something clever (read the console buffer on start up and find the prompt to redisplay when you exit?) if you really wanted to ...
If you need the program to act as a console application (e.g. print the usage information to the console) you must complile as a console application. A windows application will not have access to the console and cmd.exe will not wait for it to finish before printing the prompt and accepting the next command.
The best solution is to have two versions, one for command line and one for the GUI (which users usually run via a link on the desktop or start menu).
If you insist on using a single binary you will have to live with a console window appearing, at least for a short time. You can get rid of the console window using
FreeConsole();
You can tell that your application was run from GUI if it is the only process attached to the console. You can use GetConsoleProcessList to find the list of processes attached to the console.
This is the answer from Dan Tillett and it is remarkably effective. No flashes, no .com and .exe to trick cmd.exe. Seems to work flawlessly typing the command, in a .bat file, with focus, without focus and as double-click GUI app.
It's the bees knees!
Here is web page describing it, but I've posted it here because if that page goes 404 next month or 2 years from now, the excellent and "most complete" solution I've seen would be "off the grid".
http://www.tillett.info/2013/05/13/how-to-create-a-windows-program-that-works-as-both-as-a-gui-and-console-application/
#define WINVER 0x0501 // Allow use of features specific to Windows XP or later.
#define _WIN32_WINNT 0x0501
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#pragma comment(lib, "User32.lib")
// Attach output of application to parent console
static BOOL attachOutputToConsole(void) {
HANDLE consoleHandleOut, consoleHandleError;
int fdOut, fdError;
FILE *fpOut, *fpError;
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
//redirect unbuffered STDOUT to the console
consoleHandleOut = GetStdHandle(STD_OUTPUT_HANDLE);
fdOut = _open_osfhandle((intptr_t)consoleHandleOut, _O_TEXT);
fpOut = _fdopen(fdOut, "w" );
*stdout = *fpOut;
setvbuf(stdout, NULL, _IONBF, 0 );
//redirect unbuffered STDERR to the console
consoleHandleError = GetStdHandle(STD_ERROR_HANDLE);
fdError = _open_osfhandle((intptr_t)consoleHandleError, _O_TEXT);
fpError = _fdopen(fdError, "w" );
*stderr = *fpError;
setvbuf(stderr, NULL, _IONBF, 0 );
return TRUE;
}
//Not a console application
return FALSE;
}
//Send the "enter" to the console to release the command prompt on the parent console
static void sendEnterKey(void) {
INPUT ip;
// Set up a generic keyboard event.
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0; // hardware scan code for key
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
//Send the "Enter" key
ip.ki.wVk = 0x0D; // virtual-key code for the "Enter" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
// Release the "Enter" key
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow) {
int argc = __argc;
char **argv = __argv;
UNREFERENCED_PARAMETER(hInstance);
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
UNREFERENCED_PARAMETER(nCmdShow);
BOOL console;
int i;
//Is the program running as console or GUI application
console = attachOutputToConsole();
if (console) {
//Print to stdout
printf("Program running as console application\n");
for (i = 0; i < argc; i++) {
printf("argv[%d] %s\n", i, argv[i]);
}
//Print to stderr
fprintf(stderr, "Output to stderr\n");
}
else {
MessageBox(NULL, "Program running as windows gui application",
"Windows GUI Application", MB_OK | MB_SETFOREGROUND);
}
//Send "enter" to release application from the console
//This is a hack, but if not used the console doesn't know the application has returned
//"enter" only sent if the console window is in focus
if (console && GetConsoleWindow() == GetForegroundWindow()){
sendEnterKey();
}
return 0;
}
The program itself will never know how it was started. Unless you are willing to pass an execution arguments to the program. For example: program.exe -GUI ... you can capture the passed parameters and decide how the program should run based on parameters passed.
your program whould be something like:
class MainClass
{
public static int Main(string[] args)
{
// Test if input arguments were supplied:
if(args[0]=="GUI")
new myGUI().show(); //runs an instance of your gui
else
//you know what should go here
}
}
You can sort of guess whether you are started from the console or not by doing this:
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
fConsole = csbi.dwCursorPosition.X | csbi.dwCursorPosition.Y;
It's a guess -- if your cursor position is not 0,0 than you are in a console and can work as a console app. Otherwise go and create your windows.
Another way to guess is to look at the process tree and see what process launched your app. If it is cmd.exe go in console mode, otherwise go into GUI mode.
Make it a console application and put this into the code:
void ConsoleWindowVisible(bool show)
{
DWORD dummy;
if
(
!show && // Trying to hide
GetConsoleProcessList(&dummy, 1) == 1 // Have our own console window
)
ShowWindow(GetConsoleWindow, SW_HIDE); // Hide the window
else // Trying to show or use parent console window
ShowWindow(GetConsoleWindow, SW_NORMAL); // Show the window
}
int main(int argc, char** argv)
{
ConsoleWindowVisible(false);
}
Cheers.
gor.f.gyolchanyan#gmail.com
I want to create a virtual keyboard in osx. Is it possible? I mean can I make a program that gives same signals than real keyboard. Example of this kind of keyboard would be onscreen keyboard, or keybord viewer (does it have necessary interface btw).
How low should I start? Should I make a device driver e.g. virtual (wireless) keyboard? Or does cocoa etc. have the necessary stuff?
The requirements I have are:
- a list of tuples (time, key_down/key_up, key_code) corresponds to person typing
- virtual keyboard should work side by side with the real one (like touchpad and bluetooh mouse)
- this should work with every program. Hardest examples I can find are: Terminal+vim, remote desktop, games like starcraft
Sample code and links are more than welcome.
edit: The main point is to have programmatic access to keystrokes. There are similar programs but they are with closed source (e.g. http://www.assistiveware.com/keystrokes.php). I want to know what is the best way to make this kind of program.
edit 2: Now I got this party started. Below is a copy-edit-paste-try-something-else code that basically includes all necessary parts to make a virtual keyboard. In this case, every time I press 'a' the virtual keyboard presses 'z'. There is a bug, that there is multiple 'z's added...
#import <ApplicationServices/ApplicationServices.h>
CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
UniChar unicodeString[101];
UniCharCount unicharCount;
char chars[2];
int i,j,charsLen;
CGEventRef zDown;
CGEventRef zUp;
zDown = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)6, true);
zUp = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)6, false);
//printf("%u %u\n", (uint32_t)type, (uint32_t) event);
CGEventKeyboardGetUnicodeString(event, 100, &unicharCount, unicodeString);
for (i=0; i < unicharCount; i++)
{
if (unicodeString[i] > 127) {
chars[0] = (unicodeString[i] >> 8) & (1 << 8) - 1;
chars[1] = unicodeString[i] & (1 << 8) - 1;
charsLen = 2;
} else {
charsLen = 1;
chars[0] = unicodeString[i];
}
//for (j = 0; j < charsLen; j++) printf("%c", chars[j]);
}
if (chars[0] == 'a')
{
CGEventPost(kCGHIDEventTap, zDown);
CGEventPost(kCGHIDEventTap, zUp);
}
return event;
}
int main (int argc, const char * argv[]) {
CFMachPortRef eventTap;
CFRunLoopSourceRef runLoopSource;
eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0, kCGEventMaskForAllEvents, myCGEventCallback, NULL);
runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(eventTap, true);
CFRunLoopRun();
return 0;
}
br,
Juha
You could do this using Quartz Event Taps, which provides a:
...C API for event taps, which are
filters used to observe and alter the
stream of low-level user input events
in Mac OS X
On the Mac, there is the keyboard view. Why can't you use that?
Currently I am developing a small application that I wanna to remove the airport settings.
Firstly, I use shell command networksetup to delete the preferred networks, and then delete the recorded-password in keychain by AppleScript. But I found that the airports' passwords recorded in both system.keychain and login.keychain. I write the AppleScript such as:
tell application "Keychain Scripting"
set keychainName to "Login.keychain" -- "system.keychain"
set gkeyCount to count generic key of keychain keychainName
repeat with keyIndex from 1 to gkeyCount
log keyIndex
if (account of generic key keyIndex of keychain keychainName is "ABCD") then
delete generic key keyIndex of keychain keychainName
log "find the key"
end if
end repeat
end tell
For keychain "login.keychain", it's no problem, but for keychain "System.keychain", it failed with a popup show me "Keychain Scripting got an error: File not open with write permission."
Any idea?
Edit: This doesn't work. Ah well, it was just a guess anyway. I'm leaving the answer up for posterity.
My guess is that the problem is that the system keychain is locked. I can't really test this, since I don't want to delete things from my keychain, but I did confirm that my system keychain defaults to being locked, and this seems like the sort of thing which would cause the error you see. Thus, I'd do something like this:
tell application "Keychain Scripting"
set keychainName to "Login.keychain" -- "system.keychain"
set doRelock to false
set kc to keychain keychainName
if locked of kc then
unlock kc
set doRelock to true
end if
try
set gkeyCount to count generic key of kc
repeat with keyIndex from 1 to gkeyCount
log keyIndex
if (account of generic key keyIndex of kc is "ABCD") then
delete generic key keyIndex of keychain keychainName
log "find the key"
end if
end repeat
if doRelock then
lock kc
set doRelock to false
end if
on error
if doRelock then lock kc
end try
end tell
The idea is to first unlocked the keychain if you need to, and then make sure you relock it when you're done. Let me know if this does or doesn't work—like I said, I had nothing I wanted to test this on.
I'v got the solution with Objective-C:
BOOL deleteItemOfSystemKeychain(NSArray *accountList)
{
OSStatus retVal;
SecKeychainRef systemKeychainRef;
SecKeychainItemRef kcItem;
AuthorizationRef authRef;
AuthorizationItem right = { "system.keychain.modify", 0, NULL, 0 };
AuthorizationRights rightSet = { 1, &right };
/* Create authorization to access the system.keychain */
retVal = AuthorizationCreate(&rightSet, kAuthorizationEmptyEnvironment, kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed, &authRef);
if (retVal != errSecSuccess) {
NSLog(#"Failed to get right to modify system keychain %#", SecCopyErrorMessageString(retVal, NULL));
return FALSE;
}
SecKeychainSetUserInteractionAllowed(TRUE);
retVal = SecKeychainOpen("/Library/Keychains/System.keychain", &systemKeychainRef);
if (retVal != errSecSuccess) {
NSLog(#"Failed to open System keychain %#", SecCopyErrorMessageString(retVal, NULL));
return FALSE;
}
retVal = SecKeychainUnlock(systemKeychainRef, 0, NULL, FALSE);
if (retVal != errSecSuccess) {
NSLog(#"Failed to unlock System keychain %#", SecCopyErrorMessageString(retVal, NULL));
return FALSE;
}
// retVal = SecKeychainSetSearchList(CFArrayRef searchList);
/* Search the item we wanna to delete */
CFArrayRef arrayRef;
SecKeychainCopySearchList(&arrayRef);
SecKeychainSetSearchList(arrayRef);
CFRelease(arrayRef);
SecKeychainSearchRef searchRef;
SecKeychainSearchCreateFromAttributes(NULL,
kSecGenericPasswordItemClass,
NULL,
&searchRef);
while (errSecItemNotFound != SecKeychainSearchCopyNext(searchRef, &kcItem))
{
static int iCount = 1;
SecKeychainAttributeInfo *info;
SecKeychainAttributeInfoForItemID(systemKeychainRef,
CSSM_DL_DB_RECORD_GENERIC_PASSWORD,
&info);
SecKeychainAttributeList *attributes;
SecKeychainItemCopyAttributesAndData(kcItem, info, NULL, &attributes, 0, NULL);
for (int i = 0; i < attributes->count; i ++)
{
SecKeychainAttribute attr = attributes->attr[i];
char attr_tag[5] = {0};
attr_tag[0] = ((char *)&attr.tag)[3];
attr_tag[1] = ((char *)&attr.tag)[2];
attr_tag[2] = ((char *)&attr.tag)[1];
attr_tag[3] = ((char *)&attr.tag)[0];
NSString *attrTag = [NSString stringWithCString:attr_tag encoding:NSUTF8StringEncoding];
NSString *attrValue = [[[NSString alloc] initWithData:[NSData dataWithBytes:attr.data
length:attr.length]
encoding:NSUTF8StringEncoding] autorelease];
if ([attrTag isEqualToString:#"acct"])
{
NSLog(#"Check Item %d:%#:%#", iCount++, attrTag, attrValue);
for (NSString *str in accountList)
{
if ([attrValue isEqualToString:str])
{
NSLog(#"delete %#...", str);
retVal = SecKeychainItemDelete(kcItem);
if (retVal != errSecSuccess)
{
NSLog(#"delete %# failed...", str);
}
}
}
}
}
}
return TRUE;
}
Note: run this as root/admin.
:)
You need to open the file with writing permissions: see books_google_com from AppleScript: the comprehensive guide to scripting and automation on Mac OS X
I know, that I can use Apple Event Object Model for moving and resizing windows of Cocoa applications. But what can I use for Carbon applications?
Peter was right, you can access to bounds of any window using the following AppleScript:
tell application "System Events"
set allProcesses to application processes
repeat with i from 1 to count allProcesses
tell process i
repeat with x from 1 to (count windows)
position of window x
size of window x
end repeat
end tell
end repeat
end tell
You can also use the Accessibility API. This is how I think Optimal Layout is doing it.
First you have make sure your app has permission to use it.
BOOL checkForAccessibility()
{
NSDictionary *options = #{(__bridge id) kAXTrustedCheckOptionPrompt : #YES};
return AXIsProcessTrustedWithOptions((__bridge CFDictionaryRef) options);
}
Next, use the NSWorkspace::RunningApplications to get the PID of the app whose window you want to manipulate.
NSArray<NSRunningApplication *> *runningApps =[[NSWorkspace sharedWorkspace] runningApplications];
for( NSRunningApplication *app in runningApps )
{
if( [app bundleIdentifier] != nil && [[app bundleIdentifier] compare:#"IdentifierOfAppYouWantToFindHere"] == 0 )
{
PID = [app processIdentifier];
}
}
Then use the PID to get access to the main window reference using the Accessibility API.
AXUIElementRef app = AXUIElementCreateApplication( PID );
AXUIElementRef win;
AXError error = AXUIElementCopyAttributeValue( app, kAXMainWindowAttribute, ( CFTypeRef* )&win );
while( error != kAXErrorSuccess ) // wait for it... wait for it.... YaY found me a window! waiting while program loads.
error = AXUIElementCopyAttributeValue( app, kAXMainWindowAttribute, ( CFTypeRef* )&win );
Now you can set the size and position using something like this:
CGSize windowSize;
CGPoint windowPosition;
windowSize.width = width;
windowSize.height = height;
windowPosition.x = x;
windowPosition.y = y;
AXValueRef temp = AXValueCreate( kAXValueCGSizeType, &windowSize );
AXUIElementSetAttributeValue( win, kAXSizeAttribute, temp );
temp = AXValueCreate( kAXValueCGPointType, &windowPosition );
AXUIElementSetAttributeValue( win, kAXPositionAttribute, temp );
CFRelease( temp );
CFRelease( win );
Same thing. You can use Apple Events on any scriptable application, and Apple Events and scriptability are a lot older than Carbon.