Porting from QNX 4 to QNX Neutrino, or maintaining a program that must function on both, is possible, if you follow these rules:

The key is to not tie yourself to a particular "handle" that represents the "connection" between the client and the server, and to not rely on a particular mechanism for finding the server. If you abstract the connection and the detection services into a set of function calls, you can then conditionally compile the code for whatever platform you wish to port to.

The exact same discussion applies to the message transport—always abstract the client's API away from "knowing" how the messages are transported from client to server to some generic API which can then rely upon a single-point transport API; this single-point transport API can then be conditionally compiled for either platform.

Porting a server from QNX 4 to QNX Neutrino is more difficult, owing to the fact that QNX 4 servers were generally "hand-made" and didn't follow a rigorous structure like that imposed by the resource manager library under QNX Neutrino. Generally, though, if you're porting something hardware specific (for example, a sound card driver, or a block-level disk driver), the main "code" that you'll be porting has nothing to do with the operating system, and everything to do with the hardware itself. The approach I've adopted in these cases is to code a shell "driver" structure, and provide well-defined hardware-specific functions. The entire shell driver will be different between operating systems, but the hardware-specific functions can be amazingly portable.