I’m moving [Part 1]

Hey,
As usual it’s been some time since my last post. I swear I’ve been through busy days. Anyway, I’m posting just to keep up with you and let you know I’m moving the blog (actually I’ve moved it) to my own site thread0.me. Please, join me there!

BTW1, this is just part 1 as I’m actually moving in my real life. But that’s another story and a specific blog post will be dedicated to that 🙂

BTW2, you’ll only see part 2 on thread0.me 🙂
Cheers!

Advertisements

A native iOS app with a Qt third-party library

I’m wrapping up here pieces of information that I used to setup a working native iOS project taking advantage of a library I wrote mainly using Qt. The library I wrote has nothing to do with GUI, it just helps me dealing with connectivity, REST API interaction, file system access, compression… Also, the library was born for the Desktop but the porting effort to mobile is feasible due to the lack of GUI interaction.
In particular, the following has been tested using Qt 5.3.

Despite the huge integration level now Qt has reached over the year even on the iOS platform, I still prefer having the UI developed using the native SDK. I’m a rather experienced Cocoa developer, not that experienced with Cocoa Touch, but I managed to have everything I needed working. Since the information I found is rather sparse regarding this topic, I thought it could be nice to have everything here in a blog post.

Project info

In the following post I’m assuming you want to link a native iOS Xcode project to a third party library written using C++ and Qt. I’m also assuming you are using statically linked Qt for this project (which is the default for the iOS solution).

So what we have:

  • A native Xcode project for iOS: NativeHelloWorld.xcodeproj
  • A static lib Qt project: FancyStaticLib.pro

What we are going to have

  • NativeHelloWorld.xcodeproj
  • FancyStaticLib.xcodeproj as a subproject to NativeHelloWorld
  • Qt for iOS properly linked to make NativeHelloWorld run and use FancyStaticLib

Let’s get things started

So, first of all let’s instruct Xcode about where to find Qt on our system.
Go to Xcode -> Preferences -> Locations (Tab) -> Source Trees (Sub Tab).
Add the path to your Qt for iOS packages and name it as you wish. I just chose QTLIB_IOS.
Screen Shot 2014-12-18 at 18.25.05

I like setting my paths this way in order to keep my project as “exportable” as possible. This way, other devs can join my project pretty easily.

Now, if you haven’t already, you should create an Xcode project for your static library you want to link into your native iOS project.
In order to do so you have to run something like this:

/path/to/your/Qt/ios/bin/qmake -spec macx-xcode -r /path/to/FancyStaticLib.pro CONFIG+=staticlib CONFIG+=whatever_you_need

This will output FancyStaticLib.xcodeproj file for your static library. You can drag it to your our NativeHelloWorld.xcodeproj inside Xcode and add its product (the static lib) as a link dependency to your project.
NOTE: You will have to re-generate the FancyStaticLib.xcodeproj each time you change your static library .pro file

Link to Qt

Now that we have the project feeling more like a completely native Xcode one we have to set a few things up in order to easily keep developing directly from Xcode through our NativeHelloWorld.xcodeproj

First of all, look for the Headers Search path section in the Build Settings section of your Xcode project:
Screen Shot 2014-12-18 at 18.54.07

We want to make it easy for Xcode to find Qt headers, and also our static lib headers.
Now the variable we previously defined through the Source Trees section in the Xcode preferences comes in handy.
Let’s add the following to the Headers Search Path section:

  • $(QTLIB_IOS)/include
  • /path/to/FancyStaticLib/headers

Now, the actual linker flags.
You will probably need to start your project inside the emulator. When doing so bare in mind that the simulator has a different architecture from your iOS device. Simulator runs an i386 architecture and we want to link our project both to the static Qt lib files compiled for such architecture and for arm. This way we will be able to run our project both in the simulator and on the native device.

Scroll down to the Other Linker Flags section: you should at least have a Debug section. Under Debug, as a child item, you should have Any iOS Simulator SDK. If you don’t, click the little “+” icon on the side of the Debug item and add Any iOS Simulator SDK as child item.Screen Shot 2014-12-18 at 19.06.30

Our project dependencies are satisfied by the following modules:

  • QtCore
  • QtGui
  • QtNetwork
  • QtScript

The Debug section will host the option for running our app on a native device with debug symbols:

-L$(QTLIB_IOS)/lib -lQt5Core_debug -lQt5Gui_debug -lQt5Network_debug -lQt5Script_debug
Also, don’t forget to include proper platform support with:
-lQt5PlatformSupport_debug -L$(QTLIB_IOS)/plugins/ -lqios_debug
You’ll also need -lz -lqtharfbuzzng_debug most probably.
Also, if you are taking advantage of the bearer plugin to handle connectivity, add the following:
-L$(QTLIB_IOS)/plugins/bearer -lqgenericbearer_debug

Now the Any iOS Simulator SDK section:
Simply replace what you typed in the previous section changing “_debug” with “_iphonesimulator_debug” and you are good to go.

The last touch

Your Qt lib will most probably need an instance of QGuiApplication. This usually requires you to replace the default main coming with your project template with a custom one that actually calls QGuiApplication::exec(). Luckily, Qt has made things relatively easy and you won’t need a custom main body. Looks like the Qt guys are cool enough to inject their Qt Event Dispatcher inside the main CocoaTouch run loop making it easy to spawn QTimers and queued methods invocations from Objective-C(++).
Just make sure you initialize a QGuiApplication instance (but you won’t need to call .exec()).

We are going to add the following piece of code inside your application delegate - (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions after having renamed the application delegate file from .m to .mm. Renaming to .mm enables Objective-C++ which helps us mix C++ and Objective-C in the same source.

- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSProcessInfo *procInfo = [NSProcessInfo processInfo];
    NSArray *arguments = [procInfo arguments];
    int argc = arguments.count;
    // we need a strong reference for the
    // argv because it is required to stay
    // valid as long as the QGuiApplication instance
    // is valid
    _argv = (char**)malloc(sizeof(char*) * argc);
    for (int i = 0; i < argc; ++i) {
        NSString *arg = [arguments objectAtIndex:i];
        _argv[i] = (char *)(malloc([arg lengthOfBytesUsingEncoding:[NSString defaultCStringEncoding]]));
        strcpy(_argv[i], [arg cStringUsingEncoding:[NSString defaultCStringEncoding]]);
    }
    
    // make sure you keep a strong reference
    // to the QGuiApplication instance.
    // you can later free it inside the
    // - (void)applicationWillTerminate:(UIApplication *)application
    // delegate method
    _qApp = new QGuiApplication(argc, _argv);
    return YES;
}

Conclusions

This is pretty much what is needed to mix a native iOS project with a Qt library. If you encounter linker issues you should be able to easily address them by inspecting the .a symbols you can find inside your $(QTLIB_IOS)/{lib,plugins} directories.
Otherwise please post here your issues so that we can try address them together.

Cheers.

Workaround Windows Tray Area Item Preference

Introduction

I’m not an experienced Windows developer.
I had to make it clear 🙂

Today I had the chance to implement kind of a nasty hack on Windows.
I had to make my application tray icon always visibile, at least by default. I swear I honor user preference then. I know this is one of those don’tswhen working with Windows API since it is clearly stated in the docs developers have no control over the notification area. But sometimes you feel it deep in your heart that your application user experience would benefit a lot from making your tiny tray icon visible by default. This was my case, and as I can see on the internet, this is the case of a lot of apps out there.

I just wanted to write this down as an excercise to help me get back on sharing what I code (not always feasible, though).

There’s plenty of information out there, it’s just you won’t find a single pice of it and you’ll have to digg a lot before being able to workaround this limitation over the tray area. At least this was my experience as a non-experienced Windows developer.

Now that my reasons have been stated clear we can go ahead and see some code.

Let’s get started

So, there’s this incredible resource by Geoff Chappell which you should check if you want to know more about some undocumented/private APIs on Windows. It looks he has done a huge amount of work around the notification area documenting well enough how to workaround the default limitations exposed by the documented API.

As he states here explorer.exe exposes an ITrayNotify implementation through COM. This interface can be used to know user preferences and status regarding the notification area items. And you of course can also use it to modify such preferences.

So what we are going to do now is requesting the implementation through the canonical CoCreateInstance passing in the required CLSID information. Such information is retrievable from the docs by Geoff. But you can also look for ITrayNotify through regedit.exe in order to find the needed CLSID.

Bringing a few pieces together, here is a quick recap of the declarations you’ll need to make the CoCreateInstance call succeed.


#ifndef __ITrayNotify_INTERFACE_DEFINED__
#define __ITrayNotify_INTERFACE_DEFINED__

class __declspec(uuid(&quot;FB852B2C-6BAD-4605-9551-F15F87830935&quot;)) ITrayNotify : public IUnknown
{
public:
    virtual HRESULT __stdcall
    RegisterCallback(INotificationCB* callback) = 0;
    virtual HRESULT __stdcall
    SetPreference(const NOTIFYITEM* notify_item) = 0;
    virtual HRESULT __stdcall EnableAutoTray(BOOL enabled) = 0;
};
#endif	// #ifndef __ITrayNotify_INTERFACE_DEFINED__

const CLSID CLSID_TrayNotify = {
    0x25DEAD04,
    0x1EAC,
    0x4911,
    {0x9E, 0x3A, 0xAD, 0x0A, 0x4A, 0xB5, 0x60, 0xFD}};

This is enough for requesting the instance through CoCreateInstance. Unfortunately, as I discovered testing my own code, this won’t work on Windows 8 where apparently this private API has changed. You know, this is the drawback of using private APIs :).
Anyway, I spent the day looking for the solution and fortunately I found the appropriate interface also for Windows 8. You can find the same information by running OllyDbg against explorer.exe on Windows 8.

class __declspec(uuid(&quot;D133CE13-3537-48BA-93A7-AFCD5D2053B4&quot;)) ITrayNotifyWindows8 : public IUnknown
{
public:
    virtual HRESULT __stdcall
    RegisterCallback(INotificationCB* callback, unsigned long*) = 0;
    virtual HRESULT __stdcall UnregisterCallback(unsigned long*) = 0;
    virtual HRESULT __stdcall SetPreference(NOTIFYITEM const*) = 0;
    virtual HRESULT __stdcall EnableAutoTray(BOOL) = 0;
    virtual HRESULT __stdcall DoAction(BOOL) = 0;
};

Getting the instance to the appropriate ITrayNotify interface, though, is not enough. We are going to use another private interface, called INotificationCB, which will help us get the current information regarding our notification item.

So let’s write down our little helper class that will take care of modifying the preferences for our notification item.

// TinyTrayHelper.h

class TinyTrayHelper : public INotificationCB
{
public:
    TinyTrayHelper(NOTIFYICONDATA* nid);
    virtual ~TinyTrayHelper();

    HRESULT __stdcall Notify(ULONG, NOTIFYITEM *) __override;

    bool ensureTrayItemVisible();

    ULONG __stdcall AddRef(void) __override;
    ULONG __stdcall Release(void) __override;
    HRESULT __stdcall QueryInterface(REFIID riid, void **ppvObject) __override;

private:
    NOTIFYICONDATA *_nid;
    NOTIFYITEM _nit;
    wchar_t _exeName[MAX_PATH];
};

Now let’s see the actual implementation for our helper.

#include &quot;trayhelper.h&quot;

#include &lt;sdkddkver.h&gt;
#include &lt;VersionHelpers.h&gt;

#include &lt;stdio.h&gt;

static void* CreateTrayNotify(bool win8);

TinyTrayHelper::TinyTrayHelper(NOTIFYICONDATA *nid) :
    _nid(nid),
    _win8(false)
{
    CoInitialize(NULL);

    ::GetModuleFileName(NULL, _exeName, MAX_PATH);

    // here we prepare the NOTIFYITEM instance
    // that is required to change settings
    _nit.exe_name = _exeName;
    _nit.guid = _nid-&gt;guidItem;
    _nit.hwnd = _nid-&gt;hWnd;
    _nit.icon = _nid-&gt;hIcon;
}

TinyTrayHelper::~TinyTrayHelper()
{
}

HRESULT __stdcall TinyTrayHelper::Notify(ULONG, NOTIFYITEM *item)
{
    if (item-&gt;hwnd != _nid-&gt;hWnd || item-&gt;guid != _nid-&gt;guidItem) {
        // this is a notification about an item that is not ours
        // so let's just ignore it
        return S_OK;
    }

    _nit = NOTIFYITEM(*item);

    return S_OK;
}

ULONG __stdcall TinyTrayHelper::AddRef(void)
{
    return 1;
}

ULONG __stdcall TinyTrayHelper::Release(void)
{
    return 1;
}

HRESULT __stdcall TinyTrayHelper::QueryInterface(REFIID riid, void **ppvObject)
{
   if (ppvObject == NULL) return E_POINTER;

   if (riid == __uuidof(INotificationCB)) {
       *ppvObject = (INotificationCB*)this;
   } else if (riid == IID_IUnknown) {
       *ppvObject = (IUnknown *) this;
   } else {
       return E_NOINTERFACE;
   }

   AddRef();
   return S_OK;
}

bool TinyTrayHelper::ensureTrayItemVisible()
{
    const bool win8 = IsWindows8OrGreater();
    void *trayNotify = CreateTrayNotify();
    if (!trayNotify) {
        return false;
    }

    HRESULT hr;
    if (win8) {
        auto *win8TrayNotify = static_cast&lt;ITrayNotifyWin8*&gt;(trayNotify);
        unsigned long callback_id = 0;
        // this is synchronous
        hr = win8TrayNotify-&gt;RegisterCallback(static_cast&lt;INotificationCB*&gt;(this), &amp;callback_id);
        hr = win8TrayNotify-&gt;UnregisterCallback(&amp;callback_id);
    } else {
        hr = ((ITrayNotify*)trayNotify)-&gt;RegisterCallback(static_cast&lt;INotificationCB*&gt;(this));
        hr = ((ITrayNotify*)trayNotify)-&gt;RegisterCallback(NULL);
    }

    if (FAILED(hr)) {
        ((IUnknown*)trayNotify)-&gt;Release();
        return false;
    }

    // now we should have an up-to-date information
    // about our notification icon item

    if (_nit.preference != 0x01) { // this means always hide, so we honor user preference
        _nit.preference = 0x02;

        if (_win8) {
            ((ITrayNotifyWin8*)trayNotify)-&gt;SetPreference(&amp;_nit);
        } else {
            ((ITrayNotify*)trayNotify)-&gt;SetPreference(&amp;_nit);
        }
    }
    ((IUnknown*)trayNotify)-&gt;Release();
}

static void* CreateTrayNotify(bool win8)
{
    CLSID iTrayNotifyCLSID;
    if (win8) {
        iTrayNotifyCLSID = __uuidof(ITrayNotifyWindows8); // the interface we defined previously
    } else {
        iTrayNotifyCLSID = __uuidof(ITrayNotify);
    }

    void *trayNotify;
    HRESULT hr = CoCreateInstance (
                CLSID_TrayNotify,
                NULL,
                CLSCTX_LOCAL_SERVER,
                iTrayNotifyCLSID,
                (PVOID *) &amp;trayNotify);

    if (hr == S_OK) {
        return trayNotify;
    } else {
        printf(&quot;Cannot get reference to ITrayNotify instance\n&quot;);
    }

    return NULL;
}

I see what you did there

So, TinyTrayHelper basically does 4 things here:

  1. Creates a NOTIFYITEM instance based on a NOTIFICATIONDATA instance
  2. Chooses the appropriate ITrayNotify instance based on the current OS
  3. Registers itself as an instace of INotificationCB to receive the relevant information inside the Notify method
  4. Finally calls SetPreference to change the preference regarding the notification area item

What now?

What you need now is just to create an instance of our TinyTrayHelper and pass in your NOTIFICATIONDATA instance reference. Then call ensureTrayIconVisible to change the notification area preference regarding your item.

Please note that I adapted a more complex code to build this example so I didn’t test this code specifically. Use at your own risk.

I hope this will be useful to you. Please, let me know if I made tremendous mistakes here, I’ll try to fix!

Cheers.

I used to blog

I’m a bit shocked about how much I used to blog when I was a KDE contributor.
I lost myself in my previous blog this morning, it’s damn full of words. I was rather confident about what I was doing, that’s pretty cool. Anyway lots of events in my life brought me to stop contributing to KDE (I’m really sad about that, I apologize) and to stop blogging also.
Not that I haven’t had anything to blog about, but I’ve never had time (or will) to start a new blog from scratch. I didn’t feel like keeping the old blog. I feel it somewhat complete and it represents a specific part of my life I’m pretty happy about. So I just want to keep it as it is now.

Now, enough for the nostalgia. I’m still not really sure what I’m going to blog about here. It’s been busy years and I learnt a lot about software engineering. I love software engineering and I hope to share my experiences and have feedback from you.

OK, this is enough as first post (really?), so let’s stick with it.