Code for Concinnity


cocos2d-x with Xcode 4 from scratch (without template)

This is mainly some quick notes for myself. Getting cocos2d-x to work on iOS is surprisingly involved. Here we go:

Building cocos2d-x

First grab a copy of cocos2d-x

1
    $ git clone https://github.com/cocos2d/cocos2d-x.git

Now we need to build cocos2d-x. After some pondering about it, I conclude that the project is reasonably disorganized. The easiest way to grab a lib out of the mess is to compile its HelloWorld program:

1
2
3
4
5
6
    $ cd cocos2d-x/HelloWorld/ios
    $ xcodebuild -sdk iphonesimulator-4.3 -configuration Debug
    # ...
    # Now we have the .a file ready, let's find out where it is
    $ find . -iname '*.a'
    ./build/Debug-iphonesimulator/libcocos2d.a

Configuring the Xcode project

Now we need to configure our Xcode project to refer to the libcocos2d.a and the headers.

  1. Create a new Window-based Application
  2. Add these frameworks: OpenGLES.framework, QuartzCore.framework, libxml2.dylib
  3. In Build Settings, define the Preprocessor Macro TARGET_IPHONE_SIMULATOR
  4. Add Header Search Paths: cocos2d-x/cocos2dx/include cocos2d-x/cocos2dx/platform/ios cocos2d-x/cocos2dx/platform cocos2d-x/cocos2dx
  5. Finally Linker Flag -lcocos2d

Then we need to change our default project’s structure a bit. Since we’re creating our own window we will:

  1. Delete MainWindow.xib
  2. In *-Info.plist, remove the “main nib file” entry
  3. Change *AppDelegate.m to *AppDelegate.mm

Let’s write some code!

*AppDelegate.mm:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        static MainApplication sMainAppplication;
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        EAGLView * glView = [EAGLView viewWithFrame: [self.window bounds]pixelFormat:kEAGLColorFormatRGBA8 depthFormat:GL_DEPTH_COMPONENT16_OES preserveBackbuffer:NO sharegroup:nil multiSampling:NO numberOfSamples:0];
       
        self.window.rootViewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
        self.window.rootViewController.wantsFullScreenLayout = YES;
        self.window.rootViewController.view = glView;
       
        [self.window makeKeyAndVisible];
        cocos2d::CCApplication::sharedApplication().run();

        // ...
    }

MainApplication.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
    MainApplication::MainApplication()
    {
    }

    MainApplication::~MainApplication()
    {
       
    }

    bool MainApplication::initInstance()
    {
        return true;
    }

    bool MainApplication::applicationDidFinishLaunching()
    {
        cocos2d::CCDirector * director = cocos2d::CCDirector::sharedDirector();
        director->setOpenGLView(&cocos2d::CCEGLView::sharedOpenGLView());
       
        director->setAnimationInterval(1.0 / 60.0);
        director->runWithScene(MainScene::scene());
       
        return true;
    }

    void MainApplication::applicationDidEnterBackground()
    {
       
    }

    void MainApplication::applicationWillEnterForeground()
    {
    }

MainScene is your typical cocos2d::CCScene.

There we have it!

Published by kizzx2, on June 18th, 2011 at 1:51 am. Filled under: UncategorizedNo Comments

Good quote from Martin Fowler, worth repeating

“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.” – Martin Fowler

Published by kizzx2, on February 1st, 2011 at 1:44 am. Filled under: UncategorizedNo Comments

Learn PKI in 30 Minutes

Lately I’ve been doing some cryptographic/X.509 things, which was quite new to me. I was almost overwhelmed by the plethora of terminology when I tried to learn it. I’ve consolidated my learning in this short essay:

It’s written with the intention that someone can quickly get a grasp of the overall picture of these term-heavy X.509/PKI things. It’s written in concise language so as to not isolate the “rest of us” who don’t already grok those acronyms.

If you want a more comprehensive understanding, I can’t recommend the book Understanding PKI enough. It was really helpful and covers everything I needed to know.

There is also RFC 5280 which is the de-facto standard specification on this.

Enjoy! Comments are welcome.

Published by kizzx2, on January 27th, 2011 at 11:41 pm. Filled under: UncategorizedNo Comments

Dissecting obscure COM errors

Here’s how I solved these hair-pulling COM errors:

  • 0x800401fd CO_E_OBJNOTCONNECTED Object is not connected to server.
  • 0x8001010e RPC_E_WRONG_THREAD The application called an interface that was marshalled for a different thread.

And this one when I called IGlobalInterfaceTable::GetInterfaceFromGlobal (through CComGITPtr):

  • 0×80070057 E_INVALIDARG The parameter is incorrect.

The basic framework

To make sense of the following code segments, here’s the whole program’s framework to use for the following scenarios:

We use the boost library for threading to make the code less noisy of plumbing work. You don’t really need to grasp them to understand what’s going on.

I have chosen to use the SHDocVw::IShellWindowsPtr interface because it should be present in every Windows environment and simplifies our example without polluting it with the IDL of an example object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#import "C:/Windows/system32/shdocvw.dll"

#include <iostream>
#include <Windows.h>
#include <comutil.h>

#include <boost/thread.hpp>
#include <boost/ref.hpp>

namespace
{
    // Convenient error checking -- these will fail our
    // program with nicely printed error message in case of
    // any COM error
    void PrintHR(HRESULT hr)
    {
        std::wcerr << L"0x" << std::hex << hr << L" " <<
            _com_error(hr).ErrorMessage() << std::endl;
    }

    void EnsureSuccess(HRESULT hr)
    {
        if(FAILED(hr))
        {
            PrintHR(hr);
            exit(EXIT_FAILURE);
        }
    }

    // A simple wrapper with integrated error checking
    void MyCoInitialize()
    {
        HRESULT hr = CoInitialize(NULL);
        EnsureSuccess(hr);
    }

    // This method can be called in a thread to demonstrate
    // multi-threading issues
    void CreateShellWindow(SHDocVw::IShellWindowsPtr & retval)
    {
        // Because we might be in a different thread, we need
        // to call CoInitialize() just to make sure
        MyCoInitialize();
        HRESULT hr = retval.CreateInstance(__uuiof(SHDocVw::ShellWindows));
        EnsureSuccess(hr);
        CoUninitialize();
    }

    // This should print a numeric number
    // On my machine it always printed "1". The meaning of that
    // is not really important.
    void UseShellWindow(const SHDocVw::IShellWindowsPtr & ptr)
    {
        MyCoInitialize();
        std::cout << ptr->Count << std::endl;
        CoUninitialize();
    }

    void Example()
    {
        // Our example code segments would go here...
    }
}

int main()
{
    try
    {
        Example();
    }
    catch(const _com_error & e)
    {
        PrintHR(e.Error());
        return EXIT_FAILURE;
    }

    return 0;
}

0x800401fd CO_E_OBJNOTCONNECTED Object is not connected to server.

This one is pretty straight forward. You get this when you try to use a COM object after you have called CoUninitialize():

How to reproduce

1
2
3
4
5
6
7
8
9
void Example()
{
    MyCoInitialize();
    SHDocVw::IShellWindowsPtr ptr;
    CreateShellWindow(ptr);
    CoUninitialize();

    UseShellWindow(ptr); // ka-boom!
}

0x8001010e RPC_E_WRONG_THREAD The application called an interface that was marshalled for a different thread.

How to reproduce

1
2
3
4
5
6
7
8
9
10
11
12
void Example()
{
    MyCoInitialize();
    SHDocVw::IShellWindowsPtr ptr;

    CreateShellWindow(ptr);

    // This will use another thread to call `UseShellWindow()`
    boost::thread(&UseShellWindow, ptr); // ka-boom

    CoUninitialize();
}

What happened

The error message is pretty obvious — we need to marshal the pointer for thread A if the pointer was created in thread B, in order to use it in thread A.

How to fix

If you use ATL, one very convenient way to marshal them is to use the GIT (Global Interface Pointer) through CComGITPtr.

(The below serves as a quick fix and introduction. Please look into Global Interface Pointer and stuffs if you want to understand what’s going on).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// A GIT cookie is something you can use to retrieve a pointer
// from the GIT
void UseShellWindowFromCookie(DWORD cookie)
{
    MyCoInitialize();
    SHDocVw::IShellWindowsPtr ptr;
    CComGITPtr<SHDocVw::IShellWindows>(cookie).CopyTo(&fred);

    UseShellWindow(ptr);
    CoUninitialize();
}

void Example()
{
    MyCoInitialize();

    SHDocVw::IShellWindowsPtr ptr;
    CreateShellWindow(ptr);

    // This will register our pointer in the GIT and
    // retrieve a GIT cookie in one line
    DWORD cookie = CComGITPtr<SHDocVw::IShellWindows>(ptr).Detach();

    // Spawn a new thread of the GIT aware version of
    // UseShellWindow()
    boost::thread(&UseShellWindowFromCookie, cookie).join();

    CoUninitialize();
}

0×80070057 E_INVALIDARG The parameter is incorrect.

After discovering how easy it is to marshal COM objects across threads, you may sometimes get E_INVALIDARG when inside IGlobalInterfaceTable::GetInterfaceFromGlobal()

Now this one is really really obscure:

How to reproduce

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void CreateShellWindowCookie(DWORD & retval)
{
    MyCoInitialize();

    SHDocVw::IShellWindowsPtr ptr;
    CreateShellWindow(ptr);

    retval = CComGITPtr<SHDocVw::IShellWindows>(ptr).Detach();

    CoUninitialize();
}

void Example()
{
    MyCoInitialize();

    // Instead of using a different thread for UseShellWindow()
    // This time around we use a different thread to
    // create the COM pointer
    DWORD cookie;
    boost::thread(&CreateShellWindowCookie, boost::ref(cookie)).join();

    // Let's try to use it from the current thread
    UseShellWindowFromCookie(cookie); // ka-boom!

    CoUninitialize();
}

What happened

This is similar to what happened with CO_E_OBJNOTCONNECTED, only a lot more subtle and obscure this time around.

To understand this, keep this in mind: A COM object is thread aware. A COM object can only ever live in one single thread, even though it can be accessed from another thread (through marshaling).

What that simply means is that when the thread holding the COM object terminates, the COM object becomes invalid. In our example above, CreateShellWindowCookie() was run from a separate thread and finished before we even tried to use it. The actual COM object went down with the thread. Even though we had a cookie, the GIT would fail to find the actual COM object when it tries to do GetInterfaceFromGlobal(). Too bad that it gives such a confusing error message.

To summarize, here are the things to check when you get E_INVALIDARG from GetInterfaceFromGlobal():

  • Maybe the originating thread that called CoCreateInstance() has ended
  • Maybe the originating thread has already called CoUninitialize()
  • Maybe the actual object has already been terminated by someone Releaseing it.
  • Maybe your GIT cookie has already been used. Strangely enough, it seems like the GIT cookie can only be used to get the interface back once.

How to fix

There are 2 basic approaches:

  • Do not create any COM objects from threads other than the main thread (which is guaranteed to last through the program’s life time)
  • Have an elaborate inter-thread communication so that the creator-thread is kept-alive until the COM object’s users are finished with it (This can get really complicated).

To demonstrate, here’s the code that would work:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void CreateShellWindowCookie(DWORD & retval)
{
    MyCoInitialize();
    SHDocVw::IShellWindowsPtr ptr;
    CreateShellWindow(ptr);

    retval = CComGITPtr<SHDocVw::IShellWindows>(ptr).Detach();

    // Sleep 10 seconds
    Sleep(10 * 1000);

    CoUninitialize();
}

void Example()
{
    MyCoInitialize();

    // Create a cookie from another thread
    // We do not wait for it to finish
    DWORD cookie;
    boost::thread t(&CreateShellWindowCookie, boost::ref(cookie));

    // We wait 3 seconds
    Sleep(3 * 1000);

    // Now try to use it from cookie
    UseShellWindowFromCookie(cookie); // OK!

    CoUninitialize();
}

There you go

Hopefully this saved you from some hair-pulling experiences :)

Published by kizzx2, on December 4th, 2010 at 3:40 pm. Filled under: Uncategorized Tags: , , , , , No Comments

Tutorial: Using WinDBG to bypass specific functions — WinDBG kung-fu series

Continuing our series, this time we’ll try to use WinDBG to bypass certain functions at runtime. In this example, we’ll try to use WinDBG to ignore assert errors.

Example program

1
2
3
4
5
6
7
8
9
10
11
12
#include <cassert>
#include <iostream>

int main()
{
    int x = 10 - 10;
    assert(x);

    std::cout << "hello world" << std::endl;

    return 0;
}

Objective

The assertion dialog box should not pop up, and the console should show “hello world”.

Here we go

1
2
> cl /EHsc /Zi /Fefred.exe /Fdfred.pdb fred.cpp
> windbg fred.exe

First we need to set a breakpoint at the function we want to bypass. We’ve located the function name to be MSVCR100D!_wassert. You can find this out by looking at the call stack k

1
2
0:000> bp MSVCR100D!_wassert
0:000> g

Now our breakpoint’s been hit, let’s look at what we’ve got on the stack:

1
2
3
0:000> kp1
ChildEBP RetAddr  
0028f754 002a14d6 MSVCR100D!_wassert(wchar_t * expr = 0x002a7840 "x", wchar_t * filename = 0x002a7848 "k:\vsprojects\fred\fred\fred.cpp", unsigned int lineno = 7) [f:\dd\vctools\crt_bld\self_x86\crt\src\assert.c @ 113]

Nice, let’s try printing out the arguments

1
2
0:000> .printf "assertion error: %mu, %mu, %N", @@(expr), @@(filename), @@(lineno)
assertion error: x, k:\vsprojects\fred\fred\fred.cpp, 00000007

Now how do we go about “bypassing” this function? There are basically 2 ways to do it:

  1. Jumping to the end of the function, i.e. the ret instruction.
  2. Popping the stack manually and jumping back to the return address.

You can choose whichever method you want depending on what information you have. #1 requires you to know the exact offset of the ret instruction; #2 requires you to know the calling convention. Neither is much more robust than the other, but #2 requires a little more assembly knowledge. So we’ll do the easier approach with #1 here:

Now, let’s get a disassembly by u:

1
2
3
4
5
6
7
8
9
10
0:000> u
MSVCR100D!_wassert+0x2d [f:\dd\vctools\crt_bld\self_x86\crt\src\assert.c @ 121]:
60494afd 83c404          add     esp,4
60494b00 85c0            test    eax,eax
60494b02 0f85fc000000    jne     MSVCR100D!_wassert+0x134 (60494c04)
60494b08 833df01d4e6001  cmp     dword ptr [MSVCR100D!__app_type (604e1df0)],1
60494b0f 0f85ef000000    jne     MSVCR100D!_wassert+0x134 (60494c04)
60494b15 6af4            push    0FFFFFFF4h
60494b17 ff152c103860    call    dword ptr [MSVCR100D!_imp__GetStdHandle (6038102c)]
60494b1d 8985b8fbffff    mov     dword ptr [ebp-448h],eax

Arg… We need to look further down. Let’s use a real text editor for the job.

1
2
0:000> .shell -ci "u eip eip+0x1000" gvim -
0:000> * If you don't have vi installed, you're doomed. Too bad.

In my case, I found the return address here:

1
2
3
4
5
MSVCR100D!_wassert [f:\dd\vctools\crt_bld\self_x86\crt\src\assert.c @ 113]:
60494ad0 8bff            mov     edi,edi
60494ad2 55              push    ebp
.....
60495656 c3              ret

So 0x60495656 - 0x60494ad0 = 0xb86. We’ve got our offset. All we need to do is to rig eip to point the that instruction:

1
2
0:000> r eip = eip+0xb86
0:000> g

The thing should have run and we’ve been greeting with a nice “hello world.”

To sum it up, we could have converted the assertion error dialog box to console output with a one liner:

1
bp MSVCR100D!_wassert ".printf \"assertion error: %mu, %mu, %N\", @@(expr), @@(filename), @@(lineno); .echo; r eip = eip+0xb86; g"

The above would print “assertion error” message in the debug output and continue as if nothing happened.

Published by kizzx2, on November 17th, 2010 at 11:27 pm. Filled under: Uncategorized Tags: No Comments

Get Selenium onChange to work cross browser

Seems like there are a lot of people struggling to get Selenium RC to robustly fire the onchange event, but many people have failed. I faced the same problem. In particular, IE was not behaving properly.

Today I finally found out the solution, which makes me feel quite stupid :P

1
2
3
4
5
6
7
8
9
    // JUnit syntax. Basically the idea is that you just need to
    // use runScript to force the event to fire
    // Selenium's fireEvent is broken

    // jQuery
    selenium.runScript("$('#MyInputElement').trigger('change')");

    // Vanilla JavaScript
    document.getElementById('MyInputElement').onchange();

There you go!

Published by kizzx2, on August 15th, 2010 at 11:41 pm. Filled under: Uncategorized Tags: , , , No Comments

Using Selenium RC’s test suite runner with Internet Explorer — the solution!

If you’ve tried to use Selenium RC with Internet Explorer, here’s a list of things you will go through, before you get frustrated:

  • Using the plain and simple *iexplore doesn’t work at all. Selenium says the session is expired or something along the lines of sessionId 864408 doesn't exist.

  • Most people would tell you to try *iexploreproxy, which sort of works (the browser starts) but sometimes won’t run (especially if your test contains the open command). It would say Access denied or something in the JavaScript error bar. Even if you try to disable all security settings and run the test as root, it wouldn’t bite.

  • Then you try *piiexplore, which works but would have tests mysteriously failing for some reason (sometimes pages can’t load and will time out in an error).

The Solution

The right way to do it is to use *iexploreproxy, but you need to do two things:

  • Before each test run, you need to clear the temporary files and cookies in IE. I use the Ruby script found here which worked like a charm. This would eliminate the JavaScript access denied error.

  • Run the test suite as Administrator. Otherwise, Selenium would fail to modify some registry value at the end and your test logs will not get written.

Probably nobody has figured this one out yet since I can find absolutely no solution on the net to talk about this. Here we go!

For your reference, here’s the commands I used to start Selenium:

1
2
> ruby clear_ie.rb
> java -jar /path/to/selenium.jar -htmlSuite *iexploreproxy http://root/url /path/to/testsuite.html /path/to/logfile.html
Published by kizzx2, on August 14th, 2010 at 2:01 pm. Filled under: Uncategorized Tags: , , , , , 12 Comments

Archlinux — pure awesomeness (+ how to change Linux console font)

Today I checked out Arch Linux. It’s just that cool. It’s a minimalistic distro that focuses on, well, minimalism, simplicity and elegance.

What’s more of a pleasant surprise is that I find the Arch Linux Wiki to be probably the most comprehensive and high quality resources of Linux in general available on the net. Among those gems, I’ve found the way to change the font at the console. I’ve been using nix environments for a couple of years and this is the question that has always bugged me but nobody seemed to have talked about. There you go, several years of research ;)

Setting up Arch Linux was a pleasant learning experience from itself. The package manager pacman offers the same level of convenience as the famous apt, if not more. The nice thing about it is that Arch’s packages seem to be much more recent than those ancient rugs on Debian and Ubuntu.

At the same time, Arch doesn’t bog you down with lots of unnecessary stuffs. Right out of the box, Arch almost doesn’t have any packages, and you have to edit a couple of config files just to be able to download things from the repos. But it was a pleasant learning experience, largely attributable to the excellent wiki.

If you want to improve your nix-fu or just want plain, beautiful distro to play with, give Arch a try!

Published by kizzx2, on July 17th, 2010 at 2:57 am. Filled under: Uncategorized Tags: , , No Comments

Found a great programming blog

Peteris Krumins created a phenomenal blog at good coders, great reuse code. I found it so full of useful information and great posts that I’m going to go out of the way and do my share of Google “SEO voting” for it by linking to it.

It contains a lot more than just programming and is an excellent mind-food.

Published by kizzx2, on April 6th, 2010 at 2:33 pm. Filled under: Uncategorized Tags: , , , , No Comments

Stop Gmail Notifier from asking the password every time upon login

I use the very out-dated Gmail Notifier client. I know it hasn’t been updated since 3 years ago but very sadly it’s still the best Gmail client around (it’s lightweight, works properly and official).

Today I finally solved one annoyance I have with this application, is that it keeps popping out the password dialog box every time I login. Until stumbled upon the solution:

If you want Gmail Notifier to do NOT ask for password each time it starts, the next time that windows pops up asking for username and password, do not use it: just close it. The Gmail Notifier icon will get an (!) warnning after that. Just open Internet Explorer and go to http://mail.Google.Com/ and login with your mail and password, and choose to keep the session open. Then go to Gmail Notifier, yet with the (!) and with the right mouse button choose the option Check Mail Now.

It will not ask you again the password with a desktop window.

Oh well, so the answer turned out to be IE, lol! It looks like the Gmail Notifier client uses IE’s component to access the server, so the password session stored in IE can be used directly. Hooraay!

Published by kizzx2, on November 16th, 2009 at 3:45 pm. Filled under: Uncategorized Tags: 4 Comments