iOS 6 EXC_BAD_ACCESS in SampleFTPSample code - ftp-client

I run the SampleFTPSample source code (iOS6.0 SDK, Xcode4.5)which downloaded from iOS Developer Center.
SampleFTPSample
as the Images, when I retrieved a list from ftpServer, sometimes will get EXC_BAD_ACCESS error. I have not modified the code, I don't know why, and How can I fixed it?
Thank you very much.

do this by setting the kCFStreamPropertyFTPAttemptPersistentConnection property to false, immediately after creating the stream (using CFReadStreamCreateWithFTPURL). Here's what that might look like:
success = [self.networkStream setProperty:(__bridge id) kCFBooleanFalse
forKey:(__bridge NSString *) kCFStreamPropertyFTPAttemptPersistentConnection
];
assert(success);

yeahh!! I finally got the solution. I invoked uialertview show after main thread gets finish.So that it wont crash now. It is in mine case. So don't have an exact answer but you can also apply this
peterlawn. May be it will be usefull to you to as well. !!

- (void)_startReceive:(NSString*) urlPath
{
BOOL success;
NSURL * url;
CFReadStreamRef ftpStream;
assert(self.networkStream == nil); // don't tap receive twice in a row!
// First get and check the URL.
if(urlPath != nil)
{
...url = FTP_URL here...
}
success = (url != nil);
// If the URL is bogus, let the user know. Otherwise kick off the connection.
if ( ! success)
{
[self _updateStatus:#"Invalid URL"];
}
else
{
// Create the mutable data into which we will receive the listing.
self.listData = [NSMutableData data];
assert(self.listData != nil);
// Open a CFFTPStream for the URL.
ftpStream = CFReadStreamCreateWithFTPURL(NULL, (__bridge CFURLRef) url);
assert(ftpStream != NULL);
self.networkStream = (__bridge NSInputStream *) ftpStream;
success = [self.networkStream setProperty:(__bridge id) kCFBooleanFalse
forKey:(__bridge NSString *) kCFStreamPropertyFTPAttemptPersistentConnection
];
assert(success);
self.networkStream.delegate = self;
[self.networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop]forMode:NSDefaultRunLoopMode];
[self.networkStream open];
// Have to release ftpStream to balance out the create. self.networkStream
// has retained this for our persistent use.
CFRelease(ftpStream);
// Tell the UI we're receiving.
[self _receiveDidStart];
}
}

Related

Errors creating a multithreaded named pipe server with Administrator only access on windows c++

Im trying to create a multithreaded namedpipe server as outlined in the msdn sample here https://learn.microsoft.com/en-us/windows/win32/ipc/multithreaded-pipe-server but Im trying to restrict the namedpipe to access by adminstrators group members only.
The example works correctly when no SECURITY_ATTRIBUTES structure is specified but when an SA is specified the first call is successful, but following calls to CreateNamedPipe fail as long as the first pipe is listening or communicating with a client. The create call fails, usually with ACCESS_DENIED, but sometimes with error 1305 The revision level is unknown. When the first pipe closes due to client disconnecting the following call will be successful for the next createnamedpipe call but will in turn fail once that pipe has a client.
I have tried multiple values for the grfInheritance field with no avail. This is my first adventure into explicitly specifying SECURITY so forgive me if I have missed something obvious. Note that in the Function that calls createnamedpipe I create a new SA structure with each create attempt but I have also tried creating one and sharing it outside the create loop.
Relevant code follows:
function that creates the pipe:
HRESULT DapiSettingsSvr::DapiSettingsListener()
{
while(m_run)
{
//find an unused control array member. If they are all used we have max connection so dont create a pipe.
UINT connectId = 0;
for (connectId; connectId < MAX_CONNECTIONS; connectId++)
{
if (m_controlArray[connectId].inuse == false)
break;
}
SECURITY_ATTRIBUTES sa;
HRESULT hr = InitializeSecurity(&sa);
if (FAILED(hr))
{
return hr;
}
if (connectId < MAX_CONNECTIONS)
{
HANDLE hpipe;
hpipe = CreateNamedPipe(
lpszPipename, // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_BYTE | // byte bipe
PIPE_READMODE_BYTE | // read as bytes
PIPE_WAIT | // do not return until data is recieved
PIPE_REJECT_REMOTE_CLIENTS, // no remote connections
MAX_CONNECTIONS, // max. instances
OUTPUT_BUFFER_SIZE, // output buffer size
INPUT_BUFFER_SIZE, // input buffer size
0, // client time-out
&sa); // default security attribute
// CleanUpSecurityResources();
if (hpipe == INVALID_HANDLE_VALUE)
{
swprintf(logbuffer, ARRAYSIZE(logbuffer), L"CreateNamedPipe failed, GLE=%d.\n", GetLastError());
DapiSettingLogger(logbuffer);
}
else
{
m_controlArray[connectId].inuse = true;
m_controlArray[connectId].pThis = this;
m_controlArray[connectId].connectId = connectId;
m_controlArray[connectId].pipehandle = hpipe;
swprintf(logbuffer, ARRAYSIZE(logbuffer), L"\nPipe Server: Main thread awaiting client connection on %s\n", lpszPipename);
DapiSettingLogger(logbuffer);
// block until a client tries to connect.success is non zero. However a client can connect between the create call and ConnectNamedPipe call.
// In this case ConnectNamedPipe returns zero but GLE = ERROR_PIPE_CONNECTED and a valid connection exists. Check for this case.
fConnected = ConnectNamedPipe(hpipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
if (fConnected)
{
// Create a thread for this client.
m_controlArray[connectId].threadHandle = CreateThread(
NULL, // no security attribute
0, // default stack size
WorkerInstance, // thread proc
(LPVOID)&m_controlArray[connectId], // thread parameter
0, // not suspended
&m_controlArray[connectId].threadId); // returns thread ID
if (m_controlArray[connectId].threadHandle == NULL)
{
swprintf_s(logbuffer, ARRAYSIZE(logbuffer), L"CreateThread failed, GLE=%d.\n", GetLastError());
DapiSettingLogger(logbuffer);
CloseHandle(m_controlArray[connectId].pipehandle);
ZeroMemory(&m_controlArray[connectId], sizeof(WORKER_INFO));
}
}
else
{
// The client could not connect, so close the pipe.
CloseHandle(m_controlArray[connectId].pipehandle);
ZeroMemory(&m_controlArray[connectId], sizeof(WORKER_INFO));
}
} //else valid connection
}
else
{
DapiSettingLogger((LPWSTR) L"Max Connections reached\n");
}
}
return S_OK;
}
Function that creates the SA
HRESULT DapiSettingsSvr::InitializeSecurity(SECURITY_ATTRIBUTES* psa)
{
HRESULT result = S_OK;
DWORD res, error;
EXPLICIT_ACCESS ea[1];
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
// Create a SID for the BUILTIN\Administrators group.
if (!AllocateAndInitializeSid(&SIDAuthNT, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&m_pAdminSID))
{
error = GetLastError();
swprintf(logbuffer, ARRAYSIZE(logbuffer), L"AllocateAndInitializeSid Error %u\n", error);
DapiSettingLogger(logbuffer);
result = HRESULT_FROM_WIN32(error);
goto Cleanup;
}
ea[0].grfAccessPermissions = GENERIC_ALL;
ea[0].grfAccessMode = GRANT_ACCESS;
ea[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; //changing
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
ea[0].Trustee.ptstrName = (LPTSTR)m_pAdminSID;
// Create a new ACL that contains the new ACE.
res = SetEntriesInAcl(1, ea, NULL, &m_pACL);
if (ERROR_SUCCESS != res)
{
swprintf(logbuffer, ARRAYSIZE(logbuffer),L"SetEntriesInAcl Error %u\n", res);
DapiSettingLogger(logbuffer);
result = HRESULT_FROM_WIN32(res);
goto Cleanup;
}
// Initialize a descriptor Use localalloc as it allows memory moving without changing handle value
m_pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (NULL == m_pSD)
{
error = GetLastError();
swprintf(logbuffer, ARRAYSIZE(logbuffer), L"LocalAlloc Error %u\n", error);
result = HRESULT_FROM_WIN32(error);
goto Cleanup;
}
if (!InitializeSecurityDescriptor(m_pSD,
SECURITY_DESCRIPTOR_REVISION))
{
error = GetLastError();
swprintf(logbuffer, ARRAYSIZE(logbuffer), L"InitializeSecurityDescriptor Error %u\n", error);
result = HRESULT_FROM_WIN32(error);
goto Cleanup;
}
// Add the ACL to the security descriptor.
if (!SetSecurityDescriptorDacl(m_pSD,
TRUE, // bDaclPresent flag
m_pACL,
FALSE)) // not a default DACL
{
error = GetLastError();
swprintf(logbuffer, ARRAYSIZE(logbuffer), L"SetSecurityDescriptorDacl Error %u\n", error);
result = HRESULT_FROM_WIN32(error);
goto Cleanup;
}
Cleanup:
if (FAILED(result))
{
CleanUpSecurityResources();
}
else
{
// Initialize a security attributes structure.
psa->nLength = sizeof(SECURITY_ATTRIBUTES);
psa->lpSecurityDescriptor = m_pSD;
psa->bInheritHandle = TRUE; /// NOTE I have toyed with this value also
}
return result;
}
Any input on what Im doing incorrectly would be greatly appriciated!!
Thanks!
According to Named Pipe Security and Access Rights,
In addition to the requested access rights, the DACL must allow the
calling thread FILE_CREATE_PIPE_INSTANCE access to the named pipe.
Ok, I figured this out. Im going to mark YangXiaoPo's answer as correct as this pointed me in the right direction but for clarification GENERIC_ALL already includes the right to FILE_CREATE_PIPE_INSTANCE or at least thats what my testing indcates. So setting the EXPICIT_ACCESS structure field to ea[0].grfAccessPermissions = GENERIC_ALL | FILE_CREATE_PIPE_INSTANCE; does not resolve this issue.
The answer lies in the fact that I was running the PipeServer program from within visual studio ( debug ) and thus as a generic user. So the first time through the loop a pipe gets created and the SA with the local administrators group ACE is then applied to the pipe.
So we get a pipe created in the listening state. As soon as a client connects the working thread is created and then the the while(m_run) loop does another iteration and tries to create a new pipe instance. This attempt fails ( actually a looping fail ) because the security attribute with the administrators only ACL is now looked at and the program is not running as an administrator. As soon as the first client disconnects the working thread closes the pipe handle ( effectively destroying the pipe ) and then in the next iteration a pipe is again created.
Running the program as Administrator ( or starting Visual studio as Admin and then debugging ) resolves the issue, though I think a fully correct solution would be to create a second ACE that specified Creator Owner in addition to Admin for the SA DACL.
Thanks!!

How can I check if I can write to a file without elevated token?

I know that this question was asked by many other people, but my case has one important difference. I can't just open file handle with write option because I want to check if I can write in this file without elevated token.
For example, user can run my installer as administrator so I can write in almost all of folders, but after installation my program won't work.
I thought that I can just get the token of my process, disable all privileges and apply it to new thread. I did it but it doesn't work.
I don't want to include code that I wrote because there are a lot of insignificant stuff. Instead, I'll just describe order of functions that I use.
GetCurrentProcess
OpenProcessToken
DuplicateTokenEx - somebody told me that it removes the elevation
AdjustTokenPrivileges - I call it with DisableAllPriveleges = true
CreateThread - Suspend = true
SetThreadToken
CreateFile
I can still write to all folders. What am I doing wrong?
for create not elevated token from your existing token we can use CreateRestrictedToken function with LUA_TOKEN flag. this by fact what is UAC doing when create restricted version of an existing access token on interactive logon. and then we can do access via this token. also note that we not need use new thread - we can temporary impersonate current thread with this lua token and then revert back.
so code can look like:
inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
ULONG CheckFileWriteAccess(PCWSTR FileName, ULONG& dwFileError)
{
HANDLE hToken, hLuaToken;
ULONG dwError = BOOL_TO_ERROR(OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE, &hToken));
if (dwError == NOERROR)
{
dwError = BOOL_TO_ERROR(CreateRestrictedToken(hToken, LUA_TOKEN, 0, 0, 0, 0, 0, 0, &hLuaToken));
CloseHandle(hToken);
if (dwError == NOERROR)
{
dwError = BOOL_TO_ERROR(DuplicateToken(hLuaToken, ::SecurityImpersonation, &hToken));
CloseHandle(hLuaToken);
if (dwError == NOERROR)
{
dwError = BOOL_TO_ERROR(SetThreadToken(0, hToken));
CloseHandle(hToken);
if (dwError == NOERROR)
{
HANDLE hFile = CreateFileW(FileName, FILE_GENERIC_WRITE, FILE_SHARE_VALID_FLAGS, 0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
dwFileError = NOERROR;
}
else
{
dwFileError = GetLastError();
NTSTATUS status = RtlGetLastNtStatus();
if (RtlNtStatusToDosError(status) == dwFileError)
{
dwFileError = HRESULT_FROM_NT(status);
}
}
SetThreadToken(0, 0);
}
}
}
}
return dwError;
}
note also snippet
dwFileError = GetLastError();
NTSTATUS status = RtlGetLastNtStatus();
if (RtlNtStatusToDosError(status) == dwFileError)
{
dwFileError = HRESULT_FROM_NT(status);
}
win32 error returned from CreateFileW api - frequently confused, because many different (by sense) NTSTATUS errors mapped to single win32 error. so always better check RtlGetLastNtStatus() instead GetLastError(). even more better of course use NtOpenFile (it documented, user mode, supported, will be not altered or removed) which direct return actual NTSTATUS.
note also that potential you can got error STATUS_SHARING_VIOLATION too. more releable open file with READ_CONTROL only access (this never give sharing violation) query it security descriptor and than use AccessCheck with LUA token, but this require more complex code

How to resolve: "NSPersistentStoreCoordinator has no persistent stores"?

I'm following this tutorial exactly, which adds CoreData to an existing app:
https://www.youtube.com/watch?v=WcQkBYu86h8
When I get to the seedPerson() moc.save(), the app crashes with this error:
CoreData: error: Illegal attempt to save to a file that was never
opened. "This NSPersistentStoreCoordinator has no persistent stores
(unknown). It cannot perform a save operation.". No last error
recorded.
The NSManagedSubclass has been added.
The DataController is wired up and I can step into it. It isn't until the save() that things go wrong. Any idea what I might have left out to cause this error?
I also followed that YouTube tutorial and had the same problem. I just removed the background thread block that adds the persistent store and it worked. Here's my DataController:
import UIKit
import CoreData
class WellbetDataController: NSObject {
var managedObjectContext: NSManagedObjectContext
override init() {
// This resource is the same name as your xcdatamodeld contained in your project.
guard let modelURL = NSBundle.mainBundle().URLForResource("DataModel", withExtension:"momd") else {
fatalError("Error loading model from bundle")
}
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
guard let mom = NSManagedObjectModel(contentsOfURL: modelURL) else {
fatalError("Error initializing mom from: \(modelURL)")
}
let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)
self.managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
self.managedObjectContext.persistentStoreCoordinator = psc
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
let docURL = urls[urls.endIndex-1]
/* The directory the application uses to store the Core Data store file.
This code uses a file named "DataModel.sqlite" in the application's documents directory.
*/
let storeURL = docURL.URLByAppendingPathComponent("DataModel.sqlite")
do {
try psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil)
} catch {
fatalError("Error migrating store: \(error)")
}
// dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
// let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
// let docURL = urls[urls.endIndex-1]
// /* The directory the application uses to store the Core Data store file.
// This code uses a file named "DataModel.sqlite" in the application's documents directory.
// */
// let storeURL = docURL.URLByAppendingPathComponent("DataModel.sqlite")
// do {
// try psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil)
// } catch {
// fatalError("Error migrating store: \(error)")
// }
// }
}
}
Unfortunately, that video uses some code from Apple's website, and that code example is flawed. The main flaw is that it caches the MOC before the persistent store has been added to the MOC. Thus, if the creation of the store fails at all, the managed object context will be initialized with a persistent store coordinator that has no store.
You need use the debugger and step through the code that creates the PSC (the DataController.init method) and see why the failure happens. If you cut/paste the same way as in that example, then maybe you also forgot to change the name of your model when instantiating the model.
In any event, the most likely cause is that some initialization code in that function failed, and you are subsequently going happily along with a core data stack that has no stores.
You need to load the persistent stores
let persistentContainer = NSPersistentContainer(name: "DbName")
persistentContainer.loadPersistentStores() { [weak self] _, error in
self?.persistentContainer.viewContext.automaticallyMergesChangesFromParent = true
}
The problem is on these two lines:
guard let modelURL = NSBundle.mainBundle().URLForResource("DataModel", withExtension:"momd") else {
&&
let storeURL = docURL.URLByAppendingPathComponent("DataModel.sqlite")
DataModel needs to be changed to the name of your application if your CoreData was created automatically by Xcode. Look for these lines in AppDelegate.swift
If this is the first time that you run the application after you put the core data in it then maybe it could work by removing the app from simulator and run it again.
It was happened to me and it works after I did that.

Network request in threads is crashing my application

Currently I have a code that is crashing (SEGFAULT) on me.
I am trying to compare a big amount of images that are in my drive to their counter parts in a server.
To speed up the process I get the image from the server and compare the images on a different thread.
From what I already tried and debugged, the issue is in getting the image from the server (that is why the other calls are commented out).
Also if I run without the QtConcurrent::run it does not crash, but if I put semaphore concurrentComparisons with only one resorce, it will crash.
Finally I also get the following errors
QObject::connect: Cannot connect (null)::configurationAdded(QNetworkConfiguration) to QNetworkConfigurationManager::configurationAdded(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::configurationRemoved(QNetworkConfiguration) to QNetworkConfigurationManager::configurationRemoved(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::configurationChanged(QNetworkConfiguration) to QNetworkConfigurationManager::configurationChanged(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::onlineStateChanged(bool) to QNetworkConfigurationManager::onlineStateChanged(bool)
QObject::connect: Cannot connect (null)::configurationUpdateComplete() to QNetworkConfigurationManager::updateCompleted()
Any help would be very appreciated.....
Relevant code:
QSemaphore FileComparisonInfo::concurrentComparisons(1);
QtConcurrent::run( [this, localPath, imageURL]()
{
ImageComparer cmp;
FileComparisonInfo::concurrentComparisons.acquire();
//cmp.setImageLeftPath(localPath);
cmp.setImageRightPath(imageURL);
//cmp.createDifferenceImage();
FileComparisonInfo::concurrentComparisons.release();
});
void ImageComparer::setImageRightPath(QString path)
{
this->rightImagePath = path;
this->imageRight = getImage(path);
}
QImage* ImageComparer::getImage(QString path)
{
QUrl url(path);
QFile file(path);
if(file.exists())
{
return new QImage(path);
}
else if(url.isValid())
{
return getImageFromURL(path);
}
}
QImage* ImageComparer::getImageFromURL(QString url)
{
QNetworkAccessManager * tempNAM = new QNetworkAccessManager();
QNetworkReply *imageConnection = tempNAM->get( QNetworkRequest( QUrl( url ) ));
QEventLoop loop;
connect(imageConnection, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
QImage * downloadedImage;
if(imageConnection->error() != QNetworkReply::NoError)
{
qDebug() << imageConnection->errorString();
downloadedImage = new QImage();
}
else
{
QByteArray data = imageConnection->readAll();
downloadedImage = new QImage(QImage::fromData(data));
}
tempNAM->deleteLater();
imageConnection->deleteLater();
return downloadedImage;
}
Unfortunately this had nothing to do with the code.
One of the images was corrupted and was segfaulting in the comparison.

RegisterEventHotKey CMD+TAB in Mountain Lion

According to this post:
ShortcutRecorder record CMD+Tab
calling setCanCaptureGlobalHotKeys:YES on the ShortCutRecorder control should allow you to capture CMD+TAB. However, it doesn't seem to work. I created this small app myself to see whats going on:
OSStatus myHotKeyHandler(EventHandlerCallRef nextHandler, EventRef anEvent, void *userData)
{
NSLog(#"YEAY WE DID A GLOBAL HOTKEY");
return noErr;
}
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
EventHotKeyRef myHotKeyRef;
EventHotKeyID myHotKeyID;
EventTypeSpec eventType;
eventType.eventClass = kEventClassKeyboard;
eventType.eventKind = kEventHotKeyPressed;
myHotKeyID.signature = 'mhk1';
myHotKeyID.id = 1;
InstallApplicationEventHandler(&myHotKeyHandler, 1, &eventType, NULL, NULL);
OSStatus status = RegisterEventHotKey(kVK_Tab,
cmdKey,
myHotKeyID,
GetApplicationEventTarget(),
0,
&myHotKeyRef);
NSLog(#"status:%d", status);
}
#end
If I use cmdKey + optionKey, then it does work.
Is there another way to capture CMD+TAB in my own application on Mountain Lion? CMD+OPTION+TAB is not good enough for me.
Things have changed a bit since that question was asked in 2010! ⌘⇥ is detected by Dock.app with an Event Tap, and that event no longer makes it back to the application.
You can still hook ⌘⇥, but you need to beat Dock to it with an Event Tap yourself. Here's some example code, courtesy osxbook.com:
// alterkeys.c
// http://osxbook.com
//
// Complile using the following command line:
// gcc -Wall -o alterkeys alterkeys.c -framework ApplicationServices
//
// You need superuser privileges to create the event tap, unless accessibility
// is enabled. To do so, select the "Enable access for assistive devices"
// checkbox in the Universal Access system preference pane.
#include <ApplicationServices/ApplicationServices.h>
// This callback will be invoked every time there is a keystroke.
//
CGEventRef
myCGEventCallback(CGEventTapProxy proxy, CGEventType type,
CGEventRef event, void *refcon)
{
// Paranoid sanity check.
if ((type != kCGEventKeyDown) && (type != kCGEventKeyUp))
return event;
// The incoming keycode.
CGKeyCode keycode = (CGKeyCode)CGEventGetIntegerValueField(
event, kCGKeyboardEventKeycode);
// Swap 'a' (keycode=0) and 'z' (keycode=6).
if (keycode == (CGKeyCode)0)
keycode = (CGKeyCode)6;
else if (keycode == (CGKeyCode)6)
keycode = (CGKeyCode)0;
// Set the modified keycode field in the event.
CGEventSetIntegerValueField(
event, kCGKeyboardEventKeycode, (int64_t)keycode);
// We must return the event for it to be useful.
return event;
}
int
main(void)
{
CFMachPortRef eventTap;
CGEventMask eventMask;
CFRunLoopSourceRef runLoopSource;
// Create an event tap. We are interested in key presses.
eventMask = ((1 << kCGEventKeyDown) | (1 << kCGEventKeyUp));
eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0,
eventMask, myCGEventCallback, NULL);
if (!eventTap) {
fprintf(stderr, "failed to create event tap\n");
exit(1);
}
// Create a run loop source.
runLoopSource = CFMachPortCreateRunLoopSource(
kCFAllocatorDefault, eventTap, 0);
// Add to the current run loop.
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource,
kCFRunLoopCommonModes);
// Enable the event tap.
CGEventTapEnable(eventTap, true);
// Set it all running.
CFRunLoopRun();
// In a real program, one would have arranged for cleaning up.
exit(0);
}
The downside to this is that you cannot sandbox or ship an application that uses ⌘⇥ on the App Store. Not only should it be obvious why Event Taps are not allowed in those environments (they give you the ability to terminate—and even mutate—events), but the functionality Dock provides on ⌘⇥ is pretty darn useful and can't be remapped to a different keyboard shortcut, so even Witch and Switch avoid it using it by default.

Resources