I wrote an Helper Tool for an application based on http://dl.dropbox.com/u/463624/Elevator.zip, but setting the deployment target to 10.10 now I can see deprecation in lauch.h, this is the code:
#import <Foundation/Foundation.h>
#import <launch.h>
#import <syslog.h>
#import "HelperTool.h"
int main (int argc, const char * argv[])
{
#autoreleasepool {
syslog(LOG_NOTICE, "MyHelper launched (uid: %d, euid: %d, pid: %d)", getuid(), geteuid(), getpid());
launch_data_t req = launch_data_new_string(LAUNCH_KEY_CHECKIN);
launch_data_t resp = launch_msg(req);
launch_data_t machData = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_MACHSERVICES);
launch_data_t machPortData = launch_data_dict_lookup(machData, "com.me.MyHelper.mach");
mach_port_t mp = launch_data_get_machport(machPortData);
launch_data_free(req);
launch_data_free(resp);
NSMachPort *rp = [[NSMachPort alloc] initWithMachPort:mp];
NSConnection *c = [NSConnection connectionWithReceivePort:rp sendPort:nil];
//.....
}
return 0;
}
looking here: https://developer.apple.com/library/mac/documentation/General/Reference/APIDiffsMacOSX10_10SeedDiff/headers/System.html no big changes, but how to solve?
Related
My code is here:
in myAppDelegate.m:
void catchException(NSException *e)
{
NSLog( #"here is a exception");
}
#implementation myAppDelegate
{
NSSetUncaughtExceptionHandler(&catchException);
NSException *e = [[NSException alloc] initWithName: #"aException" reason: #"test" userInfo: nil];
#throw e;
}
However the function catchException is never be trapped. Can anybody tell me why?
I have found in my own OSX code that I had to use NSExceptionHandler in order to reliably catch exceptions:
#import <Cocoa/Cocoa.h>
#import <ExceptionHandling/NSExceptionHandler.h>
#import "CocoaUtil.h"
#import <execinfo.h>
// ExceptionDelegate
#interface ExceptionDelegate : NSObject
#end
static ExceptionDelegate * _exceptionDelegate = nil;
int main(int argc, const char **argv) {
int retval = 1;
#autoreleasepool
{
//
// Set exception handler delegate
//
_exceptionDelegate = [[ExceptionDelegate alloc] init];
NSExceptionHandler *exceptionHandler = [NSExceptionHandler defaultExceptionHandler];
exceptionHandler.exceptionHandlingMask = NSLogAndHandleEveryExceptionMask;
exceptionHandler.delegate = _exceptionDelegate;
//
// Set signal handling
//
int signals[] = {
SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGEMT, SIGFPE, SIGBUS, SIGSEGV,
SIGSYS, SIGPIPE, SIGALRM, SIGXCPU, SIGXFSZ
};
const unsigned numSignals = sizeof(signals) / sizeof(signals[0]);
struct sigaction sa;
sa.sa_sigaction = signalHandler;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
for (unsigned i = 0; i < numSignals; i++)
sigaction(signals[i], &sa, NULL);
// Do work
} // #autoreleasepool
return retval;
}
static void dumpStack(void **frames, unsigned numFrames) {
char **frameStrings = backtrace_symbols(frames, numFrames);
if (frameStrings) {
for (unsigned i = 0; i < numFrames && frameStrings[i] ; i++)
logbareutf8((char *)frameStrings[i]);
free(frameStrings);
} else {
logerr(#"No frames to dump");
}
}
static void signalHandler(int sig, siginfo_t *info, void *context) {
logerr(#"Caught signal %d", sig);
const size_t maxFrames = 128;
void *frames[maxFrames];
unsigned numFrames = backtrace(frames, maxFrames);
dumpStack(frames, numFrames);
bool send = criticalAlertPanel(#"Application Error",
#"Upload logfile to support site",
#"MyApp is terminating due to signal %d", sig);
if (send)
sendLogfile();
exit(102);
}
static void sendLogfile() {
// Redacted
}
#implementation ExceptionDelegate
- (BOOL)exceptionHandler:(NSExceptionHandler *)exceptionHandler
shouldLogException:(NSException *)exception
mask:(NSUInteger)mask {
logerr(#"An unhandled %# exception occurred: %#", [exception name], [exception reason]);
// [exception callStackReturnAddresses] will be empty, so parse the NSStackTraceKey from
// [exception userInfo].
NSString *stackTrace = [[exception userInfo] objectForKey:NSStackTraceKey];
NSScanner *scanner = [NSScanner scannerWithString:stackTrace];
NSMutableArray *addresses = [[NSMutableArray alloc] initWithCapacity:0];
NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
NSString *token;
while ([scanner scanUpToCharactersFromSet:whitespace
intoString:&token]) {
[addresses addObject:token];
}
NSUInteger numFrames = [addresses count];
if (numFrames > 0) {
void **frames = (void **)malloc(sizeof(void *) * numFrames);
NSUInteger i, parsedFrames;
for (i = 0, parsedFrames = 0; i < numFrames; i++) {
NSString *address = [addresses objectAtIndex:i];
if (![CocoaUtil parseString:address toVoidPointer:&frames[parsedFrames]]) {
logerr(#"Failed to parse frame address '%#'", address);
break;
}
parsedFrames++;
}
if (parsedFrames > 0) {
logerr(#"Stack trace:");
dumpStack(frames, (unsigned)parsedFrames);
}
free(frames);
} else {
logerr(#"No addresses in stacktrace");
}
return YES;
}
- (BOOL)exceptionHandler:(NSExceptionHandler *)exceptionHandler
shouldHandleException:(NSException *)exception
mask:(NSUInteger)mask {
bool send = criticalAlertPanel(#"Application Error",
#"Upload logfile to support site",
#"MyApp is terminating due to an unhandled exception:\n\n%#",
[exception reason]);
if (send)
sendLogfile();
exit(101);
// not reached
return NO;
}
You'll need to import ExceptionHandling.framework as noted by trojanfoe.
Here is gist which cleans up the stack trace printing (some functions are missing):
https://gist.github.com/alfwatt/5ddfaf68e530a5a69e3d
In a Qt project, how would I go about disabling the OS X scrollbar inertia for my application? This is so that I can provide custom control over inertia etc.
This does it:
project.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = project
TEMPLATE = app
macx {
LIBS += -framework Foundation
OBJECTIVE_SOURCES += helper.m
}
SOURCES += main.cpp
helper.m
#include <Foundation/NSUserDefaults.h>
#include <Foundation/NSDictionary.h>
#include <Foundation/NSString.h>
void disableMomentumScroll(void)
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:#"NO" forKey:#"AppleMomentumScrollSupported"];
[defaults registerDefaults:appDefaults];
}
main.cpp
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#ifndef Q_OS_MAC
void disableMomentumScroll() {}
#else
extern "C" { void disableMomentumScroll(); }
#endif
float rnd(float range) { return (qrand() / static_cast<float>(RAND_MAX)) * range; }
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
disableMomentumScroll();
QGraphicsScene s;
for (int n = 0; n < 30; n++) {
s.addRect(rnd(500), rnd(3000), rnd(200), rnd(1000), QPen(Qt::red), QBrush(Qt::gray));
}
QGraphicsView w(&s);
w.show();
return a.exec();
}
We had developed an ".app" installer for MAC OSX using C++ / QT. We were facing issues with loadFinished signal being called with false intermittently even while loading html file which is from local file system.
I found some other posts regarding loadFinished signal being called multiple times. In my case, the signal is called only once with false.
Anyone faced this kind of issue? Relying loadProgress signal with the value 100 is fine?
QT - 4.8.2
Mac OS X - 10.7
Code Snippet:-
boost::scoped_ptr<QWebView> m_webViewP;
static const boost::filesystem::path kJSEntryPoint = boost::filesystem::path("web") / boost::filesystem::path("index.html");
QUrl fileURL(QString::fromStdString(ISettingsManager::getInstance()->getJSEntryPoint()));
Log(INFO, "Loading auth page[%s].", qPrintable(fileURL.toString()));
m_webViewP->load(fileURL);
m_webViewP->activateWindow();
m_webViewP->raise();
const std::string SettingsManagerImpl::getJSEntryPoint() const
{
boost::filesystem::path retPath;
retPath = getAppDir_();
retPath /= kJSEntryPoint;
std::string toRet = retPath.string();
convertToURL_(toRet);
return toRet;
}
void SettingsManagerImpl::convertToURL_(std::string &path) const
{
size_t index = path.find(kBackSlash);
while (index != std::string::npos)
{
path.replace(index, 1, kForwarSlash);
index = path.find(kBackSlash);
}
path = kURLPrefix + path;
}
boost::filesystem::path SettingsManagerImpl::getAppDir_() const
{
#ifdef _WIN32
TCHAR pathName[MAX_PATH];
if (::GetModuleFileName(NULL, pathName, MAX_PATH) == 0)
{
SSLog(ERROR, "Error while retrieving app path.");
return "";
}
::PathRemoveFileSpec(pathName);
return boost::filesystem::path(pathName);
#else
NSAutoreleasePool *poolP = [[NSAutoreleasePool alloc] init];
NSString *pathP = [[NSBundle mainBundle] executablePath];
pathP = [pathP stringByDeletingLastPathComponent];
boost::filesystem::path toRet([pathP cStringUsingEncoding:NSASCIIStringEncoding]);
[poolP drain];
return toRet;
#endif
}
I don't get any format security warnings (-Wformat-security) from this code using Xcode 4.4:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
// a = #"%#" or a = #"%#%#"
NSString *a = [#"%#" stringByAppendingFormat:#"%#", arc4random_uniform(2)? #"%#": #"", nil];
// 50% change of crash, but no warning
NSLog(a, #"Hello, World!");
}
return 0;
}
Is this normal or have I somehow disabled this warning in Xcode?
I have just created the project with this code, so it haven't changed the project settings from the default.
I have read questions/559482/why-doesnt-an-iphone-apps-main-function-ever-get-a-chance-to-finish, which explains why NSApplicationMain never actually returns. The same thing happens (for the same reason) in a desktop cocoa application, which is what I am working on.
With that in mind, how would I go about using NSLog to output some final debugging messages when my application exits?
To be specific, I would like to do something like this:
int myDebugVariable = 0;
int main(int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
CMLog(#"application begin");
int exitCode = NSApplicationMain(argc, (const char **) argv);
CMLog(#"application end. Debugging variable = %d", myDebugVariable);
[pool release];
return exitCode;
}
In this example, The "application begin" line is printed to the console, but the "application end." line is not.
Note #1: In my actual code, I am using something more sophisticated than myDebugVariable. This is a simplified example that illustrates the effect I am trying to achieve.
Note #2: I am familiar with the ApplicationWillTerminate method, which gets called when the application is about to quit, but it does not suit my needs. My debugging code relies on the dealloc methods for some custom classes, so it does not come into play until after ApplicationWillTerminate is called.
update:
Adam Rosenfield's answer did the trick. For the sake of completeness, here is a working solution:
int myDebugVariable = 0;
void my_exit_handler(void)
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
CMLog(#"application end: Debugging variable = %d", myDebugVariable);
[pool release];
}
int main(int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
CMLog(#"application begin");
atexit(my_exit_handler);
int exitCode = NSApplicationMain(argc, (const char **) argv);
[pool release];
return exitCode;
}
Use atexit(3) to register an exit handler. It will automatically be invoked when your app exits, either by finishing main or by calling exit(3). For example:
void my_exit_handler(void)
{
NSLog(#"about to exit, x = %d\n", x);
}
// at some point during app initialization...
atexit(&my_exit_handler);