You are on page 1of 204

MKS Toolkit

UNIX to Windows Porting Guide

MKS Inc.

MKS Toolkit: UNIX to Windows Porting Guide


2004 MKS Software Inc.; in Canada copyright owned by MKS Inc. All rights reserved.

MKS, MKS Toolkit, and AlertCentre are registered trademarks of MKS Inc. NuTCRACKER is a registered trademark of MKS Software Inc. All other trademarks referenced are the property of their respective owners.

MKS Inc. 12450 Fair Lakes Circle Suite 400 Fairfax, Virginia 22033 Phone: +1 703 803-3343 Fax: +1 703 803-3344 E-mail: tk_info@mkssoftware.com 8.7-0604

Technical Support
To request customer support, please contact us by one of the means listed below and in your request include the name and version number of the product, your serial number, and the operating system and version/patch level that you are using. Contact MKS customer support at: Web: E-mail: Telephone: Fax:
http://www.mkssoftware.com/support tk_support@mkssoftware.com

+1-703-803-7660 (9:00am to 7:00pm Eastern, Mon-Fri) +1-703-803-3344

When reporting problems, please provide a test case and test procedure, if possible. If you are following up on a previously reported problem, please include the problem tracking number in your correspondence. Finally, tell us how we can contact you. Please give us your e-mail address and telephone number.

UNIX to Windows Porting Guide

iii

iv

MKS Toolkit

Table of Contents
1 Introduction............................................................... 1
A Note About Compilers ........................................................................2

2 Windows Concepts .................................................. 3


Process Management ..............................................................................3 Process Control................................................................................3 Process And Thread Scheduling......................................................5 Process Identification ......................................................................6 Memory Management......................................................................6 Signal Management .........................................................................7 Security ...................................................................................................8 Windows Security Overview...........................................................9 Security Identifiers ...................................................................9 Security of Objects .................................................................10 Object Access .........................................................................11 Rights and Permissions ..........................................................11 Impersonation .........................................................................11 Users and Groups...........................................................................12 Mapping of User- and Group-IDs ..........................................12 The root User and Group........................................................13 User and Group Database.......................................................13 File Security...................................................................................14 Mapping UNIX Access Modes to NTFS Permissions ...........14 Determining Ownership .........................................................14 File Mode Initialization .................................................................16 File Management ..................................................................................16 File Systems...................................................................................16 Path Names ....................................................................................18 Path Names Containing Spaces .....................................................20 Path Names Corresponding To DOS Device Names ....................20 Text Files and Binary Files............................................................20 File I/O and Control.......................................................................21 Special Files...................................................................................22 Shared Libraries ....................................................................................24 Files ...............................................................................................24 Dynamic Linking vs. Static Linking..............................................24 Exporting Symbols from DLLs .....................................................25

UNIX to Windows Porting Guide

Data Exported From DLLs ............................................................25 Locating DLLs at Run Time..........................................................25 Interprocess Communications and Networking....................................26 Locales ..................................................................................................28 Screen Management..............................................................................28

3 The Porting Process............................................... 31


Overview of the Porting Process ..........................................................31 Preparing to Port ...................................................................................33 Determining the Scope of the Port ................................................33 Accessing Source Files ..................................................................33 Line Termination ....................................................................34 File System Differences .........................................................34 Transferring and Sharing Source Files ...................................34 Selecting a Work Environment......................................................35 Preparing to Build .................................................................................36 Make File Issues ............................................................................36 Header File Issues..........................................................................37 MKS Toolkit UNIX API Header Files...................................37 Compilation Environments.....................................................38 Source Code Issues ........................................................................40 Text and Binary Modes ..........................................................41 ANSI Prototypes.....................................................................41 Global System Variables ........................................................41 Conditional Compilation ........................................................42 Using Data Exported From DLLs ..........................................42 Path Names.............................................................................43 Device Files ............................................................................43 Globbing .................................................................................43 Byte Ordering .........................................................................44 Calling Back Into NuTCRACKER Code From Win32 Code .......44 Compiling and Linking the Application ...............................................46 Debugging the Application ...................................................................47 Porting Scripts.......................................................................................49 Integrating with Windows ....................................................................50 Packaging and Deploying the Application ...........................................51 Porting to Windows Me........................................................................51 Strategies for Maintaining a Single Executable ............................51 Differences Between Windows Versions ......................................52 Daemons/Services ..................................................................52 Security...................................................................................52 Event Logging ........................................................................53 Process IDs .............................................................................53

vi

MKS Toolkit

4 API-Specific Porting Issues...................................55


Process Management ............................................................................55 Process Control..............................................................................55 atexit().....................................................................................55 clock().....................................................................................55 exec() Family..........................................................................55 _exit()/exit()............................................................................56 fork().......................................................................................56 getitimer()/setitimer() .............................................................56 longjmp()/siglongjmp() ..........................................................57 _NutForkExecXXX() Family.................................................57 popen()....................................................................................57 pthread_atfork()......................................................................58 sleep()/nap()/usleep()/nanosleep()..........................................58 system() ..................................................................................58 times().....................................................................................58 vfork().....................................................................................58 waitpid()/wait3()/wait4() ........................................................58 Process And Thread Scheduling....................................................59 getpriority()/setpriority() ........................................................59 nice().......................................................................................59 pthread_attr_setpolicy()/pthread_setschedparam() ................59 Process Identification ....................................................................59 getpgid()/getpgrp()/getsid() ....................................................59 getpid() ...................................................................................60 getppid() .................................................................................60 _NutIsNuTCProcess() ............................................................60 _NutQueryPid() ......................................................................60 pthread_self()..........................................................................60 setpgrp()/setsid().....................................................................61 Memory Management....................................................................61 brk()/sbrk() .............................................................................61 malloc()...................................................................................61 mmap() ...................................................................................61 mprotect() ...............................................................................62 msync() ...................................................................................62 munmap() ...............................................................................62 Signal Management .......................................................................62 bsd_signal() ............................................................................62 kill() ........................................................................................62 sigaction() ...............................................................................63 sigaltstack()/sigstack()............................................................63 sigqueue() ...............................................................................63

UNIX to Windows Porting Guide

vii

sigvec() ...................................................................................64 Security .................................................................................................64 Users and Groups...........................................................................64 getgroups()..............................................................................64 getpwnam()/getpwuid()/getgrnam()/getgrgid() ......................64 getuid()/getgid()/geteuid()/getegid().......................................64 _NutValidatePassword().........................................................65 setuid()/setgid()/seteuid()/setegid() ........................................65 File Security...................................................................................65 File Mode Flags......................................................................65 access() ...................................................................................66 chmod()/fchmod()...................................................................66 chown()/fchown() ...................................................................67 umask() ...................................................................................67 File Management ..................................................................................67 File Systems...................................................................................68 link() .......................................................................................68 mount()/umount() ...................................................................68 statvfs()/fstatvfs() ...................................................................68 lstat()/lchown()/readlink()/symlink()......................................68 Path Names ....................................................................................68 chdir() .....................................................................................68 chroot() ...................................................................................69 getcwd()..................................................................................69 _NutPathToXXX() Family.....................................................69 _NutQueryXXXDir() Family .................................................69 File I/O and Control.......................................................................70 creat()/open()/fopen() .............................................................70 fcntl() ......................................................................................71 _NutFastStat() ........................................................................71 _NutFdToHandle()/_NutHandleToFd() .................................71 read()/write()...........................................................................71 readdir()/readdir_r()................................................................72 rename()..................................................................................72 stat()/fstat() .............................................................................72 utimes()/utime()......................................................................73 Special Files...................................................................................73 ctermid() .................................................................................73 mknod() ..................................................................................73 pipe().......................................................................................73 ttyname()/ttyname_r().............................................................73 Interprocess Communications and Networking....................................73 bind() ......................................................................................73 gethostbyname()/gethostbyaddr()...........................................74

viii

MKS Toolkit

mkfifo()...................................................................................74 poll() .......................................................................................74 select() ....................................................................................74 sendmsg()/recvmsg() ..............................................................74 socketpair() .............................................................................74 shmat()....................................................................................75 Math Libraries.......................................................................................75 Math Library Modes ......................................................................75 Changing Math Library Modes .....................................................76 Optimization Issues .......................................................................76 Miscellaneous Functions.......................................................................77 confstr()/_NutConfStr()..........................................................77 ctime() Family ........................................................................77 dlopen() Family ......................................................................77 errno/h_errno/perror()/strerror() .............................................77 getenv()/putenv()/environ.......................................................78 mktemp() ................................................................................78 _NutDebugBreak() .................................................................78 sysconf() .................................................................................79 syslog() Family.......................................................................79

5 Language Support.................................................. 81
Using C .................................................................................................81 Using C++.............................................................................................81 Using FORTRAN .................................................................................83

6 Using the Visual C++ IDE....................................... 85


Create a New Project ............................................................................85 Visual Studio 5.x and 6.x...............................................................85 Visual Studio .NET 7.x..................................................................86 Set Compiler Options............................................................................86 Visual Studio 5.x and 6.x...............................................................86 Visual Studio .NET 7.x..................................................................87 Set Linker Options ................................................................................87 Visual Studio 5.x and 6.x...............................................................88 Visual Studio .NET 7.x..................................................................88 Build the Application............................................................................89 Run the Application ..............................................................................89

7 Porting X Applications ........................................... 91


Using imake ..........................................................................................91 Choosing the Appropriate Subsystem...................................................92 Linking X Applications ........................................................................93 Locations of X Windows Files .............................................................94

UNIX to Windows Porting Guide

ix

Using Icons ...........................................................................................94 Using Wintif .........................................................................................95 Switching Between Motif and Windows Modes ...........................95 Runtime Detection of Mode ..........................................................96 Changes to Motif Resource Defaults.............................................96 New Wintif Resources...................................................................97 Changes to Motif Widget Behavior...............................................97 Changes to Motif Widget Resources .............................................97 File Selection .................................................................................99 Easing the Transition from Motif to Wintif.................................100 Simultaneous Installation of Motif and Wintif ...................................101

8 Porting Shared Libraries...................................... 103


Building DLLs for NuTCRACKER Platform Applications...............103 Building Basic DLLs ...................................................................103 Avoiding the Module Definition File ..........................................105 Exporting C++ Functions from DLLs .........................................106 Performing Actions at DLL Initialization and Shutdown ...........107 Dynamically Loadable DLLs ......................................................107 Exporting Data from DLLs..........................................................108 Building Standalone DLLs .................................................................109 Issues ...........................................................................................110 Preparing DLL Interfaces ............................................................110 Special Scenarios .........................................................................112 MKS Toolkit UNIX API Differences..........................................113

9 Porting Threaded Applications ........................... 115


NuTCRACKER Platform POSIX Threads Implementation ..............115 NuTCRACKER Platform Threads ..............................................115 Optional POSIX Threads Features ..............................................116 UNIX 98 (Aspen) Threads Extensions ........................................117 UNIX 03 Threads Extensions......................................................117 NuTCRACKER Platform POSIX Threads Extensions ...............118 Threaded X Applications.............................................................118 Threads Implementations on Popular UNIX Platforms......................118 Other POSIX Threads Implementations......................................119 UNIX International (Solaris) Threads .........................................120 Other Threading Packages...........................................................120 Porting Threaded Software from UNIX to NuTCRACKER Platform ..... 120 Porting Draft 10 POSIX Threads.................................................121 Porting Draft 7 POSIX Threads...................................................121 Porting Draft 4 (DCE) POSIX Threads .......................................122 Porting UNIX International (Solaris) Threads ............................122

MKS Toolkit

Porting Other Threading Packages ..............................................123 NuTCRACKER Platform POSIX Threads and Win32 Threads ........123 Reducing Porting Complexity ............................................................125 Implementing Signal Handlers ....................................................125 Using Threads In Place of fork() .................................................127

10 Porting Daemons.................................................. 129


Concepts..............................................................................................129 Windows NT 2000/XP/2003 ..............................................................................129 Windows Me................................................................................130 Converting a Daemon to a Service .....................................................130 Porting an Application.................................................................131 The NuTCRACKER Platform Service Framework ....................131 Debugging a Service....................................................................133 Installing and Testing a Service...................................................134 Distributing a Service ..................................................................134

11 Porting Applications to 64-bit Windows............. 135


IA64 Support.......................................................................................135 Extended 64-bit Support .....................................................................136 Overview of the Process .....................................................................136 Determining the Scope of the Port ..............................................137 Source Code Issues .............................................................................140 Compiling and Linking a 64-bit application................................141 Debugging a 64-bit Application ..................................................141 Porting Issues ......................................................................................142 Porting to 64-bit UNIX Platforms ......................................................143 Best Practices...............................................................................144

12 Deploying Applications........................................147
Concepts..............................................................................................147 Runtime Components ..................................................................147 Packaging/Licensing....................................................................148 Deployment Mechanisms ............................................................148 Definitions ..........................................................................................149 Deployment Overview ........................................................................151 Ensuring an Application Can Coexist.................................................152 Installing the Deployment License Key..............................................153 Running the NuTCRACKER Deployment Wizard ............................154 Selecting Components .................................................................154 Staging the Components ..............................................................155 Writing an Installer .............................................................................155 Using the Installation API...................................................................156

UNIX to Windows Porting Guide

xi

Installation Overview ..................................................................156 Files .............................................................................................157 The Installation API.....................................................................158 Error Handling......................................................................158 Checking Permissions ..........................................................158 Installing the Components....................................................158 Registering Your Application...............................................159 Selecting a Preferred X Server .............................................159 Installing Files in the Root Directory ...................................159 Distributing Third-Party Options........................................................160 Uninstalling Your Application............................................................161

13 Environment Variables......................................... 163 14 Console Escape Sequences................................ 167


Keyboard Keycaps ..............................................................................167 Screen Functions.................................................................................168

15 Evolving Applications with COM ........................ 171


Introduction.........................................................................................171 COM Overview ...........................................................................172 COM Benefits..............................................................................173 Using the NuTCRACKER Platform and COM ..................................174 Using Components..............................................................................176

16 The Communications Port Interface...................177


Com Port Devices ...............................................................................177 Com Port Control................................................................................178 The termios and termiox Structures.............................................178 Supported ioctl() Operations .......................................................179 Supported fcntl() Operations .......................................................180 Other Operations..........................................................................180

Index ...................................................................... 181

xii

MKS Toolkit

Introduction

For a description of the complete MKS Toolkit product line, see the Introduction chapter of the MKS Toolkit Product Overview & Solutions Guide.

MKS Toolkit for Enterprise Developers. These products contain the tools and libraries to aid you in developing cross-platform solutions using the NuTCRACKER Platform, MKS award-winning UNIX compatibility environment on Windows. MKS Toolkit for Professional Developers lets you develop, port, migrate and deploy non-graphical UNIX-based applications and scripts. MKS Toolkit for Enterprise Developers adds support for Motif, X Windows, 3-D, and Open GL giving you a complete solution for cross-platform development, deployment, interoperability, and migration of both graphical and non-graphical UNIX applications and scripts.

Thank you for purchasing MKS Toolkit for Professional Developers or

For a complete description of other documentation included with MKS Toolkit as well as other sources of information, see the Additional Information chapter of the MKS Toolkit Product Overview & Solutions Guide.

While most of the information in this guide applies to both MKS Toolkit for Professional Developers and MKS Toolkit for Enterprise Developers, information on X Windows and other graphics-related packages applies only to MKS Toolkit for Enterprise Developers. The following is an overview of the topics covered: Windows Concepts on page 3 discusses differences between the Windows and UNIX platforms. The Porting Process on page 31 outlines the process of porting a UNIX application to the NuTCRACKER Platform. API-Specific Porting Issues on page 55 discusses some of the issues surrounding individual functions in the MKS Toolkit UNIX APIs. In particular, differences from the equivalent UNIX APIs are covered. Language Support on page 81 discusses the different programming languages you can use to develop NuTCRACKER Platform applications. Using the Visual C++ IDE on page 85 covers using the Microsoft Visual C++ Integrated Development Environment to develop NuTCRACKER Platform applications.

UNIX to Windows Porting Guide

Introduction

Porting X Applications on page 91, Porting Shared Libraries on page 103, Porting Threaded Applications on page 115, Porting Daemons on page 129, and discuss how to port or develop X Windows applications, shared libraries (DLLs), programs using threads, and daemons using the NuTCRACKER Platform. Porting Applications to 64-bit Windows on page 135 discusses how to use the NuTCRACKER Platform to port applications to the 64-bit Windows platform. Deploying Applications on page 147 describes the steps needed to distribute and deploy your NuTCRACKER Platform applications. Evolving Applications with COM on page 171 provides details integrating your NuTCRACKER Platform applications more tightly with Windows. Environment Variables on page 163, Console Escape Sequences on page 167, and The Communications Port Interface on page 177 provide additional reference material that you may find useful.

A Note About Compilers


Throughout this manual, there are many references to compiler and linker options. These options are intended for use with the cc and ld utilities in conjunction with the Microsoft VisualStudio C/C++ compiler. If you are using the GCC compiler provided on the MKS Toolkit Resource Kit CD, see the GCC Release Notes also included on the Resource Kit CD for differences between the behavior described in this manual and GCCs behavior.

MKS Toolkit

Windows Concepts

See API-Specific Porting Issues on page 55 for a discussion of related API functions that are different between UNIX and Windows

This chapter discusses concepts that should be familiar to you when

interoperating with and porting software to Windows. The discussion centers on differences between UNIX and Windows, as well as capabilities in Windows that do not exist in standard UNIX. For more detailed information about Windows operating system concepts, we recommend the book Programming Applications for Windows, 4th ed., by Jeffrey Richter (Microsoft Press, 1999).

Process Management
See Porting Threaded Applications on page 115 for a detailed discussion of threading.

The NuTCRACKER Platform implements a UNIX-style process environment on Windows. UNIX process activation, process control, and process groups are consistent with UNIX without compromising interoperability with native Windows applications. The NuTCRACKER Platform also implements POSIX threads, building on the Win32 threading architecture. The Win32 process model differs from the UNIX process model in that there are no direct equivalents to the fork() and exec() calls. Because of this, the NuTCRACKER Platform implements fork() using CreateProcess() followed by replicating the process address space. This leads to the following issues: The NuTCRACKER Platform only replicates the address space of the executable and of DLLs that have been built with the NuTCRACKER Platform. The Win32 process heap, the data sections, and private heaps of non-NuTCRACKER Platform DLLs is not be replicated, because the NuTCRACKER Platform does not control inheritance of objects that were not allocated through MKS Toolkit UNIX API calls. Address space replication adds some overhead that you can minimize by avoiding fork() in your program.

Process Control

UNIX to Windows Porting Guide

Windows Concepts

The following suggestions can help minimize the effects of the differences in process models: Use one of the mechanisms discussed below to replace fork(). Whenever feasible, use the NuTCRACKER Platform versions of DLLs, to ensure proper address space replication and inheritance of objects. Use the facilities provided by non-NuTCRACKER Platform DLLs in the parent or in the child, but not both. For example, if you have a Win32 database access DLL, you should open and use the database connection in the parent or in the child. You should not open the database connection in the parent and then attempt to use that connection in the child. Because Win32 does not implement the UNIX exec() concept of overlaying the address space of the running process, the NuTCRACKER Platform implements this by creating a new process and blocking the invoking process until the new process exits. Using the following example (error handling omitted for brevity):
if ((pid = fork()) == 0) { execl("task.exe", "task.exe", NULL); } else { waitpid(pid, NULL, 0); }

On UNIX, this results in two processes running while waitpid() is activethe parent calling waitpid(), and the child running task.exe. With the NuTCRACKER Platform, three processes runthe parent calling waitpid(), the child waiting for task.exe to complete, and the new task.exe process. This is important because the NuTCRACKER Platform process ID for
task.exe is not the same as the process ID returned by fork(), as it is on

UNIX. In most instances, the NuTCRACKER Platform handles this distinction transparently, by propagating signals and process exit status as needed. However, if your NuTCRACKER Platform process needs to know the process ID of the child of fork() from which it was exec()ed, it can call the _NutQueryPid() function. The MKS Toolkit UNIX APIs provide two mechanisms for replacing
fork(): vfork() and the _NutForkExec() family of functions.

The vfork() in the MKS Toolkit UNIX APIs does not create a new process, thereby avoiding the process creation overhead. The NuTCRACKER Platform saves the current process state, sets up a new process context, and waits for you to call exec() before returning to the parent process context. Because of this, calling getpid() in the child of a vfork() returns the same process ID as the parent. You should use

MKS Toolkit

Process Management

vfork() when you need to change process context prior to exec()ing another process, such as closing files. The return value from vfork() is the process ID of the exec()ed child. There is no intermediate process waiting for the task to exit, as described above for fork()/exec().

If you do not need to make any process context changes in your fork()ed child before calling exec(), you should use one of the _NutForkExec() family of functions, rather than calling fork() and exec(). This is the most efficient mechanism for spawning a new process. It is even more efficient than vfork(), because it does not save and restore state; it simply creates the new process context.

Process And Thread Scheduling

The Windows scheduler provides preemptive multitasking, with multiple scheduling priorities. The scheduled entity is the thread, not the process. This means that a single process can have multiple threads running at different priorities and scheduled independently by the kernel. Each process has a priority class (for example, real-time, normal, idle), that defines the base priority for threads. Each thread can alter its priority relative to the base priority. On Windows NT/2000/XP/2003, the scheduler supports symmetric multiprocessing (SMP) scheduling, in which multiple threads (from the same or different processes) can run simultaneously on different processors. In addition, the scheduler supports a priority boost algorithm, which causes a thread's priority to be boosted temporarily after waking up from certain types of I/O operations. These capabilities do not exist on Windows Me. Windows is sensitive to changes in priority class and thread priority; small changes can have much more dramatic impact on application and system performance than such changes would have in a UNIX environment. Consequently, the MKS Toolkit UNIX APIs do not provide APIs that let a process alter priority class, but does provide setpriority() and nice() to let a process alter the priority of its threads.

Process Identification

Win32 does not directly support the UNIX concepts of process groups, sessions, or controlling terminals. The NuTCRACKER Platform maintains its own process table to support these concepts. Use the NuTCRACKER Platform process command to display this table. On Windows NT/2000/XP/2003, the NuTCRACKER Platform process IDs are the same as the native Windows process IDs. These are the process IDs that are displayed by the Task Manager, and can be passed to debuggers with the -p option.

UNIX to Windows Porting Guide

Windows Concepts

On Windows Me, the native process IDs are always negative numbers. Because a negative return from a UNIX system call is usually interpreted as an error, the NuTCRACKER Platform modifies the Windows process ID by masking off the high-order bit to make it a positive number. Therefore, to convert from a NuTCRACKER Platform process ID to a Windows Me process ID, add in the high-order bit.

Memory Management

Memory management in Win32 is somewhat different from UNIX. Most UNIX platforms have a single process heap and a single process stack. Win32 provides for multiple heaps within a process, and each thread in a process has its own extensible stack. On UNIX, the process stack is truly dynamicit grows until it reaches a system-imposed maximum. By contrast, stacks on Windows grow to a fixed, per-process limit. The default is 1 megabyte and you can change it with the linker flag -W/stack:value, where value is the stack size in bytes. On Windows, heap growth is not necessarily contiguous as it is on UNIX. If the heap grows, the new address range may not be adjacent to the current heap block. Because the brk() and sbrk() functions require contiguous heap growth, they are not meaningful given the Windows memory management model and you must rethink any code that depends on them. On UNIX platforms, the system page size and the virtual memory allocation granularity are the same. In other words, the alignment and rounding of addresses returned by functions such as mmap() and shmat(), and used as parameters to functions such as mprotect() and shmget(), are the same as the physical page size values returned by sysconf(_SC_PAGESIZE). On Windows, the allocation granularity is not the same as the system page size. Code that depends on these being the same value may need to be changed. The NuTCRACKER Platform provides two parameters for sysconf() to determine the values independently_SC_NUTC_OS_PAGESIZE and _SC_NUTC_OS_ALLOCGRANULARITY. Each NuTCRACKER Platform process has two heaps controlled by the NuTCRACKER Platformthe NuTCRACKER Platform heap (used for NuTCRACKER Platform internal allocations), and the application heap (from which application memory is allocated, for example, via malloc()). Win32 maintains an additional heap, for use by the OS and by Win32 DLLs in your application. Win32 DLLs may allocate additional heaps for private use. When a NuTCRACKER Platform process fork()s, the following memory segments are replicated in the child: Data segments for the executable and any DLLs built with the NuTCRACKER Platform.

MKS Toolkit

Process Management

The NuTCRACKER Platform heap and the application heap. All attached shared-memory (that is, shmat()) segments. All memory-mapped (that is, mmap()) segments. All thread-specific data.

Signal Management

Win32 does not support interprocess exchange of software signals; there is no analog to the UNIX kill() system call. In addition, most Win32 kernel operations are not interruptible. The NuTCRACKER Platform implements UNIX signals, supporting both synchronous (for example, access violation) and asynchronous (for example, Ctrl-C) signal delivery, and interruption of system calls. Despite the Win32 limitations, in the vast majority of cases, the NuTCRACKER Platform signals behave just like UNIX signals. Because of the blocking nature of Win32 kernel operations, the NuTCRACKER Platform takes special actions to deliver asynchronous signals. If the NuTCRACKER Platform detects that the process is not in an interruptible state, it suspends the thread to which the signal is being delivered and run the signal handler in a new thread. This action is transparent in most circumstances; the NuTCRACKER Platform ensures that this new thread looks like the user thread (for example, pthread_self() returns the ID of the thread to which the signal was directed, not the ID of the Win32 thread that is actually running the signal handler). However, because the actual Win32 operation could not be interrupted, if the signal handler returns rather than exiting, the system call may not actually return EINTR right away. One example where this occurs is a read on an anonymous pipe, which cannot be interrupted under Win32. You can find the list of signals and their default actions (the action taken if no user signal handler has been installedExit, Stop, Ignore, or Core) in the online MKS Toolkit UNIX APIs Reference. There you can also find a table defining how the NuTCRACKER Platform maps Win32 exceptions to UNIX signals. This table shows that the NuTCRACKER Platform never generates certain signals. You can still raise such signals programmatically by calling the kill() function. A signal whose default action is Exit causes the process to exit with the Win32 exception number corresponding to the signal as its exit code. This makes the process compatible with native Win32 programs. The NuTCRACKER Platform converts Win32 exit codes, so that the NuTCRACKER Platform processes calling wait() or waitpid() receive status in the form they expect.

UNIX to Windows Porting Guide

Windows Concepts

The NuTCRACKER Platform does not support job control signals. Therefore, any signal whose default action is Stop never occurs. The default action for these signals is treated as Ignore. Signals whose default action is Core normally cause the process to exit with the appropriate code if no signal handler has been installed. However, if you set the NUT_DUMP_CORE environment variable, the NuTCRACKER Platform dumps a core file named core.pid, where pid is the process ID, in the current directory. This dump file is compatible with the Dr. Watson system dump utility, and can be read by the windbg debugger from the Win32 SDK; the Visual C++ debugger (msdev) cannot read these files. You can bypass the NuTCRACKER Platform default signal handler actions by setting the NUT_DEFAULT_WIN32_FAULT environment variable. This causes the signal to be propagated to Windows for handling if a user signal handler has not been installed. This normally causes a pop-up dialog to appear, letting you attach a debugger to the process (if you have enabled Just-In-Time debugging through your debugger). This should be done only for debugging, and never in a production environment.

Security
Windows NT/2000/XP/2003 provides a C2-level security model, based on Access Control Lists (ACLs) and access rights. This security model is more restrictive than that of most UNIX systems, and causes many difficulties in porting software between the operating systems. This section first discusses Windows NT/2000/XP/2003 security, and then discusses how UNIX user/ group and file security models are mapped into this environment.

Note Windows Me provides almost no security. This is one of the few porting areas in which Windows NT/2000/XP/2003 and Windows Me differ significantly.

MKS Toolkit

Security

Windows Security Overview

Windows NT/2000/XP/2003 security is built around objects. This section describes how these objects, and the descriptors and tokens associated with them, interact to allow or deny access to system resources.

Note While Windows XP uses the same security model as Windows NT,

Windows 2000, and Windows 2003, Windows XP Home has no support for Active Directory and does not support being joined to a domain.

Security Identifiers
The operating system automatically assigns a unique security identifier (SID) to each user and group when it is created. This is different from UNIX, where the administrator manually assigns user and group identifiers. The SID is guaranteed to be globally uniquethe same SID is never generated more than once on any Windows NT/2000/XP/2003 system. A SID has two parts. The first is a series of sub-authorities that uniquely identifies the machine or domain that assigned the identifier. The second is a single sub-authority called the relative identifier (RID). The RID is unique within the machine or domain (referred to as locally unique). Windows NT/2000/XP/2003 stores user and group account information in the Security Accounts Manager (SAM). Each Windows NT/2000/XP/2003 system has one SAM database defining local group and user account information. On a network using the Windows NT/2000/XP/2003 domain security model (prior to Windows 2000), the SAM database on the Primary Domain Controller is used for all domain workstation logins. The Backup Domain Controller maintains a replica of the domain SAM database and all its local databases, in case the Primary Domain Controller fails. In the Windows 2000/XP/2003 Active Directory, this security database is distributed among all Active Directory Servers in the domain tree. The Active Directory uses Globally Unique IDs (GUIDs) to identify users, groups and computers, and maps these to appropriate IDs. At the level of this discussion, the distinctions between the old domain model and the new Active Directory models are not relevant. Windows NT/2000/XP/2003 keeps a list of deleted accounts; their RID values are not reused. Once an account is removed, the SID belonging to that account cannot be reused. Objects marked with the deleted account SID retain this information.

UNIX to Windows Porting Guide

Windows Concepts

Security of Objects
Windows NT/2000/XP/2003 resources, such as files, processes, and devices, are referred to as system objects. Access to each of these system objects is mediated by a security architecture and corresponding security API. Each object has an associated security descriptor that defines ownership, access permissions, inheritance, and audit trails for that object. The security descriptor contains the following information: Ownerdefines the user or group SID that owns the object. Primary groupdefines the primary group SID. Discretionary Access Control List (DACL)defines the access permissions for the object. System Access Control List (SACL)defines the audit trail for the object. An Access Control List (ACL) consists of Access Control Entries (ACEs). Each ACE consists of a SID and an access mask. The ACE describes allow or deny access, or audit or system action, for the SID. Most objects have an attached DACL that describes the access permissions for that object. The DACL contains two types of ACEs: Allow and Deny. The Deny ACE denies a user or group access to an object. The Allow ACE grants a user or group access to an object.

Object Access
Every Windows NT/2000/XP/2003 process has an access token containing the owner, groups, auditing, and access security information necessary to validate access of the process to system objects. Windows NT/2000/XP/2003 grants access by comparing the access token owner and groups against the DACL of the desired object. The ACEs are scanned sequentially, and as soon as a Deny or Allow determination has been made, the scan stops. The preferred order for ACEs is to put all Deny ACEs before Allow ACEs, although the system lets you install ACEs in any order. If the entire list is scanned and no ACE applies, access is denied. Hence, an empty DACL denies access to everyone. On the other hand, if an object has no DACL, access is granted to everyone. The object owner can always modify the objects DACL.

Rights and Permissions


A right authorizes a user to perform certain actions, such as changing the system time, or logging in locally to the machine. Rights can be assigned to individual users, but it is more common to add users to a group that has these rights, such as the Administrators or Guests group.

10

MKS Toolkit

Security

A permission is a rule associated with an object (for example, a directory, file, or printer) in the form of a DACL that regulates which users or groups can have access to the object and in what manner. Taken together, rights and permissions make belonging to a group more powerful under Windows NT/2000/XP/2003 than on UNIX. On UNIX, a group is simply a collection of users, and this collection is used to regulate access to files. On Windows NT/2000/XP/2003, groups have rights, which are conferred to group members. When group permissions conflict, deny permissions always override allow permissions.

Impersonation
UNIX impersonation lets users with the proper privileges assume the identity of other users (set-user-ID and set-group-ID). By contrast, Windows NT/2000/XP/2003 limits impersonation to RPCs and named pipesan RPC- or named pipe-server can impersonate the client at the other end of the connection. An arbitrary process cannot assume a different user identity without negotiating an account name/password challenge.

Users and Groups

As discussed in Rights and Permissions, Windows NT/2000/XP/2003 places more restrictions on what users can do than does UNIX. On Windows NT/2000/XP/2003, the NuTCRACKER Platform implements all the major security features found on UNIX. In areas where UNIX security might conflict with Windows NT/2000/XP/2003 security, the NuTCRACKER Platform follows the Windows NT/2000/XP/2003 implementation. Because Windows Me does not have a security model, the NuTCRACKER Platform maintains pseudo user- and group-IDs in the Windows registry.

Mapping of User- and Group-IDs


On Windows NT/2000/XP/2003, the NuTCRACKER Platform uses the RID as a value for the user or group ID. Because RIDs are only unique within a domain, it is possible that the same RIDs can occur in both the local, primary domain, and trusted domain SAM databases. The high-order12 bits of a user or group ID is set to a unique offset to indicate from which SAM database the ID originates. The high-order bit of a user or group ID is set for accounts that originate in a local (non-domain) SAM database and the high order bit is clear in the user or group ID for accounts that originate in a domain database. There are a couple of limitations, however: For accounts that originate in a non-domain SAM database, there is no guarantee that the user or group ID will have the same numeric value when the same account is looked up by an application running on a different computer.

UNIX to Windows Porting Guide

11

Windows Concepts

There is no guarantee that the user or group ID for non-domain accounts that do not belong to the machine on which the application is being run will have the same value after a reboot. The numeric value of a user or group ID for accounts from the SAM database of the machine on which the application is being run will always remain the same after a reboot, however. The unique offsets chosen for trusted domains also may change in the event that domain trust relationships are created or destroyed. The unique offset for the primary domain is always zero (thus, in this case, the user or group ID is always equal to the RID for the account). On Windows Me, the NuTCRACKER Platform assigns a unique user ID for each user that logs onto the system. There is no guarantee that the same user logging onto multiple Windows Me systems will be assigned the same user ID by the NuTCRACKER Platform, because the OS does not recognize these as the same user. The NuTCRACKER Platform user ID can be manually changed via the MKS Toolkit control panel applet. You are responsible for ensuring that the user ID is unique. All users are also assigned to the group Users by the NuTCRACKER Platform.

The root User and Group


Windows NT/2000/XP/2003 does not have any concept that directly maps to the UNIX root user. Rather than providing one all-powerful user ID, Windows uses rights to determine which users can perform various actions. The user Administrator in each domain is assigned all system administration rights, by default. Members of the Administrators and Domain Admins groups are also assigned these rights. The NuTCRACKER Platform maps the Administrator account to user ID 0, and the Administrators and Domain Admins groups to group ID 0. Because Windows NT/2000/XP/2003 does not provide a direct mechanism for one user (or group) to impersonate another, it is difficult to implement facilities such as setuid()/setgid(). The NuTCRACKER Platform implements these functions by maintaining effective user- and group-IDs, and using these in the owner/group SIDs of the security descriptors used to access objects. The NuTCRACKER Platform also adds separate ACEs for both the real and effective user and group ID when needed. On Windows Me, the NuTCRACKER Platform recognizes user ID and group ID of 0 as special, and lets a process switch between these and the normal user and group ID with setuid()/setgid(). Because Windows Me has no security, this is simply an ease-of-porting facility.

12

MKS Toolkit

Security

User and Group Database


The NuTCRACKER Platform provides the standard functions that simulate read access to /etc/passwd and /etc/groups databases (getgrgid(), getpwuid(), getgrnam(), and getpwnam()). On Windows NT/2000/XP/ 2003, this is done by accessing the SAM database or Active Directory, while on Windows Me, it is done by implementing pseudo user- and group-IDs. If your application attempts to access these files directly, it must be modified to use the appropriate access API. There are no standard UNIX APIs to modify the user or group databases. On UNIX, the administrator manually modifies user, group and/or password databases (or uses a centralized facility such as NIS). In Windows NT/2000/ XP/2003, the administrator updates the database through the appropriate administrative utility. When an account is deleted or an account name is modified, the NuTCRACKER Platform Service should be restarted, so that it can update the NuTCRACKER Platform internal security tables. On Windows Me, user and group information can be modified via the MKS Toolkit control panel applet.

File Security
SeeFile Systems on page 16 for more information.

As discussed in Windows Security Overview on page 9, all Windows NT/ 2000/XP/2003 objects have a security descriptor. For disk files, only the NT File System (NTFS) supports on-disk file security. The NuTCRACKER Platform uses the DACL in the security descriptor of a file to simulate the data stored in UNIX inode structures. None of the other file systems on Windows NT/2000/XP/2003 support file security. Windows Me does not support file security.

Mapping UNIX Access Modes to NTFS Permissions


In addition to the UNIX read, write, and execute permissions, Windows NT/ 2000/XP/2003 has: Delete (D) Change Permission (P) Take Ownership (O) On UNIX, write access on a file implies Change Permission and Take Ownership permissions, while write permission on the directory containing the file implies Delete permission for the file. Because Windows NT/2000/ XP/2003 separates UNIX write mode into four permissions, the write permission alone in Windows NT/2000/XP/2003 has a weaker definition than the UNIX write mode. Hence, to provide expected behavior, NuTCRACKER Platform adds DPO permissions to any file that is created with write permission. You can also add these permissions with chmod().

UNIX to Windows Porting Guide

13

Windows Concepts

Determining Ownership
UNIX and Windows NT/2000/XP/2003 handle file ownership differently. On UNIX, a file or directory is marked with three sets of permissions: those for the owning user, those for the owning group, and those for everyone else (referred to as Other). If you do not have permission to read a file that you own, you cannot read it even if Other read permission is enabled. On NTFS, a file has an Owner (which can be either a user or a group) and a set of user and group IDs with associated permissions. This information is stored in the files DACL. The permissions available to the owner are contained in the DACL, except that the owner of the object can always modify the DACL. To emulate the UNIX security model, the NuTCRACKER Platform inspects the files DACL to determine the Owner, the Group, and Other as defined by the UNIX security model. Many UNIX implementations let users assign ownership of objects to another user or group (if the assigning user has the appropriate permissions). On Windows NT/2000/XP/2003, only users with specific user rights can assign ownership. However, you can claim ownership of an object for which you have Take Ownership permission. If the owner SID is actually a group SID, the NuTCRACKER Platform determines if the current user is a member of that group. If so, it tells the application that this user is the owner. If not, the group remains the owner. The NuTCRACKER Platform determines UNIX owner/group/other permissions as follows: The user is the owner of a file if any of the following conditions is met: The user name is the same as the name of the file owner. The name of a group to which the user belongs is the same as the name of the file owner. If none of the above is true, the user has no owner rights to the file. The group permission for this user is used if the user is not the owner and any of the following conditions is met: The primary group for the file is the same as the primary group for the user. One of the groups to which the user belongs matches a group in the file DACL. When multiple groups match, the group with the most rights is used. If none of the above is true, the user has no group rights to the file.

14

MKS Toolkit

File Management

The others permission is used for this user if an ACE for the group Everyone exists in the file DACL, although this does not exactly match the UNIX semantics for other, because Everyone includes the owner.

File Mode Initialization

The NuTCRACKER Platform creates a default DACL to place on files. The contents of this DACL depend upon several system variables and calls to umask(). This API is identical to UNIX implementations, except that it adds additional bits for the Windows NT/2000/XP/2003 Delete, Change Permission, and Take Ownership privileges. When the parent task is not a NuTCRACKER Platform application, the umask comes from the UMASK environment variable or is 022, if the environment variable is not defined. The umask is inherited across fork(), exec(), and _NutForkExec().

File Management
The NuTCRACKER Platform supports all file systems supported by Win32, and provides automatic handling of path names in UNIX, Win32, and NuTCRACKER Platform formats, as well as Win32 Universal Naming Convention (UNC) format. On NTFS, the NuTCRACKER Platform supports UNIX file security and hard links between files (on Windows NT/ 2000/XP/2003), as well as symbolic links and mount points (Windows 2000/ XP/2003-only features).

File Systems

Win32 and the NuTCRACKER Platform support several file systems: NTFS The NT File System. Supports long file names, case-preservation of names, file security and hard-links. Maintains creation, lastmodification, and last-access times for files. In Windows 2000 and Windows XP, support is added for reparse points (to implement mount() and symlink()-like concepts) and encryption. Because NTFS is closest to UNIX file systems semantically, use NTFS whenever practical. VFAT The Virtual File Allocation Table file system. Comes in a variety of flavors, such as FAT16, FAT32, FAT32x. Supports long file names with case-preservation. Maintains creation and last-modification times, and last-access dates (not times) for files. Does not support security or hard links. This is the standard file system for Windows Me.

UNIX to Windows Porting Guide

15

Windows Concepts

FAT The File Allocation Table file system. Supports only short file names (8.3 format). Maintains only last-modification time; creation and lastaccess times are not maintained. Does not support security or hard links. This is the traditional DOS file system. DOS can continue to read and write VFAT partitions modified by Windows as the on disk representation of VFAT is fully FAT compatible and an 8.3 representation of all long files names is preserved. CDFS The CD-ROM File System, also known as ISO-9660 or High Sierra format. This file system is similar to FAT, with only short names (8.3). Does not support security or hard links. Because Win32 does not recognize the Rock Ridge extensions, a CD-ROM with Rock Ridge extensions is recognized as CDFS when mounted on a Win32 system. Most UNIX platforms use Rock Ridge. Joliet The standard Microsoft format for CD-ROM file systems, and an extension to CDFS. Supports long file names with case-preservation. Does not support security or hard links. The Joliet extensions are not the same as the Rock Ridge extensions used for long file names on UNIXbased CD-ROMs, although it is possible to build a CD-ROM that supports both formats. UDF Universal Data Format. This format is used by DVD-ROMs, rewritable DVDs, and packet-writing software for CD-R/CD-RW (such as Roxios DirectCD). Supports long file names and case preservation. The format supports security, but current implementation doesnt make use of it. Supported entirely by Windows Me and Windows 2000/XP/2003. Readers for other Windows systems are available free from Roxio. The distinction between case-preservation and case-sensitivity is important. UNIX file systems are case-sensitive, meaning that you can have three files named Makefile, makefile, and MakeFile in the same directory. With NTFS and VFAT, you can have a file named Makefile, or one named makefile, or one named MakeFile, in a given directory, and the case of the name is retained. However, you cannot have more than one of these files in the same directory, because all three names access the same file. This can be important when transferring files from UNIX to Windows. There is no simple mapping to the UNIX concept of an inode number, which uniquely identifies a file on a given disk device. Locally-mounted NTFS and VFAT partitions do support an inode-type index; however, network

16

MKS Toolkit

File Management

partitions and other local file systems do not. The NuTCRACKER Platform makes an approximation of an inode number for a file, but this number is not reliable. Algorithms that depend on inode numbers should be modified when porting.

Path Names

The NuTCRACKER Platform recognizes several path name conventions and maps these into a format that can be recognized as an absolute UNIX path. Unlike UNIX, Win32 path names have a drive letter component. The NuTCRACKER Platform supports several conventions for specifying drive letters in UNIX paths: You can specify the drive with /X=/, where X is the appropriate drive letter. This is a NuTCRACKER Platform-specific extension. For example, the following statement opens file in the root directory of the D: drive:
open("/D=/file", O_RDONLY);

You can specify the drive letter with a DOS-style path X:/, or //X/. For example, the following statement copies the file myprog.c to the root directory of drive B::
cp myprog.c B:/

Path and file names returned from functions provided by the MKS Toolkit UNIX APIs are in the form /D=/. Applications that expect absolute paths to begin with a forward slash (/) can be ported without modification in this respect. Windows has no equivalent to the single system root of UNIX file systemseach drive has a root directory. If you request information about / , the NuTCRACKER Platform returns information about the root of the current drive. chdir("/C=/tmp") has the side effect of changing the current drive to C:.
Note UNIX allows path names containing multiple consecutive slashes, for example: //dira//dirb//file. Win32 interprets any path beginning with // as a UNC path. UNC rules cause Win32 to look for /dirb/file on the machine named dira. Multiple slashes are allowed and behave as they do on UNIX, except as the leading two characters.

The NuTCRACKER Platform automatically converts PATH and other environment variables from Win32 format to NuTCRACKER Platform format when the process starts, for compatibility with UNIX. For example:
PATH=c:\winnt;c:\winnt\system32;c:\nutc\bin

becomes:
PATH=/C=/winnt:/C=/winnt/system32:/C=/nutc/bin

UNIX to Windows Porting Guide

17

Windows Concepts

You must use the NuTCRACKER Platform format for specifying a path name within an environment variable when you change the environment at runtime. For example:
putenv("PATH=/d=/dir1/dir2:/c=/winnt");

The NuTCRACKER Platform does not convert arguments passed to the application in the argv array.
Note The NuTCRACKER Platform path format (/D=/) is only recognized by

NuTCRACKER Platform applications. You must not pass path names in this format to non-NuTCRACKER Platform programs, as arguments on the command line, or as output to be read by a non-NuTCRACKER Platform
program.

The MKS Toolkit UNIX APIs include the functions _NutPathToNutc(), _NutPathToWin32() and _NutPathToWin32FS() to aid in converting paths from one format to another. The following table summarizes the path name formats recognized by the NuTCRACKER Platform.
Path Name
/D=/dir1/dir2/file

Description

NuTCRACKER Platform format, using forward slashes(/), and the D= drive specification. This format makes path parsing in UNIX code work with few or no changes.
The normal Win32 format. Use the drive letter followed by a colon as a prefix to the DOS-style path name. This format is called Win32 Forward Slash. Use the drive letter followed by a colon as a prefix to the UNIX-style path name. The UNC specification lets you identify a file on a network file share. Windows NT/2000 POSIX (and Windows XP Interix) subsystem format.

d:\dir1\dir2\file

d:/dir1/dir2/file

\\host\sharename\dir1\dir2\file

//D/dir1/dir2/file

18

MKS Toolkit

File Management

Path Name
//host/sharename/dir1/dir2/file

Description You can also use the UNC format with forward slashes.

Path Names Containing Spaces

Path names containing spaces are common in Windows. For example, the standard directory for installing Windows programs is Program Files. For graphical applications, this is not a problem. However, for command-line based applications, including shell scripts, the spaces can present a problem. The solution varies with the application. Usually, correct quoting of arguments passed to other programs ensures that the program receives an appropriate argument list. In some circumstances, you may need to modify the command-line parsing in your application to accommodate path names containing spaces. To maintain compatibility with older applications, Windows reserves file names that correspond to MS-DOS special devices, such as AUX, LPT1, CON, NUL, PRN, and COM1. Windows does not allow you to create files with a DOS device name as the file name, or as the base part of the file name (the part prior to the first period). For example, AUX and AUX.TXT are invalid file names, but AUXILIARY and AUXILIARY.TXT are valid. Because this naming restriction is enforced by the Win32 file handle API functions, you cannot use these file names with NuTCRACKER Platform applications. UNIX uses a single line-feed character (\n) as a line delimiter in text files. Win32 uses a carriage return/line-feed pair (\r\n) to delimit text lines. This can cause problems when porting code that assumes that a line-feed terminates a text line. The NuTCRACKER Platform supports opening files in text mode to help alleviate these problems. When a file is opened in text mode, reading from the file converts carriage return/line-feed pairs to just a line-feed, and writing to the file converts single line-feeds to carriage return/line-feed pairs. The best solution to this problem is to modify the code to handle either form of line termination. However, because this can result in significant code changes, the following options are available (in decreasing order of preference):

Path Names Corresponding To DOS Device Names

Text Files and Binary Files

For more information, see the open() and fopen() reference pages in the online MKS Toolkit UNIX APIs Reference.

Open individual files in text mode, as needed. Use the _NutConf() function to set the default file opening mode to text mode. Link your program with the textmode.obj file supplied with the MKS Toolkit UNIX APIs to set the default file-opening mode to text mode.

UNIX to Windows Porting Guide

19

Windows Concepts

It is always preferable to avoid using text mode whenever possible, because it makes sharing file descriptors difficult. Specifically, if you pass a file descriptor to a third-party NuTCRACKER Platform DLL, or to another process via inheritance, if you have opened the file in text mode, and the recipient assumes binary mode, there may be problems interpreting the file contents.

File I/O and Control

On UNIX, all types of files (for example, disk files, device files) use a uniform name space in the file system, and each is represented by a file handle. The UNIX API treats these file handles the sameyou use the same function to read from a disk file, from a serial port, and from a console. Windows uses handles to various forms of objects (for example, files, and consoles), but these handles are not treated uniformly. There are different functions to manipulate different types of handles (for example, ReadFile(), ReadConsole()). The NuTCRACKER Platform hides these issues in most circumstances. You need to be aware of this issue when files are inherited from one process by another. When one NuTCRACKER Platform process invokes another, file inheritance occurs as on UNIX. However, when a NuTCRACKER Platform process invokes a non-NuTCRACKER Platform process, only the three standard handles (0, 1, and 2stdin, stdout, stderr) are inherited from one by the other. If a NuTCRACKER Platform process invokes a nonNuTCRACKER Platform process, which in turn invokes a NuTCRACKER Platform process (referred to as a grandchild process), the grandchild inherits files from the grandparent if the intervening non-NuTCRACKER Platform process created the grandchild with the Win32 flag that allows inheritance (bInheritHandles=TRUE). On UNIX, if a file is unlinked while in use by one or more processes, its directory entry is removed, and the disk space used by the file is released when the last process closes the file. Under Win32, it is not always possible to delete an open file. To ensure that UNIX semantics are maintained, NuTCRACKER Platform moves the file to a hidden directory called NutTrash4 in the root directory of the file system, and then deletes the file. This ensures that the directory entry for the deleted file is removed at the time of the unlink() call, so that another file with the same name can then be created in that directory.

Special Files

The NuTCRACKER Platform implements several UNIX-style special files (normally devices). You should not expect to be able to access any special file that is not documented; if your code directly accesses such files (for example, /dev/kmem), it must be modified when ported to Windows. The supported special files are:

20

MKS Toolkit

File Management

/dev/null /dev/null is mapped to the system device NUL:, which acts the same as the UNIX /dev/null. /dev/zero /dev/zero provides an infinite source of zeros - reads return a buffer

full of zeroed memory, and writes have no effect. This device is useful with mmap() for creating anonymous shared memory segments.
/dev/tty, /dev/console

These devices specify the console window for the current application. If the application already has a console window, opening /dev/tty creates a new file descriptor referring to that console. If the application does not have a console (that is, it was created detached, or is a Windows-subsystem application), opening /dev/tty and specifying O_CREAT causes a new console window to be allocated for the application.
/dev/com/n, /dev/com/nM
See The Communications Port Interface on page 177 for more information.

These devices specify the serial communication ports on the system. /


dev/com/n corresponds to the Win32 COMn: device; /dev/com/nM

is the corresponding modem-control port. You can work with these devices through the standard termios functions and ioctl()s.
/dev/lp

This device specifies the default printer for the current system. You can write data to the resulting file descriptor, which is spooled to a temporary file, and then printed when the file is closed. You can open an arbitrary printer on the network by specifying its UNC name (for example, \\system\sharename). This can be used to print raw data. Full Win32-style printing requires Win32 GDI programming.
/dev/clipboard

This device gives a simple interface to the Win32 clipboard. A snapshot of the clipboard is taken when the file is opened. It can then be manipulated as a regular file, and the clipboard is updated when the file is closed. /dev/clipboard currently only supports text. Binary transactions are not supported.
/dev/dde/application/topic

This is a character device for client-only DDE transactions. This device can only be opened for writing, and transactions have a 1-minute timeout.

UNIX to Windows Porting Guide

21

Windows Concepts

//./D:

On Windows NT/2000/XP/2003, this path opens the logical drive block device for sector-level access, where D is the drive letter. This can be used with disk partitions, floppy drives, and CD-ROM drives. For disk partitions, the process must be run by a user with Administrator privileges for the local system. On Windows Me, this device name is not supported. Accessing the block device requires direct Win32 programming, using the techniques discussed in the Microsoft Knowledge Base articles [Q125712] and [Q138434].
//./PhysicalDriven

On Windows NT/2000/XP/2003, this path opens the hard drive block device for sector-level access, where n is the physical drive number. The process must be run by a user with Administrator privileges for the local system.

You should be extremely careful when using this device name as mistakes could result in wiping out your file system. This device name is similar to /dev/hda1 on Linux and should be used with the same caution.
Caution

On Windows Me, this device name is not supported. Accessing the block device requires direct Win32 programming, using the techniques discussed in the Microsoft Knowledge Base article [Q125712].
See your Win32 documentation for information about named pipes; see the mkfifo() reference page in the online MKS Toolkit UNIX APIs Reference for information about FIFOs in the NuTCRACKER Platform.

//./pipe/pipename, //machine/pipe/pipename

These path names access Win32 named pipe objects. Opening the device with the O_CREAT option makes the process a server for the named pipe; opening without O_CREAT makes the process a client of the named pipe. Windows Me only supports client-side named pipe connections; Windows NT/2000/XP/2003 supports both client and server named pipe connections.

Note Win32 named pipes are not the same as UNIX FIFOs, which are also

sometimes referred to as named pipes.

22

MKS Toolkit

Shared Libraries

Shared Libraries
The Windows equivalent to a UNIX shared library is the DLL (Dynamic Link Library). In many respects, UNIX shared libraries and DLLs are similar. The following sections discuss the essential ways in which they differ.

Files

On most UNIX platforms, a shared library is a single file, referenced both at link time and at run time. DLLs comprise two parts: the DLL itself, and an import library. The import library defines the interfaces to the DLL, and is used at link time to create the program. The normal file extension for an import library is .lib. The DLL is loaded at run time, and contains the actual implementation of the library. The normal file extension for a DLL is .dll. The base name of the DLL and the import library are not required to match, although they normally do. The name dynamic link library is a misnomer. DLLs are actually statically linked, and dynamically loaded, meaning that mapping of a symbol to a specific DLL is performed at the time the executable referencing the DLL is linked. When the DLL is dynamically loaded at run time, the symbols are resolved to the specific DLL in which they were located when the program was linked. UNIX shared libraries, on most platforms, are both dynamically linked and dynamically loaded. The linker stores a list of symbols and a list of libraries, which is ordered based on how the libraries were specified on the link line. At run time, the libraries are loaded in order, and symbols are resolved from the first library that defines the symbol. In most instances, this distinction is not important. It becomes important, however, when an application uses features of the run-time loader (for example, the LD_LIBRARY_PATH environment variable) to change the order in which libraries get loaded into the process. With UNIX-style dynamic linking, it is possible for a symbol to be resolved at run time from a different library from the one in which it was found at link time. With Windows DLLs, this cannot happen. Applications that use these techniques (for example, to replace functions at run time for purposes of debugging) need significant restructuring when ported to Windows.

Dynamic Linking vs. Static Linking

Exporting Symbols from DLLs

On most UNIX platforms, when a set of object files is linked into a shared library, the set of symbols exported from a shared library is the aggregate set of external symbols in the set of object files. You do not have to do any work to create an entry point list for the library. While this requires no effort, it also exposes many symbols that you may not want exposed.

UNIX to Windows Porting Guide

23

Windows Concepts See Porting Shared Libraries on page 103.

Windows requires you to explicitly describe the set of symbols exported from a DLL, using either a module definition file (.def file), or compiletime directives to cause the symbol to be exported when a DLL is linked. One area where Win32 DLLs have a major difference from UNIX shared libraries is in exporting data from DLLs. Access to data exported from a DLL requires (at least) one level of pointer indirection, which implies that code must be executed to access the variable. Because of this, the following code does not compile outside the body of a function in a C source file:
int local_int = int_variable_exported_from_dll;

Data Exported From DLLs

See Using Data Exported From DLLs on page 42 for examples of resolving this issue when porting C sources.

The Visual C++ compiler does not generate initialization code for run-time initialization of global variables when compiling C source. For C++ source files there is no issue, because the compiler generates the equivalent of a C++ static constructor to initialize the variable. The following search order is used to locate DLLs both when a program is run, and when it dynamically loads a DLL while it is executing: 1. The directory from which the application loaded. 2. The current directory. 3. The Windows system directory (Windows Me). The 32-bit Windows system directory (Windows NT/2000/XP/2003). 4. The 16-bit Windows system directory (Windows NT only). 5. The Windows base directory. 6. The directories that are listed in the PATH environment variable. This search order becomes important when deciding how to distribute your application and its DLLs. Usually the DLLs are installed in the same directory as the executable (satisfying the first location in the search order). However, for DLLs that are shared among several executables installed in different locations, this leads to extraneous copies of the file on the system. Hence, DLLs that are shared among several applications are normally installed into the Windows system directory (all DLLs supplied with the NuTCRACKER Platform are installed this way, for this reason). Most UNIX platforms provide an environment variable, LD_RUN_PATH, which causes a specific search path to be linked into the executable, for resolving exactly the issues just raised. There is no equivalent capability on Windows.

Locating DLLs at Run Time

24

MKS Toolkit

Interprocess Communications and Networking

Interprocess Communications and Networking


The NuTCRACKER Platform supports the standard System V Interprocess Communications (IPC) mechanisms (shared memory, semaphores, and message queues) by building on Win32 system objects. These facilities are persistent (that is, retained even when no NuTCRACKER Platform process is running), and the standard security attributes are supported (restricted on Windows Me by the lack of security). Parameters for these facilities can be adjusted using the MKS Toolkit control panel applet. In addition, the NuTCRACKER Platform supports the newer POSIX.4/ UNIX 03 semaphores (sem_*, <semaphore.h>), shared memory (mmap, <sys/mman.h>), message queues (mq_*, <mqueue.h>), and signals (sigqueue(), sigwait()) IPC mechanisms. The NuTCRACKER Platform also supports UNIX FIFOs. The implementation of FIFOs is compatible with standard UNIX implementations. You need to be aware of the following issues: FIFOs must be created in the fifos directory under the MKS Toolkit installation directory. You can get this directory with the _NutQueryRootDir() function. You must modify your code to create the FIFO under this directory, for example:
sprintf(buf, "%s/fifos/%s", _NutQueryRootDir(NUTFMT_NUTC), MYFIFONAME); mkfifo(buf, 0666);

NuTCRACKER Platform FIFOs appear to be regular files to nonNuTCRACKER Platform applications. If a non-NuTCRACKER Platform application writes to a FIFO, it is corrupted such that it no longer appears to be a FIFO to NuTCRACKER Platform applications. The NuTCRACKER Platform implements the standard sockets API, based on the native Win32 Winsock 2.0 libraries (standard with Windows NT/ 2000/XP/2003 and Windows Me). NuTCRACKER Platform sockets are semantically the same as UNIX sockets, including support for out-of-band data and asynchronous I/O notification. The NuTCRACKER Platform does not support the TLI or XTI networking APIs. The native Windows socket implementation has a few differences from standard UNIX networking: Windows networking does not assign individual network names to physical network interfaces. Calling gethostbyname() or gethostbyaddr() does not necessarily return deterministic answers for a multi-homed Windows machine. The standard UNIX mechanism

UNIX to Windows Porting Guide

25

Windows Concepts

of assigning each interface a specific name, and then assigning multiple IP addresses to the official name, does not work the same way under Windows. Winsock 2.0 supports multiple address families beyond TCP/IP (AF_INET). There is support for AppleTalk, IPX/SPX, and other networking protocols. Any address family supported by Winsock 2.0 can be used with the NuTCRACKER Platform. In addition, the NuTCRACKER Platform extends Winsock 2.0 to support UNIX Domain (AF_UNIX) sockets. Even though NuTCRACKER Platform networking is built on Winsock sockets, NuTCRACKER Platform sockets and Win32 sockets are not completely interchangeable. The NuTCRACKER Platform must manipulate the socket state to implement UNIX semantics, such as interruptible operations. Native Win32 code may not be prepared for a socket that has been set up by the NuTCRACKER Platform, and vice-versa. You can pass a socket from the NuTCRACKER Platform to native Win32 code with _NutFdToHandle(), or from native Win32 code to the NuTCRACKER Platform with _NutHandleToFd(). Once the handle passes from NuTCRACKER Platform code to Win32 code, it should no longer be used by NuTCRACKER Platform code, and vice-versa. The networking configuration files, such as hosts or services are similar to those on UNIX, but can be difficult to find. On Windows Me, they live in the Windows installation directory (for example, C:\Windows). On Windows NT/2000/XP/2003, they live in the directory drivers\etc under the Windows system directory (for example, C:\Winnt\System32\drivers\etc). Should you need to refer to this directory programmatically, use the _NutQueryWinNetFileDir() API for maximum portability.

Locales
The NuTCRACKER Platform obtains locale information from Windows, including language, time information, collation sequences, numeric formatting, etc. This information is administered from the Windows Control Panel, using the Date/Time, Keyboard, and Regional Settings applets. Settings from these applets impact functions such as gettimeofday(), strftime(), strcoll(), as well as input and output for applications.

26

MKS Toolkit

Screen Management

Screen Management
The tables in Console Escape Sequences on page 167 list the keyboard escape sequences reported by NuTCRACKER Platform, and the output escape sequences that NuTCRACKER Platform recognizes.

The NuTCRACKER Platform provides an ANSI escape sequence translator for console I/O. This is implemented in a background process that coordinates console access for all NuTCRACKER Platform applications running in a single console window. The NuTCRACKER Platform does not support the SIGWINCH signal, so if the console window size is changed while the application is running, this change is not recognized by the NuTCRACKER Platform application. The NuTCRACKER Platform inherits the code page and font settings that were in effect when the first NuTCRACKER Platform application was invoked in a console window. Changing these settings while a NuTCRACKER Platform application is running can lead to unpredictable display effects. The MKS Toolkit curses library provides cursor movement for terminals and is used for character-oriented NuTCRACKER Platform applications. It is based on terminfo files, and is compatible with the UNIX 98 specification. It supports color and line drawing, as well as additional APIs for menus and forms, compatible with the SVR4 curses libraries.

See the online MKS Toolkit Curses Reference for more detail.

UNIX to Windows Porting Guide

27

Windows Concepts

28

MKS Toolkit

Screen Management

UNIX to Windows Porting Guide

29

Windows Concepts

30

MKS Toolkit

The Porting Process

For details on porting to a 64-bit Windows platform, see Porting Applications to 64-bit Windows on page 135.

32-bit Windows using the NuTCRACKER Platform. Subsequent chapters address specific topics such as porting threaded applications, porting X Windows applications, porting shared libraries, and porting UNIX daemons. Because MKS Toolkit for Professional Developers and MKS Toolkit for Enterprise Developers include the MKS Toolkit UNIX APIs and a UNIX development environment on Windows, it reduces the complexity of a port from UNIX to Windows to the complexity that you are already used to: that of porting from UNIX to UNIX. This chapter discusses porting differences between the NuTCRACKER Platform and other UNIX implementations.

This chapter discusses the process of porting applications from UNIX to

Overview of the Porting Process


This section provides a brief overview of the process of porting UNIX code to Windows with MKS Toolkit for Professional Developers or MKS Toolkit for Enterprise Developers. The remaining sections of this chapter describe each step in the process in detail. The basic porting process includes: Gaining access to the source code on Windows. Examining make files, header files, and source code for porting issues. Compiling and linking. Fixing linkage issues. Debugging. Porting scripts. Integrating with Windows. Distributing the application.

UNIX to Windows Porting Guide

31

The Porting Process

The first step in porting to Windows is to gain access to your source code and utility baselines. You can do this either by accessing your UNIX source repository from Windows, via NFS or Samba, or by transferring your files from UNIX to Windows.
Some ported common utilities can be found in the samples directory on the MKS Toolkit CD and in the MKS Toolkit Resource Kit. For more information, see the MKS Toolkit Resource Kit in the Additional Information chapter of the MKS Toolkit Product Overview & Solutions Guide.

Then you must ensure that you have all the necessary tools on Windows to build your application. If you use utilities to help build your application that are not included with the MKS Toolkit product family member you are using, you must ensure that they are available on Windows or you must port them. At this point, you should try a test compile of your source code, using your UNIX make files in a MKS Toolkit shell or command window, to make sure that your build process works on Windows. The MKS Toolkit includes the POSIX-compatible MKS make utility which works with most UNIX make files. Next, you should start considering the following porting issues: text mode versus binary mode, path differences, potentially non-existent device files, environment differences, and so on.

See Header File Issues on page 37 for more information.

As you compile, in some cases, you may find that MKS Toolkit UNIX API header files are different from the particular header files that you are used to. As a rule of thumb, if you reference a header file that turns up missing during compilation, comment it out and continue compiling. In some cases, you may have to adjust your conditional compilation statements to include or exclude NuTCRACKER from parts of the code.

See Porting Shared Libraries on page 103 and Porting Daemons on page 129 for more information.

After successfully compiling, link your code using your standard UNIX make file. If you are linking a shared library or porting a UNIX daemon, you may have to modify your make files to link appropriately. Linking your application may expose unresolved external references. In some of these cases, you can successfully link by adjusting your compilation or linker flags. If, on the other hand, the reference is to a function that the MKS Toolkit UNIX APIs do not supply, you must replace it with an alternate function from the MKS Toolkit UNIX APIs, a Resource Kit function, a Windows function, a third-party function, or your own function.

See Porting Scripts on page 49 for more information.

If your application includes scripts, be they shell scripts, Perl, or some other scripting language, you may need to modify these scripts in the same fashion as your source code, to deal with platform differences. After having validated your application on Windows, you may want to tune its performance and you may want to integrate it more closely with Windows, for example, by adding Windows-style help or by retrieving setup options from the registry.

32

MKS Toolkit

Preparing to Port

Preparing to Port
Before porting, you need to gain access to your source code on Windows. Then, you need to decide what kind of development environment that you are going to use on Windows and set it up.

Determining the Scope of the Port

In porting your application to Windows, it may be necessary to port more than just your source code. If you use customized utilities or third-party tools to build your application, you must consider these before porting. For those that are not available on Windows, you must port them as well. You may also need to port any shell scripts or other scripts that you use in building your application. You can find some common utilities in the samples directory on the MKS Toolkit CD and in the MKS Toolkit Resource Kit. If you use utilities on UNIX that generate source code or other data, rather than porting these tools to Windows, you could generate the code or data on UNIX and transfer the generated files to Windows.

See Compiling and Linking the Application on page 46 for a detailed discussion.

In addition, you must consider the third-party libraries that your application uses at runtime. You should keep objects compiled with MKS Toolkit UNIX API headers and those compiled with Microsoft header files in separate modules. Also, there are issues with using native Win32 DLLs with the fork() function. This section discusses accessing your source files from Windows and describes the issues you will face. You have two choices when accessing source files: you can copy the files from UNIX, or you can share the files between the two systems.

See Process Control on page 3 for a description of these issues.

Accessing Source Files

Line Termination
One issue common to both methods of file access is line termination. UNIX text files rely on a line-feed character to indicate the end of a line. By contrast, Windows expects both a carriage return and a line-feed to indicate the end of a line.
See the flip reference page for more information.

When you transfer text files to Windows, make sure their lines are properly terminated. Many common transfer utilities have options to automatically handle the termination correctly. In addition, you may find the flip command useful in doing this.

UNIX to Windows Porting Guide

33

The Porting Process

Although line termination causes problems when your files are printed, they do not typically interfere with compilation. However, Visual C++ does not update dependencies properly unless lines end in carriage return and linefeed.

File System Differences


You may also encounter differences between UNIX and Windows file systems. The primary file system type, and the one we strongly recommend, is NTFS. NTFS supports long file names, case preservation of file names, and file security, making it the most compatible with UNIX file systems. File systems under Win32, including NTFS, are case-preserving, not casesensitive as they are on UNIX. This means that you can have files named Makefile and makefile, but you may not have both in the same directory. In porting, this issue arises in two places. First, you cannot have two files that differ only by case in the same directory, as in the make file example. To work around this, rename Makefile and use make f. Second, certain tools depend on the case of file extensions. Under Win32, make cannot distinguish between foo.c (C code) and foo.C (C++ code). The standard solution is to use .c for C source files and .cpp for C++ source files.

Transferring and Sharing Source Files


Windows supports standard UNIX facilities for exchanging files between the two platforms. In addition, MKS Toolkit provides standard UNIX utilities for handling bulk file copies (cpio, pax, and tar). The transfer utilities include rcp and ftp, as discussed in the overview guide. If you transfer text files with either of these utilities using ASCII mode (rather than binary mode), you can avoid problems with line termination. Rather than transferring files between the two systems, most people share files between the two systems. This is especially important if you are maintaining a common source code baseline, a common configuration management system, or both. The two most common means of file sharing are NFS and SMB.

Selecting a Work Environment

Before porting a UNIX application to Windows, you must first decide whether to work in a traditional UNIX command-line environment or in the Visual C++ integrated development environment (IDE). The MKS Toolkit Utilities command-line environment working in a shell or a command window is close to your native UNIX environment and provides the quickest way to start porting your application.

34

MKS Toolkit

Preparing to Port For more information about ncenv and how it sets up the NuTCRACKER Platform development environment, see the ncenv reference page in the online MKS Toolkit Utilities Reference.

When you select a MKS Toolkit shell (for example, KornShell, bash, or C Shell) or Windows command prompt to use for NuTCRACKER Platform development (Start > All Programs > MKS Toolkit > Development), the ncenv script is run to set up the appropriate environment variables for the compiler and X Windows library you selected when installing MKS Toolkit. To use a different compiler or library, either repair the MKS Toolkit installation with the installer or run ncenv again with the appropriate arguments. By contrast, the IDE, which combines an editor, compiler, linker, and debugger under an integrated graphical user interface, provides a tightly integrated set of tools with limited flexibility. Regardless of whether you decide to use the IDE to build your application, you must use its debugger to debug your application.

See the make reference page for more information about those utilities. For information about the imake utility, see Porting X Applications on page 91.

The choice between command-line environment and IDE really boils down to a choice between make utilities: the MKS Toolkit POSIX make utility or the Windows nmake utility. (Certain X Windows applications use the imake utility to generate make files.) Using make lets you: Port as quickly as possible. Preserve your investment in your make files. Often, your make files work without modification. Maintain a common source code baseline between UNIX and Windows. Continue to use shell syntax in your make files. Using nmake means: You must rewrite your make files and then you must debug them. Your make files and potentially your source code directory hierarchy diverge from UNIX. You cannot use shell syntax in your nmake make files. Additionally, if you use the IDE to port, besides the learning curve, you face the following issues: You have to move much of your configuration (compiler options, linker options, etc.) from the make files to the IDE. You have to map your development onto one or more projects, which is time consuming and potentially frustrating.

UNIX to Windows Porting Guide

35

The Porting Process For instructions on using IDE, see Using the Visual C++ IDE on page 85.

You should perform your initial port from the command-line as you have done on UNIX. Then, if you decide to migrate to the IDE, you can do it over time, realizing that you are diverging from your UNIX code base.

Preparing to Build
The MKS Toolkit UNIX APIs are designed to minimize the need for modifying UNIX make files and source code. In fact, we have found that many applications are portable without any source changes at all. Naturally, this depends upon the programming methods used and whether portability was considered during design. This section discusses any modifications that you might need to make to prepare your make files and source code for compilation with the MKS Toolkit UNIX APIs.

Make File Issues

The MKS Toolkit make utility is POSIX-compliant. Your existing UNIX make files should work with little to no effort. When evaluating or changing your make files: You should use the following predefined suffix macros:
Macro $E $O $S $A Meaning Executable File Suffix Object File Suffix Assembler File Suffix Library File Suffix Value .EXE .O .S .LIB

Do not set SHELL, or set it as follows:


SHELL= $ROOTDIR/mksnt/sh.exe

36

MKS Toolkit

Preparing to Build

Header File Issues

This section discusses issues related to the MKS Toolkit UNIX API header files and the compilation environments supported by these header files (selected via compile-time C-preprocessor flags).

compilation environment, and you should never define it. If you were to define this macro on the compile line (for example, by using the -D__STDC__ option), the compilation environment would be restricted to ANSI C , which is probably not what you intended.

Note Do not define __STDC__ at compile time. This macro is defined by the

MKS Toolkit UNIX API Header Files


The header files included with the MKS Toolkit UNIX APIs provide the most portable compilation environment possible. These header files match the exact Application Programming Interface (API) provided by the NuTCRACKER Platform. If a definition exists in a MKS Toolkit UNIX API header, it is supported by the NuTCRACKER Platform. Conversely, if a definition does not exist in a MKS Toolkit UNIX API header, that function, data structure, variable, or other definition is not supported by the NuTCRACKER Platform This structure ensures that you know as quickly as possible if your code uses non-portable or otherwise unsupported features. If compilation fails because of a missing header file, the functions implemented by that header file are not supported. For example, most of the header files in the /include/sys directories of various UNIX platforms are inherently non-portable, because they describe operating system internal capabilities. All sys header files that have been standardized, as well as several others that could be properly and portably reimplemented, are provided with the MKS Toolkit UNIX APIs. In addition, by providing only the set of definitions for supported capabilities, you know at compile time where you might need to change your code to make it more portable. It is likely that the MKS Toolkit UNIX APIs provide the capability you need, but in another header or using another API function, as specified in current standards. The approach to take when you encounter missing header files and/or definitions is as follows: Isolate the non-portable portions of your code. Switch to an alternative implementation, using standard portable definitions.

UNIX to Windows Porting Guide

37

The Porting Process

If there is no single portable solution, use conditional compilation (__NUTC__) to separate the Windows-specific portions of your code from your UNIX-specific code. The MKS Toolkit UNIX APIs provide all standard and portable headers that can be reasonably implemented on Windows. Just because a header or definition exists on multiple implementations of UNIX does not mean that the header or definition is, in fact, portable. For example, several UNIX implementations support the System V File System, and provide a header file <sys/fs/s5_inode.h>.This file describes internal details of the inode on a disk partition formatted with the System V File System. This structure, though portable among several UNIX implementations, is not portable to Windows.

Compilation Environments
The default NuTCRACKER Platform compilation environment provides header files and definitions from many sources: ANSI Standard C (ISO/IEC 9899-1990)

Note Throughout this manual, ANSI C refers to ISO/IEC 9899-1990 also

known as c89. This should not be confused with the 1999 update of ANSI C also known as c99.

POSIX.1 POSIX.2 UNIX 95 UNIX 98 UNIX 03 4.4BSD System V Release 4 (SVR4) and Solaris 2.x OSF/1 and related operating systems MKS Toolkit UNIX APIs extensions By default, the MKS Toolkit UNIX APIs provide all non-conflicting definitions from these various standards and specifications. This is the compilation environment if no compile-time restrictions are defined. When conflicts exist, the definition provided by UNIX 98 is used, or if there is no UNIX 98 definition, the SVR4 definition is used. Examples of conflicting

38

MKS Toolkit

Preparing to Build

interfaces are signal() (which has different semantics in 4.4BSD and UNIX 98) and setpgrp() (which has a different number of parameters in 4.4BSD and UNIX 98). You can use compile-time flags to restrict the compilation environment to definitions from a specific standard. This ensures that your code is compiled using the most portable definitions possible. These flags do not restrict what header files you can include, however. For example, the header file <ndbm.h> is not defined in the ANSI C specification; if you include it in your source, you are including non-portable functionality, but the definitions are available. However, if you include the header file <stdlib.h> while restricting the compilation environment to ANSI C, only the definitions that the ANSI C specification lists for <stdlib.h> are visible. The following table shows the available compilation environments and the compile-time settings for enabling each:
Specification ANSI/ISO 9899-1990 (ANSI C) + ANSI/ISO 9899-1990/AM1-1995 (MSE) Compile-time Settings For the cc command: -Xc For the cl command: /Za For the Visual C++ IDE: Select the Disable Language Extensions option in the Project Settings. -D_POSIX_SOURCE -D_POSIX_C_SOURCE=2 -D_POSIX_C_SOURCE=199506L -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED -D_XOPEN_SOURCE=500 -D_XOPEN_SOURCE=0x600

POSIX.1 (1988) POSIX.2 (1992) (implies POSIX.1 (1988)) POSIX.1 (1996) (implies POSIX.2 (1992)) X/Open Portability Guide 4 (XPG4) UNIX 95 UNIX 98 UNIX 03

UNIX to Windows Porting Guide

39

The Porting Process

In addition to the flags above, you can use the following compile-time flags to enable various non-standardized features. Doing this reduces your level of portability, because it explicitly violates the above standards. The following flags are not needed by default, because they are always enabled unless you explicitly restrict them as shown above.
Feature Set 4.4BSD extensions SVR4 extensions Compile-time Settings -D_BSD_SOURCE -D_SVID_SOURCE -D_NUTC_SOURCE

NuTCRACKER Platform extensions

For example, if you chose to restrict your compilation to POSIX.1 (1996), but wanted to enable NuTCRACKER Platform extensions for portions of your code, you would select the following compilation flags:
-D_POSIX_C_SOURCE=199506L -D_NUTC_SOURCE

In your code, you would then protect the NuTCRACKER-specific extensions by bracketing them as follows:
<POSIX.1 (1996) code> #if defined(__NUTC__) <code using NuTCRACKER extensions> #else <code using only POSIX.1 (1996) interfaces> #endif /* __NUTC__ */ <POSIX.1 (1996) code>

The default compilation environment, when no flags are set, is as if the following flags had been specified:
-D_XOPEN_SOURCE=500 -D_BSD_SOURCE -D_SVID_SOURCE -D_NUTC_SOURCE -D__STDC__=0

Source Code Issues

This section describes several issues that might require a source code change on your part.

40

MKS Toolkit

Preparing to Build

If you make changes to your application source code so that it can run with the NuTCRACKER Platform, you should isolate these changes using #if defined statements in your source files using the __NUTC__ flag, for example:
#if defined(__NUTC__) // new NuTCRACKER code ... #else // old UNIX code ... #endif

The __NUTC__ define has a value that indicates the release number, in case your code depends on a particular NuTCRACKER Platform version. For example, the version of the NuTCRACKER Platform distributed with MKS Toolkit 7.0 products was 4.3, and __NUTC__ had a value of 0x0430.

Text and Binary Modes


For more information, see Text Files and Binary Files on page 20.

By default, NuTCRACKER Platform applications open files in binary mode, except for streams in C++. When you open a stream in C++, it always opens in text mode unless you specify ios::binary when the stream is created. Streams created from standard IO FILE pointers inherit the text/binary mode setting from the standard IO stream.

ANSI Prototypes
The MKS Toolkit UNIX API header files provide ANSI C function prototypes for all functions. If your programs use older style C conventions and you intend to use a strict warning level as a compiler option, you must update your programs to the ANSI conventions.

Global System Variables


Remove all declarations of global system variables (for example, errno and sys_errlist) from your code, and include the appropriate MKS Toolkit UNIX API header files. The man pages for each variable indicate the correct header file.

Conditional Compilation
Beware of code that does the following:
#if defined(SYSV) || defined(SVR4) #define NEED_UTSNAME #include <sys/utsname.h> #endif

UNIX to Windows Porting Guide

41

The Porting Process

Here, the code implicitly assumes that if SYSV or SVR4 is not defined, it is working in a BSD environment. This is inappropriate for the NuTCRACKER Platform, so you should modify code as follows:
#if defined(SYSV) || defined(SVR4) || defined(__NUTC__) #define NEED_UTSNAME #include <sys/utsname.h> #endif

A good approach is to grep for SVR4, SYSV, BSD, etc., in your source code and review all of these cases to ensure everything is correct.

Using Data Exported From DLLs


For more information, see Data Exported From DLLs on page 25.

As discussed earlier, the Visual C++ compiler does not allow global variables in C source files to be initialized from data exported from DLLs. You must do one of the following to allow your C sources to compile and run properly (there is no issue for C++ sources): Convert your C sources to C++ sources. Change your static initialization to runtime initialization, by calling functions to explicitly initialize the data when your application starts up. Use a set of macros provided by the MKS Toolkit UNIX APIs to convert your data declarations so that they initialize at runtime without your needing to implement initialization functions. To implement the last option, the MKS Toolkit UNIX APIs provide a header file <nutdlldat.h>, which you can use as follows. Using the following code fragment as an example:
#include <stdio.h> FILE *myfp = stdin;

42

MKS Toolkit

Preparing to Build

you would change this code to the following:


#include <stdio.h> #if !defined(__NUTC__) #include<nutdlldat.h> FILE *myfp = stdin; #else /* __NUTC__ */ /* } { */ /* { */

FILE *myfp; #pragma NUT_DLL_DATA_BEGIN NUT_DLL_DATA_INIT(myfp, stdin); #pragma NUT_DLL_DATA_END #endif /* __NUTC__ */ /* } */

This causes the Visual C++ compiler to generate code that initializes your data at runtime, prior to any user code running.

Path Names
See Path Names on page 18 for more information.

Be careful when parsing path names. the NuTCRACKER Platform recognizes either UNIX-style or Windows-style path names. You may need to modify your code to recognize Windows-style path names, and you should be careful not to pass UNIX-style path names to any Win32 functions you might call. The MKS Toolkit UNIX APIs include a suite of functions (_NutPathToXXX()) for converting path names to a single format before using them.

Device Files
See Special Files on page 22 for more information.

The NuTCRACKER Platform supports several UNIX devices, but not all.

Globbing
You can select whether the NuTCRACKER Platform performs Win32-style or UNIX-style command-line expression interpretation. For example, in Win32 style expansion, *.* matches all files. In UNIX, the same expression matches a different pattern (any pattern followed by a dot (.), then any pattern). By default, there is no globbing. To use globbing, link with:
wildcard.obj for Win32-style wildcards. no_case.obj for case-insensitive UNIX-style globbing. globbing.obj for UNIX-style globbing.

UNIX to Windows Porting Guide

43

The Porting Process

Byte Ordering
Various processors and operating systems store bytes in memory in differing orders. The two most common orderings are big-endian and little-endian. In big-endian ordering, the most significant byte of a word is stored first. In little-endian ordering, the least significant byte is stored first. For example, on a big-endian operating system, if you assign 0x01020304 to a word, the first byte of the word is 0x01. On a little-endian operating system, it is 0x04.0 Handling different byte orders is a significant portability challenge. The byte order for a given machine is determined by the combination of the operating system and the processor. Windows implementations are little-endian, as are Intel-based UNIX implementations. Most RISC-based UNIX implementations (for example, Solaris/SPARC and HP/UX) are big-endian. Whenever you transfer binary data between systems with different byte orders, whether in a data file or via some live connection, your software must account for the differences in byte ordering. There are many potential solutions. For manipulating 16- and 32-bit quantities, you can use the standard network/host conversion routines ntohs(), ntohl(), htons(), and htonl(). For manipulating structures, the MKS Toolkit Resource Kit contains a port of ONC RPC, including XDR. You can use the XDR functions to encode and decode structures for transfer between machines.

Calling Back Into NuTCRACKER Code From Win32 Code

When integrating NuTCRACKER Platform code with Win32 code, you may need to make changes to your source code in cases where Win32 API functions call back into your code. When a call can be made to NuTCRACKER Platform code from a thread that was not created by the NuTCRACKER Platform, you must protect this code with NuTCRACKER Platform initialization functions, as discussed in more detail below. Some situations in which you must protect callback functions include: Your application calls a Win32 API function such as timeSetEvent(), passing it a MKS Toolkit UNIX API function as its callback. This function creates a Win32 thread and periodically calls the specified callback function when a timer expires.

For more details, see Building Standalone DLLs on page 109. See Evolving Applications with COM on page 171 for more information.

Your application has one or more DLLs that may be called by nonNuTCRACKER Platform applications. Your application is an RPC server for Win32 applications. For example, you build your application as a local COM server. Your application provides callback functions to a third-party Win32 library that may do any of the above.

44

MKS Toolkit

Preparing to Build

In each instance, Win32 code may create one or more threads that call back into your code. Because the NuTCRACKER Platform did not create the threads, special precautions must be taken to initialize NuTCRACKER Platform data structures for that thread. Each callback function must call _NutEnableNuTC() as its first executable call, and call _NutDisableNuTC() before it leaves. The prototypes for these functions are:
#include <winnutc.h> void _NutEnableNuTC(sigset_t *sigmask); void _NutDisableNuTC(void);

These are actually implemented as C-preprocessor macros that cause your code to fail to compile if you do not correctly match the calls. This ensures that your function cannot exit without undoing what was done on entry. When you insert these calls directly in your code, you must ensure that the call to _NutEnableNuTC() occurs before any initialization of local variables. Using the following simple function as an example:
int myfunc1(int a, int b) { int rtn = 0; if (do_some_stuff(a, b) != 0) { rtn = -1; } return rtn; }

You would modify this function as follows:


int myfunc1(int a, int b) { int rtn; _NutEnableNuTC(NULL); rtn = 0; if (do_some_stuff(a, b) != 0) { rtn = -1; } _NutDisableNuTC(); return rtn; }

You can use setjmp()/longjmp() within the context of a _NutEnableNuTC()/_NutDisableNuTC() block, but you must not longjmp() into or out of such a block.

UNIX to Windows Porting Guide

45

The Porting Process See Porting Shared Libraries on page 103 for more information.

You can find examples of using _NutEnableNuTC() and _NutDisableNuTC() in the standalone DLL tutorial sample provided with MKS Toolkit for Professional Developers and MKS Toolkit for Enterprise Developers.

Compiling and Linking the Application


For language support issues concerning C, C++, or FORTRAN, see Language Support on page 81. For more information about selecting a target platform (for example, Windows Me) at compile time, see Porting to Windows Me on page 51.

MKS Toolkit provides cc, cxx, and ld wrappers for the cl compiler from Visual C++ (version 5.0 or later) and the Windows link linker as well as for the GCC compiler and related linker provided on the MKS Toolkit Resource Kit CD. In addition, MKS Toolkit provides ncf77 and ncf90 FORTRAN 77 and 90 compiler drivers for the Absoft FORTRAN Compiler. There are very few issues with respect to compiling and linking with the MKS Toolkit UNIX APIs. Nevertheless, keep in mind the following: You should never link with any of the Microsoft C or C++ libraries or C or C++ runtime libraries (for example, MSVCRT.LIB, LIBC.LIB, or LIBCMT.LIB).

See Choosing the Appropriate Subsystem on page 92.

The ld command sets the default subsystem to console. To link a graphical application, use ld -W/subsystem:windows. Never link NuTCRACKER Platform sockets and Winsock sockets code in the same executable or DLL. Never link code compiled against MKS Toolkit UNIX API C library headers and Microsoft C library headers in the same executable or DLL.

See Porting Shared Libraries on page 103 for more information.

The best approach to avoid mixing files compiled with MKS Toolkit UNIX API header files with those compiled with Microsoft header files is to build the object files compiled with Microsoft headers into a separate DLL, and use that DLL in your application. With this approach, any inconsistencies between the MKS Toolkit UNIX API definitions and the Microsoft definitions are physically separated and hence one cannot impact the other. Rarely, while building your application, you may discover that you are using a function that the MKS Toolkit UNIX APIs do not provide. Some of your alternatives are: Use an alternate function that the MKS Toolkit UNIX APIs do provide. For example, if you are using a BSD function, try its POSIX or UNIX 98 equivalent. Port a public domain version of the function. In some cases, you may find ported versions of functions in the MKS Toolkit Resource Kit. Re-implement the function using Win32.

46

MKS Toolkit

Debugging the Application

Debugging the Application


This section discusses several topics of interest when debugging NuTCRACKER Platform applications:
For a complete description of the mapping of Win32 error codes to UNIX errno, see the Introduction to the online MKS Toolkit UNIX APIs Reference. For information on debugging 64-bit applications, see Porting Applications to 64-bit Windows on page 135.

When the NuTCRACKER Platform can map a Windows error code directly to an appropriate UNIX errno, it does so. When it cannot, it sets errno to the negative of the Windows error code. Both strerror() and perror() work in either case. To use the Visual C++ debugger, msdev, on a NuTCRACKER Platform application, you do not need to build a VC++ project. Simply run cc -g and ld -g and then invoke VC++ by typing msdev executable-name or msdev -p pid at a MKS Toolkit command or shell prompt to launch the debugger. The windbg debugger (shipped with the Win32 SDK) is the only Microsoft debugger that can trace across process creation. The GCC compiler requires the use of the GDB debugger. This debugger is supplied with GCC on the MKS Toolkit Resource Kit CD and is described in the GCC Release Notes also included on that CD. By default, msdev stops only for unhandled exceptions. The NuTCRACKER Platform handles all exceptions in its signal handling logic. If you want the debugger to stop on an exception, such as an access violation, you must select Exceptions from the Debug menu, and choose Stop Always for each exception you want the debugger to catch. These settings are per-project, so you must do this for each program. The process command reports information about active NuTCRACKER Platform processes, including information about open files, signals, fast local transports, security, sockets, and threads. The truss command traces system calls of NuTCRACKER Platform processes, just like its UNIX counterpart. To verify that you have a consistent set of NuTCRACKER Platform DLLs, and not some DLLs from one release and some from another, use the Information tab in the MKS Toolkit control panel applet. Use the _NutDebugBreak() function to display a dialog that lets you attach a debugger to a running process. This is especially useful for debugging services (that is, ported UNIX daemons) and for debugging on Windows Me where msdev cannot attach to a running process.

UNIX to Windows Porting Guide

47

The Porting Process

On Windows Me, where you cannot use msdev to attach to a running process, you can use a third-party debugger such as SoftICE. If the problem reproduces on Windows NT, you may be more successful debugging it on that platform. You can also set NUT_DEFAULT_WIN32_FAULT in the environment for special signal handling. If no signal handler is installed and this variable is set, instead of performing the default UNIX action, the NuTCRACKER Platform performs the default Windows action, which is generally to display a dialog that lets you attach a debugger. To determine the set of DLLs linked into an application, use the command link dump imports program-name, or use the depends command from the Win32 SDK or VC++ 6.0 distribution. If you suspect heap corruption in your application, set NUT_VALIDATE_HEAPS in your environment to cause the NuTCRACKER Platform to validate the heap on every malloc() or free(). NuTCRACKER Platform applications generally do not cause problems for third-party debugging or memory analysis tools, such as Purify, except that they may not be able to follow execution across a fork(). In addition, there are many performance analysis tools that work well with NuTCRACKER Platform applications, including the Call Attributed Profiler (CAP), Win32 API Profiler (WAP), and API Monitor (APIMON) from the Win32 SDK. We have also successfully used VTune from Intel and Quantify from Rational.

Porting Scripts
To support your scripting needs, MKS Toolkit includes MKS KornShell and MKS C Shells, Perl, Tcl, awk, and sed. Additionally, pdksh is available as a sample in the samples directory on the MKS Toolkit CD. This section discusses several issues to keep in mind when porting script-based portions of your application:
See File Management on page 16 for more information.

Issues with the differences in path names between Windows and UNIX tend to be common in scripting application. Some issues you might need to address in your scripts include: n n n The existence of drive letters on Windows. Case-preserving rather than case-insensitive path names. Spaces in path names.

48

MKS Toolkit

Integrating with Windows

n n
See Text Files and Binary Files on page 20 for more information.

Different directory separator characters. Different path-element separators.

Scripts that parse characters in textual input may need to be modified to handle the carriage-return/line-feed line termination used in Windows text files. Scripts that make assumptions about file system layout must be updated. For example, scripts that assume that temporary files can be created in / tmp or /var/tmp need updating for portability.

See Packaging and Deploying the Application on page 51 for more information.

When packaging and distributing your application, you must ensure that you have licensed and are distributing the appropriate tools along with your application. You can find some examples of scripting solutions in the MKS Toolkit Resource Kit.

Integrating with Windows


Windows provides features unavailable on UNIX that you can use to make your application look and feel more like a native Windows application. You can integrate a NuTCRACKER Platform application with other Windows applications by using the Windows Clipboard, DDE, named pipes, shared memory, and semaphores. In fact, most Win32 devices (printers, named pipes, console, etc.) look like files to ported UNIX applications. You can also take advantage of the Win32 API, including:
See Evolving Applications with COM on page 171 for more information about COM, OLE, and ActiveX.

COM and ActiveX. Windows Help (WinHelp). Messaging API (MAPI). Open Database Connectivity (ODBC). Windows Registry. Winsock 2 address families (protocols other than TCP/IP). When integrating further with Windows, you should keep the following in mind:

For additional information on using and configuring nmake, see the Microsoft Win32 Software Development Kit Tools Users Guide.

Many applications using Windows technologies are best developed using the Microsoft IDE. This means that you will be using nmake to build the Windows-specific components. If you are using MKS Toolkit make to build your application, integrating these incompatible make facilities takes careful planning.

UNIX to Windows Porting Guide

49

The Porting Process

When combining UNIX code and Windows code, it is best to separate the code into distinct DLLs or executables. This helps avoid header file, symbol, and data conflicts between Windows and the NuTCRACKER Platform.

Packaging and Deploying the Application


For more information about distributing your NuTCRACKER Platform applications, see Deploying NuTCRACKER Platform Applications on page 147.

NuTCRACKER makes it easy to package applications for your end user. To redistribute your NuTCRACKER Platform application, use the NuTCRACKER Deployment Wizard to build a package for installation on target machines. To preview this wizard, select it from the Start menu.

Porting to Windows Me
See Windows Concepts on page 3 for more information about concepts that are common to the two operating systems.

MKS Toolkit for Professional Developers and MKS Toolkit for Enterprise Developers provide a development environment for porting UNIX applications to run on Windows NT/2000/XP/2003, Windows Me, or both. This section addresses building applications for Windows Me and summarizes the differences between Windows NT/2000/XP/2003 and Windows Me. Your application may need to take differences between the various platforms into account. While you could build separate executables, using conditional compilation, we do not recommend this solution. Instead, you should have your application determine the platform at runtime and take appropriate actions. To account for functions that are not implemented on Windows Me (such as security-related APIs) we recommend that you detect the operating system version at run-time using sysconf(). The following code fragment illustrates its intended use:

Strategies for Maintaining a Single Executable

50

MKS Toolkit

Porting to Windows Me

#include <unistd.h> nutc_plat = sysconf(_SC_NUTC_OS_PLATFORM); if (nutc_plat == __NUTC_PLAT_UNKNOWN) // problem if ((nutc_plat & __NUTC_PLAT_WINNT) != 0) // Windows NT, Windows 2000, Windows XP or greater else if ((nutc_plat & __NUTC_PLAT_WIN9x) != 0) // Windows 95, Windows 98, or Windows Me if (nutc_plat == __NUTC_PLAT_WINNT40) // Windows NT 4.x else if (nutc_plat == __NUTC_PLAT_WIN2000) // Windows 2000 else if (nutc_plat == __NUTC_PLAT_WINXP) // Windows XP and above else if (nutc_plat == __NUTC_PLAT_WIN95) // Windows 95 else if (nutc_plat == __NUTC_PLAT_WIN98) // Windows 98 else if (nutc_plat == __NUTC_PLAT_WINME) // Windows ME

Differences Between Windows Versions


See Porting Daemons on page 129 for more information.

This section summarizes the major differences between Windows NT/2000/ XP/2003 and Windows Me. See Windows Concepts on page 3 for a highlevel discussion of the differences, and API-Specific Porting Issues on page 55 and the online MKS Toolkit UNIX APIs Reference for details concerning individual APIs.

Daemons/Services
Unlike Windows NT/2000/XP/2003, Windows Me has no Service Control Manager (SCM). The process of porting UNIX daemons to Windows Me is significantly different from porting them to Windows NT/2000/XP/2003.

Security
See Security on page 8 for more information.

Windows Me has no security; therefore it does not support traditional users or groups. For ease-of-porting, the NuTCRACKER Platform implements pseudo-users and two pseudo-groups. For each user who logs into a Windows Me machine, the NuTCRACKER Platform assigns a user ID (uid) that is guaranteed to be unique only on that machine; it is not unique across different machines. In addition, on Windows Me, APIs using file and directory security typically ignore the security information.

UNIX to Windows Porting Guide

51

The Porting Process

Event Logging
On Windows NT/2000/XP/2003, NuTCRACKER Platform error, warning, and information messages are written to the Application Log that you can examine with the Event Viewer. Windows Me does not have either an event log or an event viewer. Consequently, on Windows Me, NuTCRACKER Platform messages are written to the file:
%ROOTDIR%\logs\NuTCEventLog.txt

On Windows NT/2000/XP/2003, when you call syslog() to log a message from an application, the NuTCRACKER Platform writes the message to the Application Log that you can examine with the Event Viewer. On Windows Me, the NuTCRACKER Platform writes messages to text files with an extension of .log.txt and places them in the %ROOTDIR%\logs directory.

Process IDs
On Windows NT/2000/XP/2003, the process ID that the NuTCRACKER Platform returns (from exec(), for example) is the Win32 process ID. On Windows Me, however, process IDs are negative and this causes many problems for UNIX code, which expects a negative number to indicate an error condition. Therefore, on Windows Me, the NuTCRACKER Platform masks the most significant bit of the process ID before returning it to your program.

52

MKS Toolkit

Porting to Windows Me

UNIX to Windows Porting Guide

53

The Porting Process

54

MKS Toolkit

API-Specific Porting Issues


See Windows Concepts on page 3 for discussion of these porting issues.

This chapter provides an overview of the MKS Toolkit UNIX API


functions which have issues that may impact your port. The MKS Toolkit UNIX APIs include several NuTCRACKER Platform extensions to the standard UNIX APIs. Each begins with the _Nut prefix. Some of these are discussed in this chapter. The man pages have details on each of the functions listed here, including the NuTCRACKER Platform extensions.

Process Management
For additional information, see Process Management on page 3.

This section discusses API functions related to process control, process identification, memory management, and signal management.

Process Control

atexit()
Each DLL has its own list of atexit() handlers. These handlers are run when the DLL is unloaded, whether dynamically (via dlclose()) or at process exit. This ensures that DLLs clean up properly when they are dynamically loaded and unloaded.

clock()
This function is not supported on Windows Me, because the operating system does not provide the CPU usage for a process.

exec() Family
In Win32, program files usually end with a .exe extension. Code ported from UNIX calls the exec() functions without specifying a file extension. Unless the program has no extension, the extension-less program name is not found. You should specify the appropriate file extension when calling the

UNIX to Windows Porting Guide

55

API-Specific Porting Issues

exec() functions. Alternatively, you can use the _NutConf() function to have NuTCRACKER Platform attempt to find a file with a .exe extension if the attempt to exec() the extensionless file fails.

Windows NT/2000/XP/2003 lets you execute an extensionless program file (for example, if you rename foo.exe to foo). Windows Me does not execute the program; the error code indicates that a necessary DLL cannot be found. The NuTCRACKER Platform recognizes the #! magic sequence at the start of an executable file. You must ensure that the path specified is validyou should not assume that /bin/sh,/usr/local/bin/perl, and so on., exist.
See Path Names on page 18 for more information.

You must ensure that any path names passed to non-NuTCRACKER Platform applications are in Win32 format, as only NuTCRACKER Platform applications recognize the NuTCRACKER Platform format. Calling one of the exec() functions from a standalone NuTCRACKER Platform DLL fails with errno set to ETXTBSY, unless the exec() call is in the child of a vfork() call. The _NutForkExec() functions may provide additional alternatives.

See Building Standalone DLLs on page 109 for more information.

_exit()/exit()
The application exit code is converted to a Win32 code for compatibility with Win32 applications. In a NuTCRACKER Platform application, the wait() and waitpid() functions convert the exit code to the appropriate format. This ensures that when a NuTCRACKER Platform application is invoked by a Win32 application, it receives an exit status that it can interpret.

fork()
See Process Control on page 3 for more details. See Building Standalone DLLs on page 109 for more information.

The NuTCRACKER Platform implements a full UNIX fork(), replicating the address space of the process. Calling fork() in a standalone NuTCRACKER Platform DLL fails with errno set to EAGAIN. On Windows Me, you can only call fork() from the main thread. You may not call fork() from any thread subsequently created.

getitimer()/setitimer()
The NuTCRACKER Platform only supports the ITIMER_REAL timer. ITIMER_VIRTUAL and ITIMER_PROF are not supported.

56

MKS Toolkit

Process Management

longjmp()/siglongjmp()
On Windows Me, you must not use longjmp() to leave a signal handler for an asynchronous signal (one generated outside the running thread, such as SIGINT). You may use longjmp() to leave a signal handler for a synchronous signal (one generated in the running thread, such as SIGSEGV). This is a restriction imposed by the operating system.
See Calling Back Into NuTCRACKER Code From Win32 Code on page 44 for details.

Windows NT/2000/XP/2003 has no such restriction. You may not use longjmp() to jump into or out of a block, such as a callback function, that is protected by calls to _NutEnableNuTC() and _NutDisableNuTC().

_NutForkExecXXX() Family
This is discussed in more detail under Process Control on page 3.

The _NutForkExec() functions parallel the exec() family of functions, and provide the most efficient mechanism for spawning a new process, by combining a normal fork() and exec() into a single operation. Use these functions in preference to fork() and exec() when you do not need to change to process state in the child before calling exec(). Handlers registered with pthread_atfork() are not executed when a _NutForkExec() function is called. Because there is no actual fork() operation, there is no chance of deadlock in the child prior to the exec() operation.

See Path Names on page 18 for more information.

You must ensure that any path name passed to non-NuTCRACKER Platform applications are in Win32 format, as only NuTCRACKER Platform applications recognize the NuTCRACKER Platform format.

popen()
There is no hard-coded path to the command interpreter. popen() first looks for a shell in the SHELL environment variable. If this is not defined, then the Windows command interpreter specified by COMSPEC is used.
See Path Names on page 18 for more information.

You must ensure all path names passed to non-NuTCRACKER Platform applications are in Win32 format, as only NuTCRACKER Platform applications recognize the NuTCRACKER Platform format.

pthread_atfork()
Handlers registered in a DLL with pthread_atfork() are removed when the DLL is unloaded. This ensures that any handlers registered by a dynamically-loaded DLL are not invoked if fork() is called after the DLL is unloaded. Handlers registered with pthread_atfork() are not invoked when you call one of the _NutForkExec() functions or vfork().

UNIX to Windows Porting Guide

57

API-Specific Porting Issues

sleep()/nap()/usleep()/nanosleep()
These functions do not interfere with SIGALRM. They are implemented using an interruptible wait function, so they do not reset an alarm timeout established with alarm() or setitimer().

system()
See Path Names on page 18 for more information.

There is no hard-coded path to the command interpreter. system() first looks for a shell in the SHELL environment variable. If this is not defined, then the Windows command interpreter specified by COMSPEC is used. You must ensure that any path name passed to non-NuTCRACKER Platform applications are in Win32 format, as only NuTCRACKER Platform applications recognize the NuTCRACKER Platform format.

times()
This function is not supported on Windows Me, because the operating system does not provide a mechanism to obtain the CPU usage for a process.

vfork()
See Process Control on page 3 for more details.

You must include either <unistd.h> or <vfork.h> in any source file that calls vfork(). Handlers registered with pthread_atfork() are not executed when vfork() is called.

waitpid()/wait3()/wait4()
waitpid(), wait3(), and wait4() transform Win32 exit codes into valid UNIX exit codes, so you can wait for a non-NuTCRACKER Platform application just as you would a NuTCRACKER Platform application.

For wait3() and wait4(), the CPU usage time returned is only that of the child and does not include the time spent by the grandchild.
For more information on process IDs, see Process Identification on page 59.

The process ID passed to wait4() should be one returned by a function in the MKS Toolkit UNIX APIs. On Windows Me, the NuTCRACKER Platform process ID is not as the Windows process ID.
WNOHANG is the only supported option for waitpid(). WUNTRACED, WNOWAIT and WCONTINUED are not currently supported. Waiting for process groups (that is, calling waitpid() with a first parameter of 0 or less than -1)

is not supported.

58

MKS Toolkit

Process Management

Process And Thread Scheduling

getpriority()/setpriority()
The getpriority() and setpriority() functions are implemented in terms of the Win32 thread-priority functions, and apply to all NuTCRACKER Platform threads in the process. No interfaces are provided for altering the priority class of a NuTCRACKER Platform process. Windows supports many fewer priority levels for a thread than are supported on most UNIX platforms. The setpriority() manual page defines the specific mapping between UNIX-style priority numbers and Windows priorities. Because of this difference in granularity, priority changes on Windows can have dramatic effects compared to the corresponding change on most UNIX platforms. The NuTCRACKER Platform only supports getting and setting the priority of the current process.

nice()
The NuTCRACKER Platform implements nice() in terms of setpriority(), with the same restrictions.

pthread_attr_setpolicy()/pthread_setschedparam()
The NuTCRACKER Platform only supports the SCHED_OTHER scheduling policy.

Process Identification

getpgid()/getpgrp()/getsid()
getpgid() and getsid() can only obtain the process group ID of a

NuTCRACKER Platform process or of a Win32 process invoked by a NuTCRACKER Platform process. Otherwise, they return -1, with errno set to ESRCH, even if the process ID specifies a running Win32 process. On Windows NT/2000/XP/2003, the returned process group ID is the Win32 process ID of the process group leader. On Windows Me, the returned process group ID is the Win32 process ID with the high-order bit stripped off.

For more information about process IDs, see Process Identification on page 6.

getpid()
For more information about process IDs, see Process Identification on page 6.

On Windows NT/2000/XP/2003, the returned process ID is the Win32 process ID. On Windows Me, the returned process ID is the Win32 process ID with the high-order bit stripped off.

UNIX to Windows Porting Guide

59

API-Specific Porting Issues

getppid()
For a NuTCRACKER Platform process that is the grandchild of another NuTCRACKER Platform process (that is, there is at least one nonNuTCRACKER Platform process in the process tree between the two NuTCRACKER Platform processes), the parent process ID is the process ID of the first intervening non-NuTCRACKER Platform process. NuTCRACKER Platform cannot track the intervening non-NuTCRACKER Platform processes.
See Process Identification on page 6 for more information about process IDs.

On Windows NT/2000/XP/2003, the returned process ID is the Win32 process ID. On Windows Me, the returned process ID is the Win32 process ID with the high-order bit stripped off.

_NutIsNuTCProcess()
This function queries whether a given process ID refers to a NuTCRACKER Platform application.

_NutQueryPid()
See Process Control on page 3 for more information.

This function returns the process ID of the process which exec()ed the calling process. This may be different from the process ID returned by getpid(), because of the way exec() is implemented. On Windows NT/2000/XP/2003, the returned process ID is the Win32 process ID. On Windows Me, the returned process ID is the Win32 process ID with the high-order bit stripped off.

For more information about process IDs, see Process Identification on page 6.

pthread_self()
See Signal Management on page 7 for more information.

This function returns the ID of the underlying Win32 thread created by pthread_create(). This is usually the ID of the thread running the pthread_self() call. If NuTCRACKER Platform is running a signal handler in an alternate thread, pthread_self() returns the thread ID of the created thread, rather than that of the underlying Win32 thread. This hides the fact that the signal handler may be running in an alternate thread.

setpgrp()/setsid()
In Win32, detaching from the controlling terminal means the following: If there are no other processes using the console window (for example, an invoking shell, or a previously-invoked child), the console window is closed. Any children created after the call to setpgrp()/setsid() are created without a console window attached.

60

MKS Toolkit

Process Management See Process Identification on page 6 for more information about process IDs.

On Windows NT/2000/XP/2003, the process group ID is the Win32 process ID of the process group leader. On Windows Me, the process group ID is the Win32 process ID with the high-order bit stripped off.

Memory Management

brk()/sbrk()
These functions cannot be implemented on Windows. See Memory Management on page 6 for more information.

malloc()
See Memory Management on page 6 for more information.

Memory is allocated from the NuTCRACKER Platform application heap. This is not the same heap that native Win32 code uses. If you are using native Win32 DLLs with your application, you should not attempt to free memory allocated in those DLLs, nor should you let the DLL free memory allocated in your code.

mmap()
Windows does not allow overlapping memory ranges to be created with mmap(). Attempts to map with MAP_FIXED at an address already in use in the process address space fail. In addition, Windows interprets the address 0 as a request for the system to pick a mapping address. Hence mapping with MAP_FIXED at address 0 is not possible. Windows requires that the size of attached memory mapped regions and the offset passed to mmap() be a multiple of allocation granularity as returned by sysconf(_SC_NUTC_OS_ALLOCGRANULARITY). If you use the MAP_FIXED flag and/or specify offset to be something other than 0, you must ensure that this address and/or offset is a multiple of allocation granularity as returned by sysconf(). The PROT_WRITE flag is implemented as PROT_READ|PROT_WRITE and the PROT_EXEC flag is implemented as PROT_READ|PROT_EXEC. On Windows Me, the PROT_EXEC flag is not supported, nor is PROT_NONE in combination with MAP_SHARED. The mapped file should be kept open as long as the mapping exists, to prevent nonsharing processes from reading and writing to the file, so that coherence can be maintained. Windows does not maintain coherence for networked files. On Windows Me, mmap() for regular files may fail if the system can not find a region large enough to map the entire file, irrespective of the size of the map requested. Also, multiple mmap() calls for the same file using MAP_SHARED all return the same address, as long as the region remains mapped in any process.

UNIX to Windows Porting Guide

61

API-Specific Porting Issues

mprotect()
Windows Me does not support the PROT_EXEC flag, nor does it support mprotect() on regions created with the MAP_SHARED flag.

msync()
Windows does not distinguish the flags MS_SYNC and MS_ASYNC. The flag MS_INVALIDATE is ignored by the system.

munmap()
Partial unmapping of the mapped regions is not supported. The length and address specified must completely match one or more continuous memorymapped regions.

Signal Management

bsd_signal()
This UNIX 98 extension function implements signal() with 4.4BSD semantics.

kill()
If you call kill() with a process ID that refers to a non-NuTCRACKER Platform process, the following occurs: If the specified signal is SIGKILL, NuTCRACKER Platform first sends a close message to the process main window. If the process does not shut down, NuTCRACKER Platform tries to kill it with the Win32 function TerminateProcess(). If the specified signal is SIGHUP or SIGTERM, NuTCRACKER Platform sends a close message to the process main window. There is no guarantee that this causes the process to shut down. If any other signal is specified, kill() returns -1, and sets errno to EPERM. On Windows NT/2000/XP/2003, kill() can fail with EPERM, based on user security for the users running the processes. On Windows Me, because there is no user security, EPERM is only returned when attempting to kill a Win32 process as described above.

sigaction()
The flag values SA_NOCLDSTOP, SA_NOCLDWAIT and SA_ONSTACK are ignored by the NuTCRACKER Platform. The values are retained, so if the passed-in sigaction structure is returned by a later call to sigaction(), these flags are still present. If the SA_SIGINFO flag is passed, the signal

62

MKS Toolkit

Process Management

handler is invoked with a siginfo_t structure as documented on the siginfo_t manual page in the man pages. The context parameter is filled in for synchronous signals, but may be NULL for asynchronous signals.

sigaltstack()/sigstack()
The Windows exception handling mechanism on which the NuTCRACKER Platform signal handling is based does not support running handlers on an alternate stack. Hence, these functions are not supported by the NuTCRACKER Platform.

sigqueue()
The determination of whether the sending process has permission to send a signal to the receiving process ignores any uid or gid settings that have been specified with calls to setuid() or setgid().The determination is done by comparing the uids of each of the two processes at the time that they were created. Using sigqueue() to send the SIGTERM or SIGHUP signal to a nonNuTCRACKER Platform attempts to post a close message to a window owned by the process specified by pid. If the process calling sigqueue() does not have sufficient privileges to perform this function, or if no window could be found to which to post the close message, kill() returns -1 with errno set to EPERM. Sending the SIGKILL signal to non-NuTCRACKER Platform processes also attempts to post a close message to a window owned by the process specified by pid. In cases where it is not possible to post this message, or where the process does not exit in a timely fashion, sigqueue() attempts to use the Win32 TerminateProcess() function to kill the process specified by pid.If the process calling sigqueue() does not have sufficient privileges to perform this function, sigqueue() returns -1 with errno set to EPERM. Sending any other signal to a non-NuTCRACKER Platform process fails with errno set to EPERM.

sigvec()
The SV_ONSTACK flag is not supported.

UNIX to Windows Porting Guide

63

API-Specific Porting Issues

Security
For additional information, see Security on page 8.

This section discusses the API functions related to user, group, and file security.

Users and Groups


See Users and Groups on page 12 for more information.

getgroups()
This function is not supported on Windows Me.

getpwnam()/getpwuid()/getgrnam()/getgrgid()
On Windows NT/2000/XP/2003, the passwd and group structures are filled with information from the SAM database. On Windows Me, these structures are filled with the NuTCRACKER Platform user and group information, because the operating system maintains no such data. The following fields from the passwd structure are filled in: pw_name, pw_uid, pw_gid, pw_gecos, pw_dir, pw_shell, and pw_expire. The following fields from the group structure are filled in: gr_name, gr_gid, and gr_mem. Windows NT/2000/XP/2003 only allows administrators and members of a group to enumerate the members of a group, so the gr_mem list is empty if a nonadministrator calls getgrnam()/getgrgid() for a group in which the user is not a member.

getuid()/getgid()/geteuid()/getegid()
See Users and Groups on page 12 for more information.

On Windows NT/2000/XP/2003, the user and group IDs are obtained from the SIDs associated with the process. On Windows Me, the NuTCRACKER Platform provides pseudo-IDs, because the operating system does not implement user security.

_NutValidatePassword()
On Windows NT/2000/XP/2003, use the _NutValidatePassword() rather than getpwnam() and crypt() to validate passwords. The user calling _NutValidatePassword() must have the Act as part of the operating system and Replace a process-level token user rights assigned (this is the default for members of the Administrators group). On Windows Me, there is no password database, so this function is not supported.

setuid()/setgid()/seteuid()/setegid()
On Windows NT/2000/XP/2003, an arbitrary process cannot assume a different user identity without an account name/password challenge or appropriate client-server connection. Therefore, the full semantics of UNIX setuid()/setgid() cannot be implemented. The NuTCRACKER 64

MKS Toolkit

Security

Platform emulates these facilities by temporarily manipulating the DACLs of the objects created and accessed by the process. Only the Administrator and System accounts (which are mapped to user ID 0) can execute these functions.
See Impersonation on page 11 and Users and Groups on page 12 for more information.

On Windows Me, the NuTCRACKER Platform provides pseudo-IDs, because the operating system does not implement user security.

File Security

File Mode Flags


In addition to the standard access mode bits, the NuTCRACKER Platform adds the following flags, which can be passed to functions such as chmod() and umask(), and are returned in the structure returned from stat():
Flag S_IDUSR S_IPUSR S_IOUSR S_IDGRP S_IPGRP S_IOGRP S_IDOTH S_IPOTH S_IOOTH Meaning Delete permission for owner Change Permission permission for owner Take Ownership permission for owner Delete permission for group Change Permission permission for group Take Ownership permission for group Delete permission for other Change Permission permission for other Take Ownership permission for other

The NuTCRACKER Platform stat structure has an st_attr field that specifies the DOS-style attributes for a file, as follows:
Flag S_IAREAD S_IAHID S_IASYS S_IADIR S_IAENCR S_IAARCH S_IANORM S_IATEMP Meaning File is read-only File is hidden File is a system file File is a directory File is encrypted File needs backup (archive bit) File is a normal file File is a temporary file

UNIX to Windows Porting Guide

65

API-Specific Porting Issues

S_IASPARSE S_IAREPARSE S_IACOMP S_IAOFFL

File is a sparse file File has an associated reparse point File is compressed File is offline

access()
On NTFS file systems, in addition to the standard F_OK, R_OK, X_OK and W_OK flags, access() accepts the flags D_OK, P_OK, and O_OK for testing Delete, Change Permission, and Take Ownership permissions, respectively. The DOS attribute bits take precedence over ACLs, so if the read-only attribute is set, a check for W_OK fails, even if the DACL for the file would allow access.
See File Security on page 14 for more information. See exec() Family on page 55 for more information.

For file systems other than NTFS, access() checks the DOS attribute bits. This allows checks only for existence (F_OK) and write ability (W_OK). When checking for execute permission (X_OK), if suffixed searching is enabled, the NuTCRACKER Platform attempts to find a file with a .exe extension if the attempt to access() the extensionless file fails.

chmod()/fchmod()
On NTFS, these functions modify the files DACL. Because there is not an exact mapping between DACLs and UNIX permissions, some unexpected actions can occur. For example, if you use chmod() to change the permissions to mode 007 (read/write/execute for Other), and later use stat() to obtain the permissions on the file, the permissions are 777 (read/ write/execute for Owner, Group, and Other). This occurs because Other maps to the Windows group Everybody, which includes the owner and group.
See File Mode Flags on page 65 for a list of additional access mode bits that the NuTCRACKER Platform supports.

On NTFS, these functions set the DOS read-only attribute bit if there is no ACE in the file's DACL that allows write access. Otherwise, the read-only attribute bit is cleared. On all other file systems, these functions set the DOS read-only attribute bit if no write-enable bit is specified in the mode parameter. Otherwise, the read-only attribute bit is cleared. The NuTCRACKER Platform does not support the S_ISUID, S_ISGID,
S_ISTXT, or S_ISVTX access mode bits.

chown()/fchown()
chown() can be used to take ownership if the user has Take Ownership permission for the file. The NuTCRACKER Platform emulates giving away ownership of a file by adding the new owner and group to the files DACL.

66

MKS Toolkit

File Management

If the process is using setuid() or setgid() to impersonate another user or group, the NuTCRACKER Platform uses the real user or group ID (rather than the effective ID) to determine whether Take Ownership permission is available.
See File Security on page 14 for more information.

In addition to the chown() API capability to take ownership, the chown command permits giving away ownership if the caller has the Restore files and directories right which is enabled for Administrators, Backup Operators and Server Operators. On Windows Me, these functions have no effect.

umask()
See File Security on page 14. for more information. For information on the access mask. see File Mode Flags on page 65

On Windows NT/2000/XP/2003, the NuTCRACKER Platform supports additional bits for the access mask. On Windows Me, this function has no effect.

File Management
For additional information, see File Management on page 16.

This section discusses the API functions related to file systems, path names, file I/O, and special files.

File Systems

link()
Windows NT only supports hard links between files on locally-mounted NTFS file systems. Trying to link files on any other type of local file system, or on a network file system, fails with errno set to EMLINK, specifying that the maximum number of links to the file has been exceeded. Windows Me does not support links.

mount()/umount()
For additional information about the behavior of mount() and umount() on non-Windows 2000/XP/2003 operating systems, see the mount() reference page in the online MKS Toolkit UNIX APIs Reference.

Windows versions prior to Windows 2000 do not support mounting a file system under a directory in another file system. Therefore, these functions are currently supported only on Windows 2000/XP/2003. On Windows 2000/XP/2003, mount points must reside on NTFS 5 partitions. These functions can be used to control network shares on all Windows versions.

UNIX to Windows Porting Guide

67

API-Specific Porting Issues

statvfs()/fstatvfs()
The base Windows 95 operating system, prior to the OEM Service Release 2 (OSR2) version, does not support file systems larger than 2G. Although the operating system can access larger networked file systems, the function used to determine the size of a file system returns incorrect information. Hence statvfs() and fstatvfs() return an incorrect size for network file systems larger than 2G. This problem does not occur on Windows NT/2000/ XP/2003 or Windows Me.

lstat()/lchown()/readlink()/symlink()
For more information, see the symlink() reference page in the online MKS Toolkit UNIX APIs Reference.

Symbolic links are only supported on Windows 2000/XP/2003 when using a local NTFS 5 file system. Therefore, on all other Windows files systems, lstat() and chown() act like stat() and chown() respectively. readlink() always returns EINVAL when called on an existing file. symlink() is not defined by default.

Path Names

chdir()
Windows supports multiple root directories (one for each drive) and maintains a current working directory on each drive. This can lead to unexpected behavior. For example, the call:
chdir("/temp/foo/bar");

changes to the directory /temp/foo/bar on the current drive. The call:


chdir("E:/temp/foo/bar");

changes to the directory /temp/foo/bar on the E: drive. The call:


chdir("bar");

changes to the directory bar below the current directory. The call:
chdir("E:bar");

changes to the directory bar below the current directory on the E: drive. Finally, the call:
chdir("E:");

changes to the current directory on the E: drive; this is the mechanism used to switch between drives without changing the current directory for that drive.
See Path Names on page 18.

You can specify the directory path in any format.

chroot()
Windows does not support changing the root directory for a process.

68

MKS Toolkit

File Management

getcwd()
getcwd() returns the current working directory, on the current drive, in the

NuTCRACKER Platform format. You can use one of the


_NutPathToXXX() functions to convert this path to whatever format you

require.

_NutPathToXXX() Family
Path formats are discussed in more detail under Path Names on page 18.

These functions convert path names from one format to another:


_NutPathToNutc() converts a path to NuTCRACKER Platform format, in which drive letters are represented by /D= rather than D:, and path components are separated by forward slashes (/). _NutPathToWin32() converts a path to Win32 format, in which drive letters are represented as D:, and path components are separated by back-slashes (\). _NutPathToWin32FS() converts a path to Win32 forward slash format, in which drive letters are represented as D:, and path components are separated by forward slashes (/).

_NutQueryXXXDir() Family
These functions determine the correct values for several paths whose locations change from system to system:
_NutQueryRootDir() returns the path to the MKS Toolkit product

installation directory.
_NutQueryWinDir() returns the path to the Windows installation

directory.
_NutQueryWinNetFileDir() returns the path to the various networking configuration database files (for example, hosts, networks). Use the return value from this function rather than a hardcoded /etc in code that accesses network configuration files. _NutQueryWinSysDir() returns the path to the Windows system directoryusually the system subdirectory (for Windows Me) or the system32 subdirectory (for Windows NT/2000/XP/2003)under the

Windows installation directory.

File I/O and Control

Since Windows file APIs permit files as large as 16 giga-tera-bytes, the NuTCRACKER Platform provides access to these files through standard Large File Unix APIs, such as open64(), creat64(), and readdir64(), amongst others.

UNIX to Windows Porting Guide

69

API-Specific Porting Issues For details on the _NutConf() API, see the _NutConf() reference page in the online MKS Toolkit UNIX APIs Reference.

For compatibility with earlier 32-bit-only versions of the NuTCRACKER Platform which were capable of reading beyond the 2G boundary, please use the _NutConf() API.

creat()/open()/fopen()
On Windows NT/2000/XP/2003, files created with write permission also have Delete, Change Permission, and Take Ownership permissions, to ensure that the file is created with write semantics that are equivalent to UNIX.
For more information, see File Security on page 14.

Windows supports more modes in which a file can be opened than does UNIX. The NuTCRACKER Platform provides additional flags that you can add to the flags passed to open() and fopen() to enable these Windows modes:
open() O_TEXT O_BINARY O_TEMPORARY fopen() "t" "b" "D" Meaning Opens the file in text mode. Opens the file in binary mode. Deletes the file when the last descriptor referring to it is closed. This corresponds to the FILE_FLAG_DELETE_ON_CLOSE flag in Win32. Randomly accesses files. This is a hint to optimize file caching. This corresponds to the FILE_FLAG_RANDOM_ACCESS flag in WIn32. Sequentially accesses files from beginning to end. This is a hint to optimize file caching. This corresponds to the FILE_FLAG_SEQUENTIAL_SCAN flag in Win32. Uses the file for temporary storage. File systems attempt to keep all of the file in memory for quicker access rather than flushing the data back to mass storage. This corresponds to the FILE_ATTRIBUTE_TEMPORARY flag in Win32.

O_RANDOM

"R"

O_SEQUENTIAL

"S"

O_SHORT_LIVED

"T"

70

MKS Toolkit

File Management

fcntl()
You can switch between text and binary modes by adding O_TEXT or O_BINARY to the flags set with the F_SETFL command. File locks set with fcntl() are valid only for NuTCRACKER Platform applications running on the local machine.

_NutFastStat()
Filling in a normal stat structure may take time, because the NuTCRACKER Platform may need to communicate with the SAM database over the network to fill in the security-related fields. The _NutFastStat() function is for those times when you need only the type, size, and/or dates of a file.

_NutFdToHandle()/_NutHandleToFd()
These functions provide interoperability between NuTCRACKER Platform applications and native Win32 code. _NutFdToHandle() returns a Win32 handle corresponding to a NuTCRACKER Platform file descriptor. _NutHandleToFd() returns a NuTCRACKER Platform file descriptor corresponding to a Win32 handle.

read()/write()
See Text Files and Binary Files on page 20 for more information.

Reads from a file in text mode convert carriage return/line-feed pairs (\r\n) into single line-feeds (\n). Writes to a file do the opposite. Reading from a non-seekable file (for example, a socket) in text mode may not be reliable if the last character read is a carriage return (\r), the NuTCRACKER Platform cannot look ahead to determine if the next character is a line-feed. This results in the pair not being correctly replaced. Trying to read from a directory fails with errno set to EISDIR. Use the readdir() family of functions to read directories.

readdir()/readdir_r()
readdir() and readdir_r() always set d_ino to zero.

rename()
See File Systems for more information.

Handling of file name case is dependent on the underlying file system, which is either case-preserving or case-insensitive. You must avoid writing code that renames files that differ only in case. Windows does not allow renaming of open files on network file systems. Hence rename() fails on such files.

UNIX to Windows Porting Guide

71

API-Specific Porting Issues

stat()/fstat()
The NuTCRACKER Platform cannot provide a complete stat structure for all files and devices, because of differences in the operating systems representation of the data, and in the implementation of special files. For disk files the following applies: The st_dev and st_rdev fields are set to the volume serial number of the file system containing the file, if it can be obtained. Otherwise, st_dev is set to 0. The st_ino field is reliable only for locally-mounted NTFS and VFAT file systems. The NuTCRACKER Platform generates an inode number based on other file information, but this number cannot be guaranteed to be unique.
See File Mode Flags on page 65 for more information.

The st_mode field may contain additional permission flag bits. On Windows Me, the st_gid and st_uid fields are taken from the NuTCRACKER Platform-assigned user and group IDs. The time fields provide as much information as the underlying file system provides. For example, NTFS supports all three file times, while FAT only supports last-modification times. Note that on a VFAT file system, the last-access "time" is actually only a date. The NuTCRACKER Platform provides an st_attr field which contains the DOS-style file attribute settings, such as hidden or readonly. For special files and devices, you cannot depend on which fields are valid for a given device. The bits in st_mode, which indicate the type of the file (for example, the S_ISXXX macros), are always valid.

See File Management on page 16 for more information.

These bits are shown in File Mode Flags on page 65.

See File Management on page 16 for more information.

utimes()/utime()
Windows Me does not support a concept that maps to utimes()/ utime() on a directory. In addition, you must have write permission on the file or directory (Windows NT only) for utimes()/utime() to succeed.

Special Files

ctermid()
ctermid() always returns /dev/tty.

mknod()
mknod() can only be used to create FIFOs; attempts to create any other form of special file fails, with errno set to EINVAL.

72

MKS Toolkit

Interprocess Communications and Networking

pipe()
Some UNIX platforms create bi-directional pipes with pipe()you can read and write on both file descriptors. Windows only supports unidirectional anonymous pipes. You may only read from the read-side of the pipe (fd[0]), and write on the write-side of the pipe (fd[1]).

ttyname()/ttyname_r()
These functions return /dev/tty/nnn, where nnn is the process group ID.

Interprocess Communications and Networking


bind()
Sockets in the AF_UNIX address family may be bound only to paths that are local to the machine calling bind(). The socket appears to be a regular file to a non-NuTCRACKER Platform application. If a non-NuTCRACKER Platform process writes to that file, it is corrupted and no further new connections can be made to the socket. Once all NuTCRACKER Platform file descriptors for the socket are closed, the socket then appears to be just a regular file to all NuTCRACKER Platform applications.

gethostbyname()/gethostbyaddr()
See Interprocess Communications and Networking on page 26 for more information.

Windows networking does not assign individual network names to physical network devices. Therefore, these functions are not guaranteed to return deterministic answers for multi-homed machines.

mkfifo()
See Interprocess Communications and Networking on page 26 for more information.

FIFOs must be created in the fifos directory under the NuTCRACKER Platform installation directory. You can get the installation directory with the _NutQueryRootDir() function. Also, NuTCRACKER Platform FIFOs appear to be regular files to non-NuTCRACKER Platform applications. If a non-NuTCRACKER Platform application writes to a FIFO, it is corrupted such that it no longer appears to be a FIFO to NuTCRACKER Platform applications.

poll()
The NuTCRACKER Platform implements poll() as a wrapper around select().

UNIX to Windows Porting Guide

73

API-Specific Porting Issues

select()
Windows 95 does not correctly return ECONNREFUSED for non-blocking socket connections; the connection attempt blocks indefinitely. Therefore, on Windows 95 you should always use a timeout in your calls to select() on non-blocking sockets. This does not apply to Windows 98/Me.

sendmsg()/recvmsg()
These functions are only supported for the AF_UNIX address family.

socketpair()
This function is only supported for the AF_UNIX address family.

shmat()
Windows requires that attached shared memory regions be aligned on 64K boundaries. If you call shmat() with a fixed address, you must ensure that this address is 64K-aligned.

Math Libraries
This section discusses programming in C and C++ using the standard math library, libm. For information about using FORTRAN math libraries, refer to Using FORTRAN on page 83.

Math functions in various flavors of UNIX differ in their handling of the errno variable, when and if they call the matherr() function and whether to display errors on standard error. Since there are so many standards to choose from and none is compatible with any other, MKS Toolkit for Professional Developers and MKS Toolkit for Enterprise Developers provide a single Math library with multiple personalities. The default is ANSI/POSIX 1003.1 mode but may be changed programmatically. The MKS Toolkit math library can run in any of four different modes, each corresponding to a different standard, and each defining a different means of error handling. These four modes are ANSI/POSIX 1003.1 (POSIX), IEEE754 (IEEE), X/Open Portability Guide issue 3 (XOPEN), and System V Interface Definition Edition 3 (SVID). The primary error behaviors of each are: In POSIX mode, errno is set, the matherr() function is not called, and no warning messages are printed on standard error. POSIX mode is the default behavior of the MKS Toolkit math library. In IEEE mode, errno is not set, the matherr() function is not called, and no warning messages are printed on standard error.

Math Library Modes

74

MKS Toolkit

Math Libraries

In XOPEN mode, errno is set, the matherr() function is called, and no warning messages are printed on standard error. In SVID mode, errno is set and the matherr() function is called. If matherr() returns 0, warning messages for certain errors are printed on standard error. In addition, functions that overflow return HUGE (defined in math.h), the maximum single precision floating point value, rather than the double precision Infinity/HUGE_VAL.

Changing Math Library Modes

To change math library modes, you should include math.h and call the _NutLibMSetLibraryType() function, whose prototype is:
_LIB_VERSION_TYPE _NutLibMSetLibraryType(_LIB_VERSION_TYPE newtype)

where newtype is an enum (_POSIX_, _IEEE_, _XOPEN_, or _SVID_) where each value corresponds to one of the modes discussed above. This function returns previously set library mode. The function may be changed at any time before or after calling a math function.

Optimization Issues

When you use the intrinsic math functions, either via compilation flags (for example, cl -Oi) or via compiler pragmas (for example, #pragma intrinsic(acos)), the compiler generates inline floating point instructions. Even in the face of inline floating point instructions, the MKS Toolkit math library sets errno and calls matherr() as appropriate for the mode of the math library for most math functions. However, some functions have true intrinsic forms (that is, the processor is capable of calculating the result directly without the need to call the math library) that are typically used with high optimization (-Oi and -Ox used together along with the #pragma intrinsic). On the Intel x86 platform, the functions atan(), exp(), sin(), atan2(), log(), sqrt(), cos(), log10(), and tan() all have true intrinsic forms that are directly supported by the processor. Unlike the math library routines of the same names, these true intrinsic functions do not check input values and have different exception handling and boundary conditions. Using such functions means that you will lose IEEE exception handling, matherr(), and the setting of errno (loss of errno means your program will no longer be ANSI compliant). However, the intrinsic forms can enhance performance of floating-point-intensive programs considerably, and for many programs, standards conformance is not important. This implies that when you build executables for debugging (-g implies no -O), they use different implementations of math APIs from non-debugging or optimized executables. The results of the APIs may even differ slightly because of differences in the hardware and software implementations.

UNIX to Windows Porting Guide

75

API-Specific Porting Issues

Miscellaneous Functions
confstr()/_NutConfStr()
The NuTCRACKER Platform supports several additional confstr() parameters for locating various paths at run time. The _NutConfStr() function lets you select the format of the returned path.

ctime() Family
Accepted TZ formats are detailed on the tzset() reference page in the online MKS Toolkit UNIX APIs Reference.

The NuTCRACKER Platform supports POSIX-style formats for the TZ environment variable, which allows per-process specification of local time, including the date and time of transition between standard and daylight savings time. If the value of TZ begins with a colon, the process's local time zone is set from the Registry. In this case, the portion of the TZ string following the colon is the key name of the time zone entry to be used by the process.

dlopen() Family
Specific issues are discussed on the dlopen(), dlclose(), dlsym(), and dlerror() reference pages in the online MKS Toolkit UNIX APIs Reference.

The dlopen() family of functions is built on native Windows facilities, and hence does not behave exactly the same as on most UNIX platforms. For example, there is no lazy binding on Windows, so the RTLD_LAZY flag has no effect.

errno/h_errno/perror()/strerror()
You should not explicitly declare errno in your code; you should always include <errno.h> to ensure that errno is correctly defined in a threadsafe fashion. Similarly, always include <netdb.h> to ensure that h_errno is correctly defined.
See the Introduction to the online MKS Toolkit UNIX APIs Reference for a table showing the mapping of Windows error codes to errno values.

The NuTCRACKER Platform maps Win32 error codes to a corresponding UNIX errno value whenever possible. When no valid mapping exists, errno is set to the negative of the Win32 error code. Your code must allow negative errno values. For example, directly accessing sys_errlist[errno] without validating that errno is positive can cause an access violation. You should always use the strerror() function in preference to sys_errlist[]. The strerror() function returns the Windows error message for any error code that does not map to a UNIX error code. The NuTCRACKER Platform also supports h_errno, for networking name-resolution functions (such as gethostbyname()), by mapping Winsock error codes as needed.

76

MKS Toolkit

Miscellaneous Functions

The NuTCRACKER Platform provides a perror command, which takes an error number as an argument. This command interactively displays error messages corresponding to UNIX errno values (a positive number as an argument), or Windows error codes (a negative number as an argument).

getenv()/putenv()/environ
On Windows, environment variable names are case-insensitive. The NuTCRACKER Platform maintains this behavior, so getenv("Path") and getenv("Path") get the same variable.
See Path Names on page 18 for more details.

When a NuTCRACKER Platform application starts, the NuTCRACKER Platform converts all paths in the environment from Windows format to NuTCRACKER Platform format. When exec()ing another program, the environment is converted to Win32 format. When adding paths to the environment with putenv(), you should ensure that these paths are in NuTCRACKER Platform format, by using _NutPathToNutc() when appropriate. If you fail to do this, the NuTCRACKER Platform can misinterpret the path when it converts the environment to Win32 format. You can control which environment variables get converted and which do not with the NUT_ENV_CONVERT and NUT_ENV_LITERAL environment variables. If you directly access the environ array, you should either modify your code to use the getenv() and putenv() functions (which take this into account), or modify your name-matching algorithms to be case-insensitive.

See Environment Variables on page 163 for more information.

mktemp()
You should not assume that the directory /tmp or /usr/tmp exists when using mktemp() to create a temporary file name. If you use tempnam(), the NuTCRACKER Platform uses the correct temporary directory on the system. Otherwise, you are responsible for ensuring that the directory exists.

_NutDebugBreak()
This function is useful when debugging your application. It pops up a message box giving you the opportunity to attach the debugger to the running process.

sysconf()
See Strategies for Maintaining a Single Executable on page 51 for more information.

Use _SC_NUTC_OS_PLATFORM to determine the version of Windows on which the process is running.

UNIX to Windows Porting Guide

77

API-Specific Porting Issues

syslog() Family
On Windows NT/2000/XP/2003, messages are logged in the system Application Event log. The ident string passed to openlog() is used as the Event Source name. The priority passed to syslog() is used as the event priority. You can use the Windows Event Viewer to display the Application Event log. On Windows Me, messages are logged to the file ident.log.txt in the logs subdirectory of the MKS Toolkit installation directory, where ident is the parameter as passed to openlog().

78

MKS Toolkit

Miscellaneous Functions

UNIX to Windows Porting Guide

79

API-Specific Porting Issues

80

MKS Toolkit

Language Support

For details on using the GCC compiler, linker, and other related tools provided on the MKS Toolkit Resource Kit CD, see the GCC Release Notes also provided on the Resource Kit CD.

This chapter discusses using the various Microsoft and Absoft compilers
and linkers that the NuTCRACKER Platform supports for C, C++, and FORTRAN. In addition to the compilers and linkers discussed in this chapter, the NuTCRACKER Platform also supports a version of the GCC compiler.

Using C
See the cc and ld references pages in the online MKS Toolkit Utilities Reference for more details.

The NuTCRACKER Platform relies on cl from Visual C++, but MKS Toolkit provides cc and ld wrappers that behave like their UNIX counterparts. Because the MKS Toolkit utilities are front-ends for the native Microsoft compiler, you can use the online Win32 SDK Tools Reference to look up messages and warnings. There are very few issues with respect to using the cc wrapper: To pass additional compiler or linker flags with cc, use -W/cl_option, where cl_option is a valid Microsoft compiler (cl) or linker (link) option. To determine what cc or ld is passing to cl, use the verbose flag, -Wv.

See Using Data Exported From DLLs on page 42 for information on changes you might need to make in your source code if you are using data exported from shared libraries to initialize global variables,

Using C++
The NuTCRACKER Platform SDK relies on cl from Visual C++, but MKS Toolkit provides cxx and ld wrappers that behave like their UNIX counterparts. Because the MKS Toolkit utilities are front-ends for the native Microsoft compiler, you can use the online Win32 SDK Tools Reference to look up messages and warnings.

UNIX to Windows Porting Guide

81

Language Support

Review the following issues with respect to using C++ with the NuTCRACKER Platform: The NuTCRACKER Platform supports only the Microsoft Visual C++ compiler (version 5.0 or later).
See the cxx reference page in the online MKS Toolkit Utilities Reference for a complete description of usage and options.

Use only the cxx command to compile and link C++ applications. Do not use cc. To pass additional compiler or linker flags with cxx, use -w/cl_option, where cl_option is a valid Microsoft compiler (cl) or linker (link) option. To determine what cxx or ld is passing to cl, use the verbose flag, -Wv. The Visual C++ compiler mangles/decorates the names of external variables, not just function names. Most UNIX C++ compilers do not mangle variable names. If you are linking C and C++ objects, and have not correctly declared your variables as extern "C", you might get linkage errors. This is fixed simply by ensuring that your variable declarations are correctly protected. The Visual C++ compilers have two different runtime libraries. One is a standard non-template version, the other uses templates and supports the Standard Template Library (STL). Use one or the other (but not both) in your application. There is no command-line switch to select the template or non-template versions of the runtime libraryinstead the selection is made by changing which header files you include. For example, to include the non-template version of ostreams,use:
#include <ostream.h>

To use the template version of ostreams you would instead use:


#include <ostream>

The template version of the C++ runtime library uses namespaces, so you may also need to use the declaration:
using namespace std;

in your C++ source files to successfully link your application.


See the cxx and ld reference pages for more details.

When you are linking applications that contain mixed-language sources (for example, both C and C++), you must use the cxx command to link the application. If you are linking applications that contain other languages (for example, FORTRAN and C++), you may need to specify additional switches to the cxx command to tell the linker to include any additional required runtime components.

82

MKS Toolkit

Using FORTRAN

You do not need to specify any of the C++ runtime libraries on the command line when you link your application. The correct libraries are automatically included by the cxx command. The cxx command provides a static switch to force a link to the static C++ runtime libraries. We strongly recommend against using this. The Visual C++ compiler implements static destructors by registering the destructor function with atexit(). Because of this, static destructors are not run if the process exits abnormally, such as via a signal or by calling _exit().

Using FORTRAN
For more information about this compiler, contact Absoft directly (http://www.absoft.com).

The NuTCRACKER Platform works with the Absoft Pro FORTRAN compiler (version 5.0 or later). You must purchase and install this compiler separately. MKS does not provide technical support for this compiler; direct all compiler-related support issues to Absoft.
Note MKS Toolkit supplies two commands, ncf77 and ncf90, that must be used instead of the Absoft-supplied f77 and f90 commands. Be sure to edit your make files accordingly.

Please review the following notes before installing and using the Absoft compiler: The NuTCRACKER Platform does not support the Absoft integrated development environment (IDE) to link executables. If you choose, you may use Absoft's IDE or command-line tools to compile source files and generate object files; however, you must use ncf77 or ncf90 to link executables. You may use the ncf77 and ncf90 commands to link an executable containing both FORTRAN and C object files. The default stack size under Windows NT/2000/XP/2003 is 1 MB. Many UNIX platforms have a much larger value (5-8 Mb). Older FORTRAN programs tend to use lots of stack memory and consequently programs may unexpectedly crash when first run on Windows NT/2000/XP/2003. If you need a 5 Mb stack, you can specify:
-W/stack:5000000

with the ncf77/ncf90 commands when linking the executable to increase the size of the maximum stack.

UNIX to Windows Porting Guide

83

Language Support

When you first install the Absoft compiler, it may reset your LIB and INCLUDE environment variables to point to Absoft's libraries and include files. This causes problems if you also use Microsoft Visual C++. You must update the environment to point to both compilers, or you can re-install Visual C++, which should cause the environment variables to point to both compilers. You should not link against the following Absoft-supplied libraries when using the MKS Toolkit UNIX APIs: absrt0.lib, fio.lib, fiodll.lib, libac.lib, libacdll.lib, mrwe.lib, unix.lib, and vms.lib. These libraries provide interfaces that resemble certain interfaces from the MKS Toolkit UNIX APIs, and unpredictable program behavior would result if you were to mix these Absoft libraries with the NuTCRACKER Platform. It is safe and completely normal to link against the Absoft-supplied math libraries. Several Absoft extension libraries (such as OpenGL and SuperPlot) work with the NuTCRACKER Platform only as long as you do not call fork(). MKS does not claim to support any of these extension libraries.

For details on building standalone Win32 DLLs, see Building Standalone DLLs on page 109.

Note If you need tight seamless run-time library integration between C and

FORTRAN, you must use the Absoft compiler. But if you do not need, for example, synchronized input/output between the C and FORTRAN code or if the FORTRAN has no input/out then you can compile the FORTRAN code with your favorite FORTRAN compiler and build a Win32 standalone DLL and link it to your C driving executable code. This FORTRAN code cannot make NuTCRACKER Platform calls but it is often the case that FORTRAN is simply used for fast Math subroutines in which case this solution will work just fine with, for example, the HP/Compaq/DEC/Microsoft FORTRAN compiler.

84

MKS Toolkit

Using the Visual C++ IDE


The instructions in this chapter apply only to building applications. See Porting Shared Libraries on page 103 for instructions for building DLLs with the IDE.

Environment (IDE) with the NuTCRACKER Platform. While we recommend that you not use the IDE in your initial port, you may need or want to use it as you integrate your application more tightly with Windows. The information in this chapter describes how to: Create a new project, Set compiler and linker options for that project, and Build and run a console application.

This chapter discusses using the Visual C++ Integrated Development

Create a New Project


Visual Studio 5.x and 6.x
See Choosing the Appropriate Subsystem on page 92 for a complete discussion of the differences.

The first step is to create a new project in which to work: 1. Select File > New. 2. Select the Project tab. 3. To create a console (non-graphical) application, select Win32 Console Application. 4. To create a Windows (graphical) application select Win32 Application. 5. Type a name for your project in the Name field. 6. In the Location field, specify a directory for your project. 7. Select Create or OK. In VC++ 6.x, an additional dialog appearsselect An empty project. 8. To import source code, select Project > Add to Project > Files. 9. Choose the source files for your project and select OK.

UNIX to Windows Porting Guide

85

Using the Visual C++ IDE

Visual Studio .NET 7.x

The first step is to create a new project in which to work: 1. Select File > New > Project. 2. In the Product Types field, select Visual C++ Projects. 3. In the Templates field, select Win32 Project. 4. Enter a name for your project in the Name field. 5. In the Location field, specify a directory for your project. 6. Click OK. The Win32 Application Wizard begins. 7. Click Application Settings. A dialog appears.

See Choosing the Appropriate Subsystem on page 92 for more information.

8. Specify whether the project is a console application, a Windows application, a DLL, or a static library. 9. Under Additional Options, select Empty Project. 10. Click Finished. 11. To import source code, select Project > Add Existing Item. 12. Select the source files for your project and click OK.

Set Compiler Options


Once you have created your project, you need to set the project compiler options:

Visual Studio 5.x and 6.x

1. Select Project > Settings. 2. Select Win32 Debug in the Settings For control. 3. Add /FI"$(ROOTDIR)\include\nutc.h" and /Zl to the Project options field (anywhere). 4. Select Win32 Release in the Settings For control. 5. Add /FI"$(ROOTDIR)\include\nutc.h" and /Zl to the Project options field (anywhere). 6. Select All Configurations in the Settings For combo box. 7. Select Preprocessor from the Category list box. 8. Add $(ROOTDIR)\include to the Additional Include Directories field. 9. In addition, for C++ applications: 10. Select Code Generation from the Category list box.

86

MKS Toolkit

Set Linker Options

11. Select Multithreaded DLL in the Use run-time library list. 12. Click OK.

Visual Studio .NET 7.x

1. Select Project > Properties. 2. Select the Debug configuration. 3. Select the Win32 Platform. 4. From the Configuration Properties list, select C/C++ > Code Generation > Basic Runtime Checks. Change this to Default.

Note Setting Basic Runtime Checks to Both can cause compile problems. Thus, the Default setting is recommended.

5. From the Configuration Properties list, select C/C++ > Command Line. 6. In Additional Items, add /FI"$(ROOTDIR)\include\nutc.h" and /Zl, and click Apply. 7. Select Configuration Release. 8. From the Configuration Properties list, select C/C++ > Code Generation. 9. In the Additional Items field of C/C++ > Command Line, add /FI"$(ROOTDIR)\include\nutc.h" and /Zl, and click Apply. 10. In the Configurations field, select All Configurations. 11. Select C/C++ > General and add $(ROOTDIR)\include to Additional Include Directories field, and click Apply. 12. For C++ applications, select C/C++ > Code Generation. 13. Select Multithreaded DLL in the Run-Time Library list, and click Apply. 14. Click OK.

Set Linker Options


To next step is to set the linker options for your project:

UNIX to Windows Porting Guide

87

Using the Visual C++ IDE An exception is the case discussed in Linking X Applications on page 93. Note The header files provided with the MKS Toolkit UNIX APIs include

pragmas that cause the linker to include the appropriate NuTCRACKER Platform libraries. Therefore, you should never need to include a NuTCRACKER Platform library on your link line.

Visual Studio 5.x and 6.x

1. Select Project > Settings. 2. Select All Configurations in the Settings For combo box. 3. Select the Link tab. 4. Select General from the Category list box. 5. Type the name you want for the executable file in the Output File Name field. 6. Select Customize from the Category list box. 7. Select the Force file output check box. 8. Select the debug build in the Settings For list. 9. Select Input from the Category list box. 10. Enter $(ROOTDIR)\lib in the Additional library path field. 11. Select Debug from the Category list box. 12. Select Win32 Debug in the Settings For control. 13. Select the Debug info check box. 14. If you created a Windows (rather than a console) application: 15. Select Output from the Category list box. 16. Enter mainCRTStartup in the Entry-point Symbol field. 17. Select Both Formats. 18. Click OK.

Visual Studio .NET 7.x

1. Select Project > Properties. 2. Select Configurations: All Configurations. 3. Select the Win32 platform. 4. Select Linker > General in the Configuration Properties. 5. Enter the name you want for the executable file in the Output File field. 6. Select Linker > Command Line. 7. Select the Debug Configuration

88

MKS Toolkit

Build the Application

8. Select Linker > General. 9. Enter $(ROOTDIR)\lib in the Additional Library Directories field. 10. Select Linker > Debug, and click Apply. 11. Select Yes in the Generate Debug Info field. 12. If you created a Windows (rather than a console) application: 13. Select Linker > Advanced. 14. Enter mainCRTStartup in the Entry-Point field. 15. Click OK.

Build the Application


To build your application with Visual Studio 5.x and 6.x, select Build filename.exe (where filename is the name of the executable file you created in the previous step) from the Build menu. The application is compiled and linked and the results of the build are displayed in the Build window. To build your application with Visual Studio .NET 7.x, select Build from the Build menu. The application is compiled and linked and the results of the build are displayed in the output window.

Run the Application


To run your application with Visual Studio 5.x and 6.x, select Build > Start Debug > Go. To run your application with Visual Studio .NET 7.x, select Debug > Start.

UNIX to Windows Porting Guide

89

Using the Visual C++ IDE

90

MKS Toolkit

Porting X Applications

See the OReilly X Window System suite of documentation for details. You can also find a link to the X documentation at
http://www.mkssoftware.co m/docs/x_index.asp.

MKS Toolkit for Enterprise Developers contains a standard X

development environment based on X11R6 and Motif 2.1.30. In addition, using the optional Wintif libraries, Motif applications can have a Windows look and feel. This product comes with both Wintif and Motif libraries, but you must license Wintif redistribution rights separately. MKS Toolkit for Enterprise Developers comes with several sample X clients in the samples directory on the MKS Toolkit CD. To run any of these X applications, you must have an X server installed on your system. MKS Toolkit for Enterprise Developers does not provide reference pages for X Windows functions.

Using imake
For detailed information about imake, see Software Portability with imake, 2nd ed., by Paul DuBois (OReilly and Associates, Inc. 1996).

We recommend that you use imake to build your X applications, if possible. You may encounter the following issues with imake: The imake configuration files reside in the directory ROOTDIR/usr/lib/X11/config. The NuTCRACKER-specific configuration files are:
NuTC.cf (NuTCRACKER Platform configuration parameters) NuTC.rules (NuTCRACKER Platform-specific imake rules) NuTC.tmpl (NuTCRACKER Platform-specific makefile templates) NuTClib.tmpl (NuTCRACKER Platform-specific shared library

dependencies) To make changes that apply to all of your Imakefiles, we recommend that you change the standard site.def file, or one of these files.

UNIX to Windows Porting Guide

91

Porting X Applications

You should use the following define when making NuTCRACKERspecific modifications:
#ifdef NuTCRACKERArchitecture #endif

so that you can use the same Imakefile for the NuTCRACKER Platform and other environments. If you have a single Imakefile that builds multiple programs using NormalProgramTarget() and has a macro such as:
PROGRAMS = bitmap bmtoa atobm

add the following rule to your Imakefile, immediately before your first NormalProgramTarget rule:
MultiNormalProgramBuildRule

This NuTCRACKER Platform-specific rule handles the .exe extension for executables under Windows. Similarly, rules such as:
Alltarget(twm)

that specify executable target files must be changed to:


Alltarget(ProgramTargetName(twm))

which handles the .exe extension on Windows.

Choosing the Appropriate Subsystem


Windows supports two subsystems for Win32 applicationsconsole and Windows. A console-subsystem application is a standard command-line oriented program, while a Windows-subsystem application is a GUI-only application. When Windows starts an application, it examines the subsystem type (stored in the executable file). If it is a console-subsystem application and the application is running in a console window (for example, from a command or shell prompt), the standard handles of the application are connected to that console. Otherwise, a new console window is created, and the standard handles are connected to this new console window. For a Windows-subsystem application, the standard handles for the application are not connectedthere is no standard input and no standard output. By default, NuTCRACKER Platform applications are linked as consolesubsystem applications. For most UNIX applications, this is the desired behavior. However, for X-based, GUI-only applications, this may not be desirable. If you run your X application from a command prompt, you will

92

MKS Toolkit

Linking X Applications

not notice the distinction, because the standard handles are attached to your current console window. However, if you run your X application by doubleclicking on its icon in the Explorer, you will see a console window created in addition to your GUI, which is probably not the desired result.
For details on creating a Windows-subsystem application with the GCC linker, gld, see the GCC Release Notes provided on the MKS Toolkit Resource Kit CD.

You can create a Windows-subsystem application by specifying the correct link-time flags: For cc/cxx/ld, add -W/subsystem:windows to your link line. For cl/link, add /subsystem:windows and /entry:mainCRTStartup to your link line. For the Visual C++ IDE, follow the steps described in Using the Visual C++ IDE on page 85. Keep in mind, however, that your Windows-subsystem application has no standard output, even when run from a console window (unlike UNIX, where standard output from an X application goes to the window from which you started the application, or to /dev/null if you start the application directly from a GUI). One solution to this problem is to provide a debugging-mode flag for your X application. When your application starts, if it is being run with the debugging flag set, you can create and attach to a new console window by executing the following code:
freopen("/dev/tty", "wt", stdout); freopen("/dev/tty", "wt", stderr); freopen("/dev/tty", "rt", stdin);

You can then send debugging output to standard output or standard error as you would on UNIX.

Linking X Applications
The NuTCRACKER Platform automatically determines the set of link libraries for an application based on pragmas in the header files. Therefore, when using the NuTCRACKER Platform, you generally do not need to specify any MKS Toolkit UNIX API libraries on the link line. However, X source code often includes Xt header files before Motif header files, causing the linker to include Xt.lib before Xm.lib, which is usually incorrect. Therefore, you must put the Motif library on the link line before the Xt library.

UNIX to Windows Porting Guide

93

Porting X Applications

Locations of X Windows Files


X Windows applications rely on many configuration files whose locations are specified by environment variables, such as XFILESEARCHPATH, XUSERFILESEARCHPATH, XAPPLRESDIR, and XENVIRONMENT. The NuTCRACKER Platform default values for X environment variables that refer to file search paths have identical values to their UNIX default values, except that the ROOTDIR value is placed before any absolute path. For example, on UNIX, if XUSERFILESEARCHPATH is:
/usr/lib/X11/%L/%N%C:/usr/lib/X11/%l/%N%C:

for the NuTCRACKER Platform, it would be:


$ROOTDIR/usr/lib/X11/%L/%N%C:$ROOTDIR/usr/lib/X11/%l/ %N%C:

The only exception to this rule is that X and Motif header files are in ROOTDIR/include/X11 and ROOTDIR/include/Motif/Xm, respectively. In addition, the NuTCRACKER Platform recognizes the tilde (~) character as a replacement for the percent (%) character in X file search paths because % also specifies environment variables under Win32.

Using Icons
In Windows, each application displays one or more icons in the following locations: In the left corner of the application window, where the icon is actually a push button for the window control menu. On the task bar button for the application window. In the task manager task list.
See the OReilly documentation for the XmGetPixmap() function for details.

You change the icon in a NuTCRACKER Platform application via the XmNiconPixmap resource. The default icon is a large X. You can set this resource in a resource file to the name of an XBM bitmap file or an XPM pixmap file. You can also set it programmatically. For example, to set the icon for all shell windows in an application to a given pixmap file, add the following to the application defaults file:
*iconPixmap: my_icon.xpm

94

MKS Toolkit

Using Wintif

If the file name does not include a path, Motif and Wintif search the path specified in the XBMLANGPATH environment variable for the file, or a default search path if XBMLANGPATH is not set. It is possible to use multiple icon pixmaps in an application by setting resources appropriately. For example, the following creates a default icon for the application, and special icons for two dialogs:
*editDialog*iconPixmap: edit_icon.xpm *searchDialog*iconPixmap: search_icon.xpm *iconPixmap: default_icon.xpm

Using Wintif
Wintif is a set of replacement libraries for Motif. These libraries offer the same API as Motif, so you can use Wintif the same way you use Motif, but with Wintif, you can select a Windows look and feel or a Motif look and feel at runtime. After installing MKS Toolkit for Enterprise Developers with the Wintif option, to use Wintif, simply compile and link your application. While Motif is freely redistributable, Wintif is not. You must purchase redistribution rights for Wintif.

Switching Between Motif and Windows Modes

Wintif has three look and feel modes that you can select at runtime. You can choose a traditional Motif look, a Windows 3.1 look, or the standard Windows look. To switch between modes: From the command-line, add the option xrm "*compatibilityMode: value", where value is one of the following: Motif, Windows3_1, or Windows95. In a resource file, add the resource *compatibilityMode: value, where value is one of those listed above. In the environment, set WINTIF_MODE to one of the values listed above. We recommend against setting the mode in the environment.

UNIX to Windows Porting Guide

95

Porting X Applications

Runtime Detection of Mode

If you need to detect the look and feel mode at runtime, define WINTIF in your make environment and use code similar to the following:
#if defined(WINTIF) if ( (_WXmLookAndFeel() == WXmWINDOWS95) || (_WXmLookAndFeel() == WXmWINDOWS3_1) ) { // In Windows95/3.1 look and feel } else { #endif // WINTIF not defined or in Motif look and feel #if defined(WINTIF) } #endif

Changes to Motif Resource Defaults

Because Wintif displays in Windows95 mode by default, the default values of certain resources are different from their traditional UNIX defaults, to mimic the Windows look and feel. The default value for each of the following resources was changed, affecting all widgets: Background ColorMotif displays background color dynamically, depending on your display. For Wintif, the default background is gray in Windows95 mode and white in Windows3_1 mode. FontThe default Motif font is fixed. Wintif uses the first font it finds from the following list:
sysmsw, mswsys0, and mswsys1 are aliases that can be set to a font suitable for use by your PC X server. Microsoft Windows-system--r- is the Microsoft Windows

System font for some PC X servers.


Adobe-Helvetica-*-r-*-*-12-*-*-*-*-*-* is an X font that

closely matches the previous font.


Adobe-Helvetica-*-r-*-*-14-*-*-*-*-*-*-* is another X

font that closely matches the previous.


fixed is the default font for Motif.

New Wintif Resources

The following resources are added to Wintif:

96

MKS Toolkit

Using Wintif

The XmScrollBar widget has a new resource XmNsquareSliders (class XmCSquareSliders). If True (the default), scroll bar sliders are always shown as squares. If False, the sliders resize to indicate how much of a windows contents are currently displayed. The XmToggleButton and XmPushButton widgets have a new resource XmNshowDashedBorder (class XmCShowDashedBorder). If True (the default), a dashed border is drawn around the label string of a button when it has focus. The VendorShell widget has a new resource XmNcompatibilityMode (class XmCCompatibilityMode) to control the compatibility mode (look and feel) of an application. This resource takes one of the following values: Motif, Windows3_1, or Windows95 (the default).

Changes to Motif Widget Behavior

The following Wintif widgets behave differently than their Motif counterparts, when displayed in Windows mode: The XmScale widget does not inherit its managers colors and shadow thickness. The XmToggleButton widget ignores the XmNfillOnSelect resource. The scroll bar widget, XmScrollBar, does not allow scrolling when there is nothing to scroll.

See File Selection on page 99 for details.

The XmFileSelectionBox and XmFileSelectionDialog widgets are significantly different. The following table shows the default values for Wintif widget resources that differ from the default values of their Motif counterparts.

Changes to Motif Widget Resources


Widget
XmArrowButton

Resource Name
XmNbackground

Motif Value
#729fff

Wintif Value
#ffffff

XmCascadeButton

For option menus:


XmNshadowThickness 2 1

In all other cases:


XmNshadowThickness XmNhighlightThickness XmDrawnButton XmNpushButtonEnabled 2 2 False 0 1 True

UNIX to Windows Porting Guide

97

Porting X Applications

Widget

Resource Name
XmNhighlightThickness

Motif Value
2 dynamic dynamic dynamic 2 2 2 False 2

Wintif Value
1 black black 1 0 1 1 True 1

XmFrame

XmNtopShadowColor XmNbottomShadowColor XmNshadowThickness

XmLabel XmList

In a menu: XmNmarginHeight XmNshadowThickness XmNhighlightThickness

XmPrimitive

XmNhighlightOnEnter XmNhighlightThickness

XmPushButton

In XmBulletinBoard and subclasses:


XmNdefaultButtonShadowThickness dynamic 0

In a menu:
XmNshadowThickness 2 1

In all cases:
XmNfillOnArm XmNhighlightThickness XmNbackground XmRowColumn XmNentryAlignment True 2 dynamic False 1 #ffffff

Motif: XmALIGNMENT_BEGINNING Wintif: XmALIGNMENT_CENTER


2 1

XmNshadowThickness XmScale XmScrollBar XmNhighlightThickness XmNbackground XmNtroughColor XmNtopShadowColor XmNshadowThickness XmScrolledWindow XmNspacing XmNshadowThickness XmSeparator XmNseparatorType

2 dynamic dynamic dynamic 2 4 dynamic

1 Gray76 Gray76 white 3 0 0

Motif: XmSHADOW_ETCHED_IN Wintif: XmSINGLE_LINE


5 5 1 1

XmText

XmNmarginHeight XmNmarginWidth

98

MKS Toolkit

Using Wintif

Widget

Resource Name
XmNborderWidth XmNshadowThickness XmNhighlightThickness

Motif Value
0 2 2 5 5 0 2 2 dynamic dynamic 2

Wintif Value
1 0 0 1 1 1 0 0 black 0 0

XmTextField

XmNmarginHeight XmNmarginWidth XmNborderWidth XmNshadowThickness XmNhighlightThickness

XmToggleButton

XmNselectColor XmNshadowThickness XmNhighlightThickness

File Selection

To handle changing drives, file selection (XmFileSelectionBox and XmFileSelectionDialog) is significantly different on Windows. If you use either of these widgets in their default operating mode, code is fully reusable in either Motif or Windows mode. You may need to make changes if your application: (a) customizes the XmFileSelectionDialog widget by adding or removing widgets, (b) directly manipulates the children of the widget, or (c) uses a custom search procedure. Motif lets a program obtain pointers to the child widgets of a file selection dialog, using the XmFileSelectionBoxGetChild() function. The Motif documentation states that the widgets obtained in this fashion should be treated as opaque types, and only used to manage or unmanage the child to add or remove it from the dialog. Code that retrieves values from the child widgets (via XtGetValues() or XtVaGetValues()) will almost certainly not behave correctly in Windows mode. As an example, some programs use the XmNvalue field of the XmDIALOG_TEXT child to obtain the full path selected in the dialog. The only correct ways to get this value are: By using the defined callbacks for the widget, and getting the values from the callback structure. By getting the value of the XmNdirSpec resource of the file selection widget. In addition, Motif allows custom directory and file search procedures for a file selection dialog. Custom search procedures for file selection dialogs are not implemented in Wintif.

UNIX to Windows Porting Guide

99

Porting X Applications

Wintif has made the following changes to the XmFileSelectionBox widget: An option menu lists the local and connected network drives, so that a user can select a drive just as in a standard Windows application. The function XmFileSelectionBoxGetChild() can be called with the values XmDIALOG_DRIVE_LIST and XmDIALOG_DRIVE_LIST_LABEL to obtain the widget ID of the drive option menu and the label widget for the option menu. The XmFileSelectionBox widget has a new resource XmNwintifFileCheck (class XmCWintifFileCheck). If True, the file selection box rejects filenames that are not in the standard FAT (8.3) format, and pops up an error dialog. False is the default. The XmFileSelectionBox widget has a new resource XmNdriveListLabelString (class XmCDriveListLabelString) of type XmString for changing the label of the drive option menu.

Easing the Transition from Motif to Wintif

You may find the following suggestions helpful when developing your applications: If you add buttons to dialogs, use button widgets rather than button gadgets to ensure that buttons pick up the Wintif default color scheme. If you must access values from composite widgets, do so via the resources of the composite widget rather than by getting the child and accessing its resources directly. Values returned by accessing the child widget directly may be invalid. Attempting to calculate sizes for x, y positioning by assuming the layout of child widgets, accessing child widget geometry resources, and adding them together may result in invalid values. If your application uses custom dialogs, and you want them to behave correctly in all look and feel modes, you should either start from an existing dialog, such as XmTemplate, or if you create your own dialog based on XmForm, you should not hardcode any resources (including constraints). Do not hard-code resources; use resource files instead.

100

MKS Toolkit

Simultaneous Installation of Motif and Wintif

Simultaneous Installation of Motif and Wintif


When you install MKS Toolkit for Enterprise Developers, both the Motif and Wintif libraries are installed simultaneously. This lets you switch libraries without having to re-install the product. Although you select a library to use during installation, you can change the library thereafter either: Permanently, by performing a maintenance install of MKS Toolkit from Add/Remove Programs in the Control Panel, and selecting the new library type. Temporarily, from a shell prompt, by running:
ncenv compiler_type Motif_Type

where compiler_type is the major version of Visual Studio you are using (7 is the major version of VS.NET) and Motif_Type is one of Motif or Wintif. For example:
ncenv 6 Wintif

or
ncenv 7 Motif

Note Wintif is an optional runtime product that must be licensed for an

additional fee from MKS. Wintif is comparable to Motif 1.2.4 and does not work for applications that depend on new behavior in Motif 2.x.

UNIX to Windows Porting Guide

101

Porting X Applications

102

MKS Toolkit

Porting Shared Libraries


For details on how UNIX shared libraries and Windows DLLs differ, see Shared Libraries on page 24. See Programming Applications for Windows, 4th Ed. by Jeffrey Richter (Microsoft Press, 1999) for details on how Windows handles DLLs, and how to work with DLLs with native Win32 API functions. See 00readme.txt in the directory on the MKS Toolkit CD for more information about the specific examples.
samples/tutorial/dll

This chapter describes how to port a UNIX shared library to Windows

using the NuTCRACKER Platform. It begins with a discussion of porting a C-language shared library for use with a NuTCRACKER Platform application, followed by a discussion of more complex things you can do. The final topic addresses building a shared library that is usable outside a NuTCRACKER application, for example, linked with a native Win32 application, dynamically loaded into a Visual Basic application, or implementing a COM object or ActiveX control.

MKS Toolkit for Professional Developers and MKS Toolkit for Enterprise Developers include several examples that demonstrate concepts discussed in this chapter. You can find these examples in the samples/tutorial/dll directory on the MKS Toolkit CD.

Building DLLs for NuTCRACKER Platform Applications


See Building Standalone DLLs on page 109 for information on building DLLs for nonNuTCRACKER Platform applications.

This section describes building a DLL for a NuTCRACKER Platform application, the compiler and linker flags needed to build a DLL, and more complex issues such as exporting data from a DLL.

Building Basic DLLs


For information on exporting data from your DLL, see Exporting Data from DLLs on page 108.

Building a DLL from UNIX C source code is straightforward, and can be accomplished with no source code changes (unless you need to export data from your DLL; in that case) Perform the following steps: 1. Generate a module definition file for your DLL, specifying the exported functions. 2. Optionally select a run time load address for your DLL. 103

UNIX to Windows Porting Guide

Porting Shared Libraries

3. Change your make file to specify the correct compilation flags for compiling code into a DLL. 4. Change your make file to specify the correct link flags for linking your compiled object files into a DLL.
Detailed information on the format of a .def file is in the Microsoft Visual C++ on-line documentation.

The first step is to generate your module definition file. By convention, the name for this file is the base name of your DLL, with a .def extension. The simplest form for this file is as follows:
LIBRARY my_dll_name EXPORTS Function1 Function2 Function3 ...

This is sufficient for most purposes. You simply generate this file, listing all the functions you want exported from your DLL. Next, you should consider choosing a preferred load address for your DLL. If you specify a preferred load address, you can reduce program load time. The linker creates your DLL assuming that it is loaded at this preferred address. At run time, the loader does not perform any relocation unless your DLL cannot be loaded at the preferred address (for example, if another DLL is already loaded at this address). In addition, you should specify a preferred load address to help ensure that the NuTCRACKER Platform can load the DLL at the same address in the child of a fork() as it was loaded in the parent. The fork() fails if the DLL cannot be loaded at the same address. If you decide to assign a preferred load address, you should pick an address in the range 0x30000000 through 0x60000000 (the operating system assigns addresses to DLLs without preferred addresses at 0x10000000 and working up, and system DLLs are assigned addresses starting at 0x80000000 and working down; NuTCRACKER Platform DLLs are in the 0x20000000 range). The address must be on a 64k (0x10000) boundary. These addresses apply to both Windows NT/2000/XP/2003 and Windows Me. Next, you need to compile your source files. The table below shows the required compilation flags:
Purpose Compile source files for inclusion in a DLL. Flag for cc/cxx -W/dll Flag for cl, or VC++ IDE /D__NUTC_DLL__

104

MKS Toolkit

Building DLLs for NuTCRACKER Platform Applications

After compiling all of your source files, link your object files to create the DLL. This link step creates three files: Your DLL. The import library for your DLL. An export definition file. The table below shows the required linker flags:
Purpose Specify the DLL output file. Flag for cc/cxx/ld -o my_dll_name.dll Flag for cl, or VC++ IDE /out:my_dll_name.dll /dll

Specify that a DLL is -W/dll being built rather than a program. Specify the name of the module definition file for the DLL. Specify the preferred load address for the DLL.
For more information, see Locating DLLs at Run Time on page 25.

-W/def:filename

/def:filename

-W/base:load-

address

/base:load-address

To use your newly-created DLL, place the .dll file where it can be located at runtime and place the .lib file where it can be found when your program is linked. Creating a module definition file is annoying: specifying exported symbols in a separate file can lead to maintainability problems. The Visual C++ compiler provides a compile-time solution to this problem, through the use of special keywords when declaring and defining functions. If you use these keywords exclusively, you do not need a module definition file at all. The two techniques can also be combined (for example, to make use of the more advanced directives available to the module definition file): the set of symbols exported is the combination of the symbols named in the module definition file and the symbols named with compile-time keywords. Adding the keyword __declspec(dllexport) to the definition of a function causes the linker to export the function when it is linked into a DLL. The corresponding keyword __declspec(dllimport) specifies that the function is to be imported from a DLL.

Avoiding the Module Definition File

UNIX to Windows Porting Guide

105

Porting Shared Libraries

A problem occurs with these directives, however. It is common for header files that define interfaces for a DLL to be included in source files used to build the DLL itself, as well as in source files that are using functions from the DLL. Hence these header files must be constructed so that they only declare functions with __declspec(dllimport) when not being used to build the DLL that is exporting those functions. The common solution is to use C-preprocessor directives in the header file, for example:
#if defined(BUILD_DLL1) # define DLLIMP1 __declspec(dllexport) #else # define DLLIMP1 __declspec(dllimport) #endif

Then add the keyword DLLIMP1 in front of the definition of each function that is to be exported from your DLL, and in front of those functions in the header files that declare the interfaces to your DLL. When building your DLL, all source files should be compiled with -DBUILD_DLL1. Because this symbol is not be defined when code that uses your DLL is compiled, it gets the correct import definition, while the files in your DLL see the correct export definition. There is a reason for the 1 on the C-preprocessor tokensin any project that consists of multiple DLLs, this same mechanism is required for each DLL, and the tokens for each DLL must be unique. Hence, you could have BUILD_DLL1, BUILD_DLL2, and BUILD_DLL3 for three DLLs in your project (choose more mnemonic names, as appropriate).

Exporting C++ Functions from DLLs

Using the compile-time directives rather than the module definition file is important when building DLLs that export C++ functions. C++ compilers mangle (or decorate) function names as a technique for implementing typesafe linkage and overloading. The resulting names often do not resemble the original function names and are often illegible. This makes the task of manually generating a module definition file for C++ functions more difficult. Using __declspec(dllexport) and __declspec(dllimport), your C++ code can simply be linked into the DLL, and the appropriate symbols are exported. It is common to perform startup actions when a DLL is initialized, and cleanup actions when the DLL is shut down. DLLs provide a simple notification mechanism for DLL initialization and shutdown, and also for

Performing Actions at DLL Initialization and Shutdown

106

MKS Toolkit

Building DLLs for NuTCRACKER Platform Applications

thread creation and destruction, which is useful when building thread-safe DLLs. To make use of this technique, you must implement a DllMain() function, with the following prototype:
#include <winnutc.h> BOOL WINAPI DllMain( HMODULE hDllHandle, ULONG ulReason, LPVOID lpReserved);

The ulReason parameter is passed to your function with one of the following values:
DLL_PROCESS_ATTACH

The DLL has just been loaded into the process, either during process creation or via dynamic loading.
DLL_PROCESS_DETACH

The DLL is about to be unloaded from the process, either during process termination or via dynamic unloading.
DLL_THREAD_ATTACH

A new thread has been created in the process.


DLL_THREAD_DETACH

A thread in the process is terminating. You can handle any or all of these events, as needed. If your DLL does not care about thread creation and destruction, you should call the function _NutDisableThreadLibraryCalls() in the DLL_PROCESS_ATTACH portion of your function, passing it the hDllHandle parameter. This prevents your DLL from receiving the DLL_THREAD_ATTACH and DLL_THREAD_DETACH notifications, which reduces overhead on thread creation and destruction.
For full documentation on the the DllMain() function. see the Visual C++ on-line documentation.

A default DllMain() function is used if you do not implement one for your DLL. It simply calls _NutDisableThreadLibraryCalls() to reduce overhead. A DLL built with the NuTCRACKER Platform SDK can be loaded during program initialization (the case in which the import library was linked against the program), or dynamically at runtime (via dlopen()). There is one important thing to remember when developing a DLL that can be dynamically loaded. The Visual C++ compiler provides for compile-time definition of thread-specific data (via the __declspec(thread) keyword).

Dynamically Loadable DLLs

UNIX to Windows Porting Guide

107

Porting Shared Libraries

Unfortunately, Windows does not support this in a dynamically loaded DLL; if it is used, the DLL causes an access violation when it attempts to reference the data. Dynamically loaded DLLs must use run-time thread-specific data.

Exporting Data from DLLs


See Using Data Exported From DLLs on page 42 for a detailed discussion of this issue.

Exporting data from a DLL can present a significant challenge. The simplest solution is to use __declspec(dllexport) and __declspec(dllimport) with your data, exactly as you would for functions. This transparently exports your data. However, your data still cannot be used to statically initialize another global variable in C code, because the DLL import of data requires a pointer indirection. If you are using a module definition file, you can define a symbol with the DATA keyword to have it exported as data. However, you must still declare that variable with __declspec(dllimport) before you can access it. This is not required for functions, but is required for data. Where things get truly complicated, however, is in those cases where you cannot ensure that the user of your DLL will include your header file without manually declaring your data. For example, if you have an integer variable xyz exported from your DLL, and your users code has:
extern int xyz;

the users code fails to compile if you used __declspec(dllimport) in your header file, because the two definitions conflict. If you examine the MKS Toolkit UNIX API header files, you will find several instances where this problem occurs, because much legacy UNIX code declares global variables such as errno, optarg, and sys_errlist directly in code rather than including the appropriate header files. Other techniques for exporting data are required to deal with these situations. The first technique is to declare the variable with the CONSTANT keyword in the module definition file. This causes the address of the symbol to be exported with the name of the symbol. It also causes a linker warning, because this keyword is obsolete. It does, however, provide a mechanism to declare the variable that does not conflict with the definition in the user code. Rather than naming your variable xyz, you would name it xyz_dll, then declare it in your header file as:
#if defined(BUILD_DLL1) extern int xyz_dll; #define xyz xyz_dll #else extern int *xyz_dll; #define xyz (*xyz_dll) #endif

108

MKS Toolkit

Building Standalone DLLs

While ugly, this is fairly effective. However, the CONSTANT keyword is obsolete, and Visual C++ may stop supporting it at some point. The other technique is to export the variable through a function-return pointer. Using this technique, rather than having a variable xyz, you would export a function xyz_dll, as follows:
int *xyz_dll(void) { static int _xyz; return &_xyz; }

The declaration of this variable in your header file would then be:
extern int *xyz_dll(void); #define xyz (*xyz_dll());

This has the advantage of using the same definition inside and outside the DLL, while avoiding the obsolete CONSTANT keyword. However, it adds an extra level of function-call overhead. These examples show that exporting data from a DLL can be problematic. If at all possible, you should use the __declspec(dllexport) and __declspec(dllimport) compile-time directives.

Building Standalone DLLs


A standalone DLL is one that is designed for use outside a NuTCRACKER Platform application. Reasons to develop such DLLs might include creating a DLL-based product for use with native Windows programs, creating a DLL callable from other languages such as Visual Basic, or building COM objects or ActiveX controls. This section discusses how to develop such a DLL for the NuTCRACKER Platform that leverages your UNIX code while providing integration with the capabilities of the Windows environment.

Issues
For more information, see Preparing DLL Interfaces on page 110.

Building a DLL for use within a NuTCRACKER Platform application is straightforward; however, building a DLL to use with a non-NuTCRACKER Platform application requires planning and code preparation. In a NuTCRACKER Platform application, the NuTCRACKER Platform controls the program from its first instruction, and can prepare data structures and framework before your code executes. This enables UNIX environment issues such as signal handling to be prepared ahead of time. With a standalone DLL, each entry point to the DLL must assume that the NuTCRACKER Platform framework has not yet been established, and these entry points are required to establish the environment.

UNIX to Windows Porting Guide

109

Porting Shared Libraries

Another concern with a standalone DLL involves configuration of the NuTCRACKER Platform. Because more than one standalone DLL for the NuTCRACKER Platform may be loaded into an application, or a standalone DLL may be loaded into a NuTCRACKER Platform application, you should avoid any global NuTCRACKER Platform configuration options. For example, when developing a standalone DLL, you should not assume that files are in text mode or binary mode, and you should not change the default mode. You must open files in the mode you need, or if you are accepting open file descriptors on an interface, your code should handle the files in either mode. You should not depend on any NuTCRACKER Platform environment variables to configure the behavior of your standalone DLL. You can, of course, use standard UNIX environment variables (such as DISPLAY or HOME). When it comes time to package and redistribute your standalone DLL, remember that your DLL is not self-contained. It depends on the NuTCRACKER Platform, just as a NuTCRACKER Platform application does. Hence you must package, distribute, and install the NuTCRACKER Platform, in accordance with your distribution license.

Preparing DLL Interfaces


For information on inserting _NutEnableNuTC() and _NutDisableNuTC(), see Calling Back Into NuTCRACKER Code From Win32 Code on page 44.

For a standalone DLL, each interface function must use _NutEnableNuTC() and _NutDisableNuTC(). For your standalone DLL, you can either insert these calls into your code, or you can generate wrapper functions to call your actual function. Using the module definition file, it is relatively straightforward to build these wrappers without modifying your existing code. For example, if you have a DLL function with this prototype:
int mydllfunc1(type1 arg1, type2 arg2, type3 arg3);

you would implement the wrapper for this function as:


int wrap_mydllfunc1(type1 arg1,type2 arg2,type3 arg3) { int rtn; _NutEnableNuTC(NULL); rtn = mydllfunc1(arg1, arg2, arg3); _NutDisableNuTC(); return rtn; }

To cause the linker to export the wrapper function with the name of your DLL function, put the following in your module definition file:
mydllfunc1 = wrap_mydllfunc1

There are two scenarios in which wrapper functions do not work well: Functions that take a variable number of arguments.

110

MKS Toolkit

Building Standalone DLLs

Exporting C++ functions. Functions that take a variable number of arguments should be modified so that the va_list argument is correctly passed through the wrapper. Given a function such as:
int mydllfunc2(const char *arg1, ...) { va_list args; va_start(arg1, args); <body of function> }

you would need to rewrite this as follows to have the function callable both inside the DLL and from outside the DLL:
int mydllfunc2_body(const char *arg1, va_list args) { <body of function> } int mydllfunc2(const char *arg1, ...) { va_list args; va_start(arg1, args); return mydllfunc2_body(arg1, args); } int wrap_mydllfunc2(const char *arg1, ...) { int rtn; va_list args; va_start(arg1, args); _NutEnableNuTC(NULL); rtn = mydllfunc2_body(arg1, args); _NutDisableNuTC(); return rtn; }

with this line added to the module definition file:


mydllfunc2 = wrap_mydllfunc2
For more information, see Exporting C++ Functions from DLLs on page 106.

For C++ functions, because of the issues with decorated function names, you cannot easily use a module definition file, and hence cannot easily use the name aliasing shown above. So you should change the name of your C++ function, and write the wrapper function with the name you want exported from the DLL, or call _NutEnableNuTC()/_NutDisableNuTC() directly. A standalone DLL can be called from other languages, such as Visual Basic. To make your DLL callable from Visual Basic, you need to make one further change to your interfaces. Visual Basic requires that all functions from external DLLs be declared with the __stdcall calling convention. When this keyword is added to the definition and declaration of a function, it tells the compiler to use a different

Special Scenarios
See the Visual Basic program provided with the DLL sample set for an example of preparing your DLL for use with Visual Basic.

UNIX to Windows Porting Guide

111

Porting Shared Libraries

convention for passing parameters to the function. It also causes the function name, by default, to be decorated with a number that indicates the size of the parameter list. Because of this decoration, it is best to use a module definition file to specify the name by which you want the function exported. This prevents the Visual Basic user from needing to be concerned about the decoration when declaring the interface in a Visual Basic application. Another UNIX programming capability that can be used with a standalone DLL, is the handling of asynchronous signals, such as might be generated via an interval timer established with setitimer(). By combining the techniques discussed in this chapter with some POSIX Threads programming, you can establish a handler for your timer that operates even when the users program is not running NuTCRACKER Platform code.
See Porting Threaded Applications on page 115, and to the DLL sample set for examples of how to use this technique (the Visual Basic sample uses this technique to handle an interval timer while Visual Basic is running).

The basic architecture is to start a POSIX thread that does nothing but wait for your signal to arrive using the sigwait() function, then performs the actions that are traditionally performed by your signal handler. Keep in mind that signals and interval timers are process-wide resources. Hence it is not inconceivable to have more than one standalone NuTCRACKER Platform DLL trying to set up interval timers in the same application. This takes careful coordination. Certain functions in the MKS Toolkit UNIX APIs behave differently in a standalone NuTCRACKER Platform DLL than in a NuTCRACKER Platform application. You should modify your code accordingly. The differences are: You cannot call fork() from a standalone DLL. A call to fork() fails with errno set to EAGAIN if the application is not a NuTCRACKER Platform application. Because the NuTCRACKER Platform does not control the process, it cannot guarantee that a child process would have a valid address space, and hence the operation is not allowed. You cannot call the exec() family of functions from a standalone DLL, except from the child of a vfork() operation. A call to one of the exec() functions from a standalone DLL fails with errno set to ETXTBSY. Because the NuTCRACKER Platform does not control the process, it disallows replacing it with an exec() call. You can call the _NutForkExec() family of functions, call exec() from the child of a vfork(), call popen(), or call system() if you need to run another process. If the application is not a NuTCRACKER Platform application, the process does not exit when the last POSIX thread exits. Because there may be other Win32 threads active in the process, the NuTCRACKER Platform cannot exit when its last thread exits (like it can when the NuTCRACKER Platform controls the application).

MKS Toolkit UNIX API Differences

112

MKS Toolkit

Building Standalone DLLs See Special Scenarios on page 112 for techniques to use when you need to handle signals where the application is running outside your DLL.

Asynchronous signals are queued until the next time a NuTCRACKER Platform thread is running.

UNIX to Windows Porting Guide

113

Porting Shared Libraries

114

MKS Toolkit

Porting Threaded Applications


See the MKS Toolkit UNIX APIs Reference for details on each function that the NuTCRACKER Platform supports.

The NuTCRACKER Platform implements the POSIX threading API

(PThreads) as defined in POSIX 1003.1 (1996) (formerly known as POSIX 1003.1c), along with a subset of the extensions added to the UNIX 98 specification (also known as Aspen Threads). This chapter discusses the NuTCRACKER Platform PThreads implementation, how it relates to threading implementations on other UNIX platforms, and how it relates to native Win32 threads. For additional information on thread programming, we recommend the following publications: Multithreaded Programming with Win32, by Thuan Q. Pham and Pankaj K. Garg (Prentice Hall PTR, 1996). Multithreading Programming Techniques, by Shashi Prasad (McGrawHill, 1997).

NuTCRACKER Platform POSIX Threads Implementation


This section discusses the NuTCRACKER Platform implementation of POSIX threads, the status of POSIX optional features and UNIX 98 threads extensions, and the POSIX threads extension functions added in the NuTCRACKER Platform.

NuTCRACKER Platform Threads

The NuTCRACKER Platform POSIX threads implementation derives from the POSIX 1003.1 (1996) standard. POSIX threads in the NuTCRACKER Platform are implemented on native Win32 threads. This provides optimum interoperability with the Win32 operating environment and significantly reduces the overhead for threads performance. However, Windows does not support all the features necessary to implement all the advanced optional POSIX threads features.

UNIX to Windows Porting Guide

115

Porting Threaded Applications See NuTCRACKER Platform POSIX Threads and Win32 Threads on page 123 for information on how NuTCRACKER Platform POSIX threads and native Win32 threads interact.

Threads are kernel-level objects in Win32, and each thread is scheduled in relation to all other threads in the system. Windows NT/2000/XP/2003 supports SMP hardware implementations, providing true concurrent threading. NuTCRACKER Platform implements all core POSIX thread functions, as well as the core thread-safe (re-entrant) functions, as specified in POSIX 1003.1 (1996). This covers the following function groups: Thread attribute objects Thread creation and destruction Thread cancellation Thread-specific signals Thread-specific data Mutex objects Condition variable objects

Optional POSIX Threads Features

The POSIX specification defines several optional threads features; each is identified by a compile-time constant. For supported optional features, the specified constant is defined with the value 1 in <unistd.h>; the specified constant is not defined for unsupported optional features. The NuTCRACKER Platform supports the following optional features:
_POSIX_THREADS

Specifies that all core threads functionality is supported.


_POSIX_THREAD_SAFE_FUNCTIONS

Specifies that the core set of defined re-entrant functions (such as strtok_r()) are supported.
_POSIX_THREAD_ATTR_STACKSIZE

Specifies that the stack-size thread attribute is supported.


_POSIX_THREAD_PRIORITY_SCHEDULING

Specifies that the implementation supports setting thread-specific priority and scheduling attributes.

Note Currently, the NuTCRACKER Platform only supports the

SCHED_OTHER scheduling class.

116

MKS Toolkit

NuTCRACKER Platform POSIX Threads Implementation

The NuTCRACKER Platform does not support the following optional features:
_POSIX_THREAD_ATTR_STACKADDR _POSIX_THREAD_PRIO_INHERIT _POSIX_THREAD_PRIO_PROTECT _POSIX_THREAD_PROCESS_SHARED

UNIX 98 (Aspen) Threads Extensions

By the time the POSIX threads specification was finished, several UNIX vendors had already implemented extensions to the standard. These companies formed the Aspen group to rationalize the extensions, and the results of their effort are part of the UNIX 98 standard. The NuTCRACKER Platform supports the following UNIX 98 threads extension: Multiple types of mutexes, including recursive and error-checking mutexes. The NuTCRACKER Platform does not support the following UNIX 98 threads extensions: Read/write locks as core synchronization objects. Concurrency-level setting for threads implementations that allow multiplexing multiple user-space threads on a single kernel-space thread object. Stack guard-page size attribute. Overlapped read/write operations via the pread() and pwrite() functions.

UNIX 03 Threads Extensions

The NuTCRACKER Platform supports the following UNIX 03 threads extensions: Spinlocks are implemented as a very fast simple wrapper around InterlockedExchange that bypasses the system call layer. As a result, spinlocks are not visible in a truss log; however, they are very fast. This implementation also includes NuTCRACKER extensions for spinlock naming. Fully conforming Reader/Writer locks with NuTCRACKER extensions to add names. Fully conforming Barriers from the Realtime specification.

UNIX to Windows Porting Guide

117

Porting Threaded Applications

NuTCRACKER Platform POSIX Threads Extensions

The NuTCRACKER Platform adds functions to let you set and query symbolic names on threads, mutexes, and condition variables. This is useful in debugging threaded applications, because you can debug thread objects by name rather than by an arbitrary number. The process command displays these symbolic names in its thread display, if they have been set by the program. The functions that support symbolic names are:
pthread_setname_np()/pthread_getname_np() pthread_cond_setname_np()/pthread_cond_getname_np() pthread_mutex_setname_np()/pthread_mutex_getname_np()

Because this code cannot be ported to any UNIX implementation, you should always bracket these extensions with:
#ifdef __NUTC__ #endif

Threaded X Applications

The NuTCRACKER Platform supports threaded X applications, using POSIX threads and the mechanisms supplied with X11R6. Refer to your X documentation or the Programmers Supplement for Release 6 of the X Window System (OReilly & Associates, 1995) for documentation on writing threaded X applications.

Threads Implementations on Popular UNIX Platforms


The POSIX threads specification went through ten drafts prior to final acceptance. Because of this, operating system vendors implemented various drafts of the specification. In addition, several alternative threading implementations were deployed on various UNIX platforms. This section discusses these implementations and the UNIX platforms that support them. You may find this information useful in understanding the issues involved in porting threaded applications to the NuTCRACKER Platform from UNIX as well as between UNIX platforms.

Other POSIX Threads Implementations

Only two drafts of the specification have widely available implementations. The Open Software Foundation (OSF) implemented Draft 4 in its Distributed Computing Environment (DCE) programming environment. Although the terms DCE threads and POSIX threads are often used interchangeably in older literature, this usage is incorrect. The Draft 4 API differs significantly from the final specification: many changes were made to

118

MKS Toolkit

Threads Implementations on Popular UNIX Platforms

parameter types, and return values changed completely. Additionally, the final specification added significant new features beyond those provided for by Draft 4. The other common implementations of POSIX threads are done to the Draft 10 specification and later integrated into the core specification as part of POSIX 1003.1 (1996)(which was certified as POSIX 1003.1c in 1995). This specification, in turn, is part of the UNIX 98 specification, which includes some additional features. The extended version is known as Aspen threads. The following table shows the POSIX threads specification draft for a variety of popular UNIX implementations.
Implementation AIX 3.2.5 AIX 4.x, x < 3 AIX 4.x, x >= 3 DG/UX 5.4 Digital UNIX 3.2 Digital UNIX 4.0 HP/UX 9.x HP/UX 10.x, x < 30 HP/UX 10.30, 11.x IRIX 6.x, x >= 3 Solaris 2.x, x >= 5 Transarc DCE POSIX Threads Draft Draft 4 (DCE) Draft 7 Draft 10 Draft 6 Draft 4 (DCE) Draft 10 Draft 4 (DCE) Draft 4 (DCE) Draft 10 + Aspen Draft 10 Draft 10 Draft 4 (DCE)

UNIX International (Solaris) Threads

During the POSIX threads standardization, UNIX International (UI) developed a competing threading API specification. The most prevalent implementation of this API is on Solaris (2.3 and later releases). Hence, this threading API is commonly referred to as Solaris Threads. However, the same API is also implemented on SCO UnixWare 2.x, so the term UNIX International Threads is used to remove any platform-specific ambiguity. UI Threads are similar to POSIX threads. POSIX threads supports thread cancellation, which is not part of UI Threads. UI Threads support thread suspension/resumption, read/write locks, and semaphores, which are not part

UNIX to Windows Porting Guide

119

Porting Threaded Applications

of POSIX threads, although read/write locks are part of the UNIX 98 Aspen extensions, and semaphores are part of the POSIX real-time extension (POSIX 1003.1b, also part of POSIX 1003.1 (1996)). As of Solaris 2.5, both POSIX threads and UI Threads are supported. UnixWare does not currently implement POSIX threads.

Other Threading Packages

Two other threading implementations are available on popular UNIX platforms. SunOS 4 has a light-weight process (-llwp) package that provides rudimentary threading capabilities. This threading package is nonpreemptive, and bears little correlation to either POSIX threads or UI threads. Because of this, many programmers use the Transarc implementation of DCE threads for threaded programming on SunOS 4. Silicon Graphics IRIX operating system provides a low-level kernel threading model referred to as sproc threads (named after the sproc() function, which is used to create a thread). This threading model is lowlevel, providing limited tools to the user. It also bears little correlation to either POSIX or UI threads. As of IRIX 6.3, POSIX threads are supported natively on SGI platforms.

Porting Threaded Software from UNIX to NuTCRACKER Platform


This section discusses porting applications based on various threads implementations to the NuTCRACKER Platform. The table above shows the mapping from a threads implementation to a POSIX draft. As a general threads porting issue, you should be aware that the POSIX specification leaves the default settings for attribute objects as implementation-defined. In other words, you should not expect that the attribute settings in a default attribute object are the same on each platform. Writing portable POSIX threads applications requires that you take this into account by explicitly setting any attribute that could be of concern. Examples of problematic attributes whose defaults vary between systems include the detached state for newly created threads, and the schedulerparameter inheritance attribute. The default settings for each type of attribute object are documented on the pthread_XXX_init() reference pages.

Porting Draft 10 POSIX Threads

Code written to the final 1003.1c/1003.1 (1996)/Draft 10 POSIX threads implementation should port to the NuTCRACKER Platform without any changes, assuming that code that depends on optional POSIX threads features is correctly bracketed by the defined feature-test macros (for

120

MKS Toolkit

Porting Threaded Software from UNIX to NuTCRACKER Platform

example, the program should only attempt to create a process-shared synchronization object if the _POSIX_THREAD_PROCESS_SHARED macro is defined). If unsupported optional features are used, the functions that implement those functions return ENOSYS. If the error conditions are not handled, the program may silently fail as defined by POSIX.

Porting Draft 7 POSIX Threads

Draft 7 of the POSIX threads specification was close to the final specification; later drafts mostly just added more functions. However, there are a few semantic differences to be aware of when porting code based on Draft 7: Prior to Draft 10, multiple threads could call pthread_join() on a single thread. With Draft 10, at most one thread may join on another thread. Draft 7 has the function sigthreadmask(), while Draft 10 has the function pthread_sigmask(), which is semantically identical. The symbolic constant PTHREAD_CREATE_UNDETACHED was changed to PTHREAD_CREATE_JOINABLE in Draft 10. Draft 7 has the function pthread_yield(), which causes the currently running thread to give up control of the processor. Draft 10 has the sched_yield() function to perform the same function.

Porting Draft 4 (DCE) POSIX Threads

Draft 4/DCE Threads differ significantly from the final POSIX threads specification. In addition to the changes noted above between Draft 7 and Draft 10, the standards committee made significant changes to the thread API between Draft 4 and Draft 7, adding several functions and renaming and changing parameter types for many others. Moreover, they changed the handling of function return values. Prior to Draft 7, functions returned 0 on success, -1 on error, and set errno to indicate the specific error. From Draft 7 on, these functions return 0 on success, and the error number on error, without touching errno. The scope of these changes is too broad to cover in this document. DCE Threads added several capabilities to the Draft 4 specification. These changes fall into two broad categories: API additions and exception handling. The API additions all take the form pthread_XXX_np() (np: non-portable). Much of this functionality was adopted for later drafts of the standard. The exception handling mechanisms from DCE were not adopted by the standards committee, and do not exist for any thread implementation other than DCE threads.

See the readme.txt file included with the DCE Threads emulation layer for detailed instructions on how to use it.

Because these API differences could cause significant code changes when porting, the NuTCRACKER Platform has a tool to assist in porting DCE threads. In the samples/threads/dce_thr directory of the MKS Toolkit

UNIX to Windows Porting Guide

121

Porting Threaded Applications

CD is the source code for a DCE Threads emulation layer. This emulation layer provides an API mapping from DCE Threads to POSIX threads. This layer only maps the APIit does not provide the semantics of DCE Threads. For example, pthread_join() called through the emulation layer lets only one thread join on a given thread ID, as specified by POSIX, rather than allowing multiple threads to join on a given thread ID, as is allowed by DCE Threads. Because there is no POSIX threads equivalent of the DCE Threads exception handling mechanism, the emulation layer does not support this.

Porting UNIX International (Solaris) Threads


See the readme.txt file included with the UI Threads emulation layer for detailed instructions on how to use it.

The API for UNIX International Threads is completely different from the POSIX threads API, although the two packages share similar semantics. Because these API differences could cause significant code changes when porting, NuTCRACKER Platform has a tool to assist in porting of applications based on UI threads. In the samples/threads/ui_thr directory of the MKS Toolkit CD is the source code for a UI Threads emulation layer. This emulation layer provides an API mapping from UI Threads to POSIX threads. This layer only maps the APIit does not provide the semantics of UI Threads. For example, the thr_join() function in UI Threads can wait on any thread by passing 0 for the thread ID. Because POSIX threads provides no such capability, this mechanism is not supported by the emulation layer. The emulation layer provides no support for suspending and resuming threads, because these capabilities do not exist in POSIX threads. However, it supports the read/write locks and semaphores specified in UI Threads by implementing them in terms of POSIX threads synchronization objects in the emulation layer.

Porting Other Threading Packages

The NuTCRACKER Platform provides no assistance for porting code based on other thread packages (such as SGI sproc threads or SunOS -llwp threads). You must rewrite that code that depends on inherently non-portable packages in terms of POSIX threads APIs. Rewriting to the POSIX APIs has the added advantage of providing an implementation that ports easily to other UNIX platforms.

122

MKS Toolkit

NuTCRACKER Platform POSIX Threads and Win32 Threads

NuTCRACKER Platform POSIX Threads and Win32 Threads


To provide the best possible interoperability with Win32 applications and tools, the NuTCRACKER Platform POSIX threads implementation is built on Win32 thread primitives. The most visible sign of this interoperability is that the thread ID returned by pthread_create() is actually the thread ID of the underlying Win32 thread. This makes debugging a threaded NuTCRACKER Platform application as simple as debugging a native Win32 threaded application. The debugger tools for examining and manipulating threads work exactly the same with the NuTCRACKER Platform threads as they do with Win32 threads. Unfortunately, POSIX and Win32 synchronization objects have too little in common to interoperate. It is not possible, for example, to use pthread_mutex_lock() on a Win32 Mutex handle, nor is it possible to use WaitForMultipleObjects() to wait for a NuTCRACKER Platform pthread_mutex_t object. For this reason, among others, applications should not mix Win32 and UNIX thread and synchronization functions in the same module (that is, either an executable or a DLL). That said, it is reasonable to mix Win32 threaded code with NuTCRACKER Platform threaded code in the following circumstances:
See Process Control on page 3 for other issues that may effect mixing Win32 threaded coded with NuTCRACKER Platform threaded code.

Win32 DLLs that create threads should work correctly within the context of a threaded NuTCRACKER Platform application. In other words, when writing threaded NuTCRACKER Platform applications, you do not need to worry about Win32 DLLs creating Win32 threads. The two sets of threads can coexist without interference. NuTCRACKER Platform code can be called inside a Win32 thread by using the _NutEnableNuTC()/_NutDisableNuTC() functions to morph the Win32 thread into a NuTCRACKER Platform thread. This operation creates the appropriate data structures for the thread that would normally have been created if pthread_create() were called from a NuTCRACKER Platform application. The NuTCRACKER Platform has no equivalent to Win32 fibers, which are lightweight user-space threads, that are cooperatively scheduled (that is, a fiber retains control of the processor until it chooses to release it or calls a blocking Win32 operation). Calling _NutEnableNuTC()/_NutDisableNuTC() from a fiber is not supported. Other than this restriction, fibers can be used by native Win32 code in parallel with the NuTCRACKER Platform threads, but fibers should not be used within NuTCRACKER Platform threads.

For more information, see Calling Back Into NuTCRACKER Code From Win32 Code on page 44.

UNIX to Windows Porting Guide

123

Porting Threaded Applications

While you can get a Windows handle to a NuTCRACKER Platform thread using the GetCurrentThread() function, and then manipulate the NuTCRACKER Platform thread using Win32 functions, this is not supported by the NuTCRACKER Platform. Program behavior is undefined if Win32 thread API calls are made on NuTCRACKER Platform threads created by pthread_create() or converted via _NutEnableNuTC()/_NutDisableNuTC().

Reducing Porting Complexity


Threads can reduce the complexity of porting certain applications, while maintaining a high level of portability between the NuTCRACKER Platform and other UNIX implementations. The procedures discussed here considerably simplify certain porting tasks.

Implementing Signal Handlers

The sigwait() function, combined with threads, provides a convenient way to handle an asynchronous signal in a synchronous fashion. Using this mechanism can remove the need to handle EINTR error returns from system callsthe functions are not be interrupted because the signal is being handled in another thread. This can significantly reduce the overall complexity of your code. Because many Win32 functions are not interruptible, the NuTCRACKER Platform must do extra work to support interrupting these operations. Other operations cannot be correctly restarted, so some functions that are restartable on some UNIX platforms may not be with the NuTCRACKER Platform. So the use of sigwait() and a signal catching thread can reduce the overhead of a NuTCRACKER Platform-ported application, and results in flexible code directly usable on many UNIX platforms as well. Here is the basic framework for using sigwait() and threads to handle signals: In the application initialization, set the process signal mask to block all signals that are handled with sigwait(), using sigprocmask() or pthread_sigmask(). Create one or more signal handling threads. Because sigwait() returns the signal number that woke it up, a single thread can process multiple signals if desired. In the thread initialization, create a signal mask containing the set of signals to be handled. The thread function should then loop, and at the top of the loop should call sigwait() with this signal mask as an argument.

124

MKS Toolkit

Reducing Porting Complexity

After sigwait() returns, process the signal that occurred using the code that would normally be in your signal handler functions. The following example responds to SIGUSR1 to display statistics from the running application, and to SIGUSR2 to reset the statistics (this example is derived from a similar example in the OReilly Pthreads Programming book):
Main program framework: pthread_t stats_thread; pthread_mutex_t stats_lock1=PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t stats_lock2=PTHREAD_MUTEX_INITIALIZER; main() { . . . sigset_t sigs_to_block; . . . // Set main threads signal mask to block SIGUSR1 // and SIGUSR2. Other threads inherit this mask // and have them blocked. sigemptyset(&sigs_to_block); sigaddset(&sigs_to_block, SIGUSR1); sigaddset(&sigs_to_block, SIGUSR2); pthread_sigmask(SIG_BLOCK, &sigs_to_block, NULL); . . . pthread_create(&stats_thread, NULL, report_stats, NULL); . . . } Signal-handling thread framework: void *report_stats(void *p) { sigset_t sigs_to_catch; int caught; sigemptyset(&sigs_to_catch); sigaddset(&sigs_to_catch, SIGUSR1); sigaddset(&sigs_to_catch, SIGUSR2); for (;;) { sigwait(&sigs_to_catch, &caught); pthread_mutex_lock(&stats_lock); switch(caught) { case SIGUSR1: display_stats(); break; case SIGUSR2: reset_stats(); break; }

UNIX to Windows Porting Guide

125

Porting Threaded Applications

pthread_mutex_unlock(&stats_lock); } }

An important point to remember is that this method can cause the signal handler thread and the main thread to run in parallel. Therefore, you should protect shared data with mutexes. While this seems complex, it actually provides far better control over shared data than you can normally achieve in signal handlers. This way, you control access to the data. With traditional signal handlers, the handler is called at an indeterminate point, which can lead to data corruption (this is why it is dangerous to call malloc() or printf() from inside a signal handler).

Using Threads In Place of fork()

As discussed elsewhere in this manual, fork() is an expensive operation, because of limitations in the Win32 process model. In many instances, you can replace fork() with vfork()/execX(), or _NutForkExecX(). However, there are other instances where this is not a valid solution. For example it is common to implement server processes by having the server process loop accept connections, then fork() a child to handle each request. This can be expensive on most UNIX implementations; on Windows, it is especially so. Threads can provide a convenient and portable solution to this problem. By creating threads to handle user requests, rather than processes, the overhead to handle each request is greatly reduced. However, because the threads share a common address space, some changes are required in the server code. At a minimum, synchronization objects are needed to protect shared data. In some applications, the data structures themselves may need to be changed to support multiple transactions in the same process. In the end, you must decide which approach provides the best cost/performance ratio. The NuTCRACKER Platform supports a direct port of the UNIX server, although the fork() overhead may be high. Alternatively, if you rewrite the code using threads, you can achieve significant performance improvements both with the NuTCRACKER Platform and on other UNIX platforms.

126

MKS Toolkit

Reducing Porting Complexity

UNIX to Windows Porting Guide

127

Porting Threaded Applications

128

MKS Toolkit

Porting Daemons

10

This chapter describes porting a UNIX daemon process to Windows with

the NuTCRACKER Platform. Windows refers to these processes as services. Windows NT/2000/XP/2003 provides a Service Control Manager that controls starting and stopping services. Windows Me has a simpler architecture, that provides a list of programs to be invoked automatically when the system boots.

See 00readme.txt in the


samples/tutorial/service

directory on the MKS Toolkit CD for more information on this framework.

MKS Toolkit for Professional Developers and MKS Toolkit for Enterprise Developers come with a NuTCRACKER Platform service framework for building services from your daemon programs, plus a copy of the UNIX inetd daemon ported using this framework. This framework is found in the samples/tutorial/service directory on the MKS Toolkit CD. With it, you can build a single service binary that works on both Windows NT/2000/XP/2003 and Windows Me.

Concepts
Windows NT/2000/XP/2003 and Windows Me treat services differently. This section discusses those differences.

Windows NT 2000/XP/2003

The Windows NT/2000/XP/2003 Service Control Manager maintains a database of all registered services in the system. This database contains information such as: The executable that is providing the service; a single executable can provide multiple services on Windows NT/2000/XP/2003. When the service should be started (for example, boot time, on demand, or never). The severity level for service start failures. A list of other services the service depends on, so that service startup can be ordered correctly.

UNIX to Windows Porting Guide

129

Porting Daemons

User account information identifying the user context in which the process is to run. When a service is installed, it is registered in the Service Control Manager database. This installation verifies dependences, to ensure that dependence loops are not created. When a service is uninstalled, it must be removed from the Service Control Manager database. The service database can be modified by users with appropriate permissions, using the Services control panel applet, or using the Server Manager application, which allows manipulation of services on remote systems (both for NT 4.0) or the computer management tool. In addition, services can be started and stopped using the net start and net stop commands.

Windows Me

Windows Me does not have a Service Control Manager. Instead, a list of services to be run at boot time is maintained in the registry, under the key:
HKLM\Software\Microsoft\Windows\CurrentVersion\RunServices

Each executable listed is run when the system starts, and no control facilities are available as they are on Windows NT/2000/XP/2003. What distinguishes a service from any other process on Windows Me is that it is not killed when you log out, and it does not appear in the task list that is displayed when you press Ctrl-Alt-Del. Because there is no Service Control Manager to aid in starting and stopping your service on Windows Me, you may want to provide a tool to assist users to do this manually.

Converting a Daemon to a Service


Porting a UNIX daemon to Windows consists of the following steps, covered in detail in the sections below. This section provides an overview of the porting process; for specifics on the framework itself, refer to the sample code. 1. Port your daemon as a standard NuTCRACKER Platform application, to resolve any general porting issues, before converting the application to a service. 2. Copy the NuTCRACKER Platform service framework code to your build directory, configure the framework through the provided configuration header file, and add the framework to your build process. 3. Test the service in debug mode, to ensure the framework is correctly integrated with your service code.

130

MKS Toolkit

Converting a Daemon to a Service

4. Install and test the service. 5. Prepare your service for distribution.

Porting an Application

Porting a daemon is largely the same as porting any other general application.You should convert your daemon to a standalone application, by removing the daemon-creation code (for example, fork() followed by setpgrp() followed by closing open files). The NuTCRACKER Platform service framework handles this by wrapping your application with its own startup code. You should verify that your application is working correctly before adding the framework, because debugging a service can be complex. Once integrated with the framework, your application is a Windowssubsystem application, which means that stdin, stdout, and stderr, by default, are no longer connected to a console. The framework provides a debug mode, in which a console is attached to your process so you can interact with it. The NuTCRACKER Platform service framework has two parts: a C header file that you edit to tailor the framework for your service, and a C source file that you compile into your application to provide the service interaction. Refer to the framework header file and accompanying documentation for specific information on the configuration parameters. The discussion here is restricted to concepts. The framework wraps around your applications main() functionthe first step for integrating the framework is to rename your main() function to user_main(). The frameworks main() function provides command-line processing, and accepts the following arguments:
-install [-verbose|-quiet|-user username|-password password|-desktop]

See The Porting Process on page 31 for general porting advice.

The NuTCRACKER Platform Service Framework

Use this option to register the service with the Service Control Manager (on Windows NT/2000/XP/2003) or the OS (on Windows Me). If you add the -verbose option, a status dialog is displayed even if no errors occur. The -quiet option causes status and error output to be directed to stdout, which is not visible unless I/O is redirected. The -user and -password options are used to specify the user name and password of the account under which the service should run. The -desktop option tells the Service Control Manager to let the service interact with the desktop. The -user, -password, and -desktop options are ignored on Windows Me.
-remove [-verbose|-quiet]

Use this option to deregister the service from the Service Control Manager (on Windows NT/2000/XP/2003) or the OS (on Windows 131

UNIX to Windows Porting Guide

Porting Daemons

Me). If you add the -verbose option, a status dialog is displayed even if no errors occur. The -quiet option causes status and error output to be directed to stdout, which is not visible unless I/O is redirected.
-debug
See Debugging a Service on page 133 for more information.

Use this option to run the service in debugging mode. This causes the service to run interactively; the framework attaches a console that lets you interact with the service. Any additional command-line arguments are passed to your (renamed) main function. If none of these arguments is at the start of the command-line, the framework assumes it has been invoked as a service (as opposed to debug mode, or to process a registration command). Any command-line arguments are passed to your main function. The following configuration options are available in the frameworks header file. Most default values are appropriate for your service; avoid making changes unless absolutely necessary. The internal and display names. The display name is the name by which users refer to your service (for example, in the Services control panel applet, or net start command). The internal name is the token used to identify your service in the Service Control Manager database. The internal name can be the same as the display name, but it must consist solely of alphanumeric characters, and must contain no spaces. The proper start up order for your service: Windows NT/2000/XP/2003, with its more complex Service Control Manager, uses a service dependence list to ensure that your services start in the correct order. (Your service may depend on other services to start properly.) Windows Me cannot handle service dependences services are started in the order they were installed. Therefore, you should ensure that the NuTCRACKER Platform is installed before you register your service. When your service should be started: Whether your Windows NT/2000/XP/2003 service should start automatically when the system boots, or only when requested. Windows Me services are always started at boot time. Parameters that control how your service is notified when it is being shut down.

132

MKS Toolkit

Converting a Daemon to a Service

The name of your service main function, and optionally the names of the usage-message and process-cleanup functions that the framework calls, if provided.

Note This framework does not make use of all of the capabilities of the SCM (for example, pausable services). In particular, the framework supports only a single service in an executable, and uses default error handling.

Debugging a Service

Once your service is integrated with the framework, you should run it using the -debug command-line option, which causes your service to run interactively, displaying a console window in which you can display debugging information (using standard I/O streams). In the event that you are using Windows Installer to deploy your application, you may instead create the appropriate entries in the ServiceControl and ServiceInstall tables of the Windows Installer database. To run the service under the debugger, use a command such as:
msdev myservice.exe debug

Debugging your service when it is running as a service can be difficult. Some releases of Windows NT/2000/XP/2003 do not let you attach a debugger to a running service process. You must do the following to debug the running service: For Windows NT/2000/XP/2003, change the Startup parameters for your service in the Services control panel applet to give your service access to the desktop. You should restart the service if it is running when you make this change. Add a call to _NutDebugBreak() at the beginning of your service, or at any point at which you want to attach the debugger. This causes a dialog to appear, allowing you to attach the debugger to the running process.

Installing and Testing a Service

Before you install your service, you should make an Emergency Recovery Disk (on Windows NT/2000/XP/2003) or a Registry Backup (on Windows Me), to ensure that you can recover your system safely if your service startup causes the system to fail to boot. This is not likely, but it is a wise precaution in the event that something goes wrong. Install your service by running it with the -install command-line option: On Windows NT/2000/XP/2003, start your service from the Services control panel applet, or with the net start command.

UNIX to Windows Porting Guide

133

Porting Daemons

On Windows Me, run your service executable manually. Then verify that your service is correctly running, using whatever test procedures are appropriate. Verify that your service shuts down correctly: On Windows NT/2000/XP/2003, stop your service from the Services control panel applet, or with the net stop command. On Windows Me, the service runs until the system is rebooted, unless you use an external mechanism to shut it down (the kill command works, if you do not provide another mechanism). The final validation step is to reboot your system to ensure that the service starts and runs correctly at system startup.

Distributing a Service

Distributing and installing your service is straightforward. Because the service is self-installing, and self-removing, your installation and removal programs can simply run the service executable with the appropriate option after installing the executable file.

134

MKS Toolkit

Porting Applications to 64-bit Windows

11

This chapter discusses the process of porting UNIX applications to the 64bit Windows platform (Win64) using MKS Toolkit for Enterprise Developers 64-bit Edition. Information is provided on porting to both the Intel IA64 architecture and extended 64-bit architectures. Extended 64-bit architectures include the AMD Opteron and AMD Athelon (oftentimes discussed in the press as AMD64) as well as Intel processors with 64-bit Extension Technology.

The compiler, linker, and all other tools required for development on both IA64 and extended 64-bit architectures are all 32-bit applications. This makes it possible to do cross-development using inexpensive x86 hardware, should you choose to do so. For the most part, the porting process for 64-bit applications is the same as the porting process for 32-bit applications. However, there are some important differences of which you should be aware.

IA64 Support
At press time, the Microsoft Platform SDK could be freely downloaded at http://
www.microsoft.com/ msdownload/platformsdk/ sdkupdate/.

While, at the time of writing, Microsoft had not released a Visual Studio for targeting 64-bit development, the Microsoft Platform SDK has a command line compiler that can be effortlessly used with the NuTCRACKER development process. You do not need to download the entire SDK, but can select which components you wish to install. In this case, you must download at least the 64-bit compilation environment. This environment includes the compiler, linker, assembler, header files and link libraries that are required to compile and link native Windows applications. You can also install and use the platform SDK on an Itanium machine and use the compiler as if it were a native compiler. You should install the Platform SDK before you install MKS Toolkit for Enterprise Developers 64-Bit Edition. The release notes included with the Platform SDK which are specific to the 64-bit build environment are normally found in the bin\win64 directory.

UNIX to Windows Porting Guide

135

Porting Applications to 64-bit Windows For more information on support for Intel compilers, contact MKS Customer Support.

In addition, support for the Intel C++ 8.0 compiler for the IA64 architecture is available from MKS upon special request.

Extended 64-bit Support


Like the IA64 architecture, there is not yet a released version of Microsoft Visual Studio for extended 64-bit architectures. However, the Microsoft Windows Server 2003 DDK contains a compiler suitable for use in the NutTCRACKER development environment. The DDK is currently available to MSDN subscribers via MSDN subscriber downloads. This environment includes the compiler, linker, assembler, header files, and link libraries that are required to compile and link native Windows applications for extended 64-bit architecture platforms. You can also install and use the DDK on extended 64-bit architecture machines and use the compiler as if it were a native compiler. You should install the DDK before you install MKS Toolkit for Enterprise Developers 64-Bit Edition. Beta versions of Windows XP and Windows Server 2003 for extended 64-bit architecture platforms are also available from MSDN Subscriber Downloads as well as through the appropriate beta channels at Microsoft. Because these versions of Microsoft Windows are still in a beta status, versions of MKS Toolkit for extended 64-bit systems should also be regarded as beta product.

Overview of the Process


The process of porting applications to 64-bit platforms involve several steps, most of which are identical to the porting process for 32-bit applications.
For more information on porting applications to the 32-bit NuTCRACKER Platform, see The Porting Process on page 31. For general instructions related to porting applications to a 64-bit version of UNIX. see Porting to 64-bit UNIX Platforms on page 143.

There are many aspects to porting an application to a 64-bit platform, and it is beyond the scope of this manual to provide a comprehensive guide to this development process. In general, you will find the porting process easier if you have already ported your software to the 32-bit NuTCRACKER Platform, and if the application is already 64-bit clean (that is, it has already been ported to a 64-bit version of UNIX). Most of the remainder of this chapter assumes that your application is already 64-bit clean and has been ported to the 32-bit NuTCRACKER Platform. Thus, only those issues specific to 64-bit versions of Windows remain. Key among these issues is the size of the long datatype. Various flavors of 64-bit UNIX use what is known as the LP64 model where both the long and pointer datatypes are 64-bits. All other datatypes are unchanged from the 32-

136

MKS Toolkit

Overview of the Process

bit UNIX systems. Microsoft uses the LLP64 model where only pointers become 64-bits on Win64 platforms, and all other datatypes remain unchanged. Thus, the long datatype is 64 bits on most 64-bit UNIX platform, while it is only 32 bits on Win64. Because this is not a configurable compiler option, a part of the process of porting to Win64 platforms is to identify those locations where this difference is important.

Determining the Scope of the Port

Probably the greatest amount of effort in porting to Win64 platforms is to identify and correct places where the assumption is made that the long datatype is capable of holding a 64-bit quantity. If there are no such instances in your application, the porting process may be quite easy. For example, the core GUI logic in many Motif/X11 applications appears to not require any changes. Correcting each individual instance is generally quite easy. The recommended procedure is to replace long with intptr_t, and unsigned long with uintptr_t. The intptr_t and uintptr_t derived datatypes are defined by the UNIX standard to be integral datatypes of a size large enough to hold a pointer. On 64-bit UNIX platforms, these types are often simply derived from long, while on the NuTCRACKER Platform, these datatypes behave in an identical manner to the long datatype on a 64-bit UNIX platform. The more difficult part of the task is often assessing the degree to which this issue affects your application. You can choose any or all of the following approaches to do this assess, depending on what makes the most sense for your application: The first approach is to simply attempt to compile and run your application as a native 64-bit application. However, you should be careful. If you store a 64-bit pointer in a 32-bit location, and if the top 32-bits of the pointer have all of the bits clear, then you have pointer truncation issues that do not cause a program failure. Simply by setting the NUT64_USE_HIGH_ADDRESS environment variable to any value, the heap management used by the NuTCRACKER Platform ensures that all memory addresses returned from malloc() are at an address above 0x100000000. When you link your DLLs, it is also possible to specify a default load address that is greater than 0x100000000. If the DLL has already been built, the rebase utility that comes with the Platform SDK is capable of changing the default load address for a DLL. Performing these two steps and then running your application makes any places where pointer truncation occurs evident because these occurrences will cause the application to crash. The basic strategy here

UNIX to Windows Porting Guide

137

Porting Applications to 64-bit Windows

is to debug the issues one-by-one, correct the problems, and repeat until the application is stable. When using this approach, you must be diligent about the proper usage of include files. For example, if you fail to include stdlib.h or malloc.h, and your source code calls malloc(), the compiler will assume malloc() returns an int and any pointers returned by it will be truncated. The second approach is to let the compiler assist you. Turning up the warning level of the compiler can help find those spots where pointer truncation is occurring. In particular, if you turn the warning level up to level 3 (cc -W/W3) and turn on an additional compiler warning flag (cc -W/Wp64), the compiler generates warnings specifically designed to help identify these issues. The specific compiler warnings that you want to remain alert for are: C4244. Conversion from type1 to type2, possible loss of data. C4267. Conversion from type1 to type2, possible loss of data. C4311. type_cast : pointer truncation from type1 * to type2. C4312. type_cast : conversion from type1 to type2 of greater size. Of these, C4311 deserves the most attention, although potentially any one of the 4 could indicate a real problem. Because these warning messages identify the two datatypes in question, it is easy to search for situations where pointers are being stored in long variables. These warnings may sometimes be spurious. For example, you may have used a generic datatype of some sort for which the only constraint is that it must hold the largest object available. In such a case, you may have instances where you are casting such an object to a smaller size where the usage is entirely legitimate, but the compiler has no way of knowing this. In the case of spurious warnings, it is difficult, but not impossible, to use a type cast to eliminate 4311 warnings. You must first type cast the pointer datatype to an integral type such as uintptr_t, and from there you can cast it to an integral type of a smaller size.

138

MKS Toolkit

Source Code Issues For more information about the clean64 utility, see the clean64 reference page in the online MKS Toolkit Utilities Reference.

The third approach is to use the clean64 utility to compile your source code. The recommended approach is to start with a clean source tree for your application, and then compile it substituting clean64 for cc. For many applications, this can be as simple as using a command line like:
make CC=clean64

The clean64 utility performs two essential tasks. It first syntactically analyzes your source code and header files, and automatically replaces instances of long with intptr_t and instances of unsigned long with uintptr_t. Should a given source file need to be changed, the original source file is renamed with a .orig suffix appended to the name, and the modified file is written out with the original name. Once this has occurred, the source file is compiled in the usual fashion. One limitation of clean64 is that it does not ensure that inttypes.h has been included before substituting datatypes. As a result, you may need to make minor modifications to ensure that this header file has been included. Once you have compiled your application, you must examine the results and decide which changes are relevant and should be kept, and which are not relevant and can be discarded. Those changes that you wish to keep should be committed to your source code management system. The clean64 utility does not alter code which is not compiled for this platform. For example, a code fragment like:
#ifdef linux unsigned long value; #endif

remains unchanged. The clean64 utility does not modify system header files (typically ones which are found by searching the INCLUDE environment variable search path). However, header files which are found by searching paths specified with I directives are modified. You do not need to use the clean64 utility each time you build your application. Normally, you need only use it the first time you build an application for 64-bit.

Source Code Issues


This section describes several issues that may require source code changes on your part.

UNIX to Windows Porting Guide

139

Porting Applications to 64-bit Windows

If you make changes to your application source code so that it can run with the NuTCRACKER Platform, you should isolate these changes using #if defined statements in your source files using the __NUTC64__ flag, for example:
#if defined(__NUTC64__) // new NuTCRACKER 64-bit code ... #else // old UNIX code ... #endif

It is also possible to isolate changes so that they would only apply to Itanium or AMD machines in this case, you could use something like:
#if defined(__NUTC64__) && defined(_IA64_) // new NuTCRACKER 64-bit code for Itanium #else if defined(__NUTC64__) && defined(_AMD64_) // new NuTCRACKER 64-bit code for AMD64 #endif

In general, it is unlikely that you should ever need to do this unless your code is performing tasks specific to this processor. An example might include a SIGSEGV signal handler that dumps the machine registers for the point at which the signal was raised.

Compiling and Linking a 64-bit application

First, you must open a 64-bit shell window. To do so, select Development from the MKS Toolkit Start menu and chose your preferred shell for 64-bit development. This is similar to the process for selecting a 32-bit development shell, so be sure to choose the 64-bit version of your desired shell. To compile and link 64-bit NuTCRACKER Platform applications, you would use the cc and cxx commands in the same way you would when building 32-bit NuTCRACKER applications. The header files in the $ROOTDIR/include directory are used for compilation in both 32 and 64-bit modes. The library files in the $ROOTDIR/lib directory are only for 32-bit mode however. When building 64-bit executables, use either the libraries in the $ROOTDIR/lib64i directory for Itanium platforms, or the libraries in the $ROOTDIR/lib64x directory for extended 64-bit architecture platforms. In most cases, this should make no difference to you. You should never need to directly specify those paths when compiling and linking as the cc and link commands automatically search the correct path. Building 64-bit applications from Visual Studio projects does not currently work due to the lack of a Visual Studio for targeting 64-bit platforms.

140

MKS Toolkit

Porting Issues

Debugging a 64-bit Application


The Debugging Tools for Windows Native 64-bit package can be downloaded free of charge from
http://www.microsoft.com/ whdc/ddk/debugging/ default.mspx.

There are two debuggers available that you can use to debug your 64-bit applications. One of these is a 64-bit version of the windbg debugger, and the second is a 64-bit version of the Visual Studio.NET debugger. The 32-bit versions of the Visual Studio debugger are not capable of debugging 64-bit applications. To debug 64-bit applications with the 64-bit version of windbg, you must download and install the Debugging Tools for Windows Native 64-bit package. There are separate downloads for the IA64 and AMD64 platforms. A 64-bit version of the Visual Studio.NET debugger is included with the Microsoft Platform SDK, and can normally be found in the bin\win64\debugger directory. In general, you must manually configure this debugger before you can use it. The Microsoft Platform SDK release notes contain instructions for this. These release notes also explain how to use this debugger, and enumerate a number of known limitations. To use the 64-bit windbg debugger, simply invoke:
windbg exename

or
windbg p pid

to launch the debugger. This version of windbg can also debug 32-bit applications, should you have a need for such a capability.

Porting Issues
There are several other issues that you will need to keep in mind when porting applications to 64-bit versions of Windows. Perhaps the most significant ones are some of the other ramifications of the fact that the long datatype is still 32-bits. Examples include: The strtol() function only returns a long (32-bit value). Similarly, atol() only returns a 32-bit value.
printf() format specifiers such as %ld only format and print a 32-bit

number. When formatting a pointer, it is generally recommended that you use %p instead, as this formats and correctly displays pointer values on all modern UNIX platforms. For 64-bit integral quantities, you can use the %q format specifier to format and print quadword values.

UNIX to Windows Porting Guide

141

Porting Applications to 64-bit Windows

The functions fseek() and ftell() use a 32-bit long value to represent file offsets. In the event that you have a need to use large files, you should use the fseeko() and ftello() functions instead, as these use a file offset specified as an off_t, and this datatype is 64-bits on 64-bit machines. The values LONG_MAX, LONG_MIN, and ULONG_MAX remain set to the values that are consistent with a 32-bit long. The load address for DLLs that do not have a preferred load address can vary much more than on 32-bit platforms. This may interfere with the proper operation of fork() for example. On 64-bit platforms it is even more important that a preferred load address be assigned.

Porting to 64-bit UNIX Platforms


More comprehensive information on porting to a 64-bit UNIX platform can be found on various World Wide Web sites.

If you have never ported your application to a 64-bit UNIX platform, the porting process is slightly more complicated than if you were simply porting to a different 32-bit UNIX platform. This section provides a brief overview of the general issues related to porting 32-bit UNIX applications to a 64-bit UNIX platform. Should you require additional assistance, MKS provides consulting services to help with porting issues related to 64-bit UNIX platforms. Please contact your sales representative for further information.

For more information about the clean64 utility, see the clean64 reference page in the online MKS Toolkit Utilities Reference.

Unfortunately there are no automated tools to help with the general case of porting to a 64-bit platform. MKS does provide the clean64 utility which is of use when your application is already known to be 64-bit clean. On the surface, the most obvious differences are the sizes of various datatypes. 64-bit platforms have a pointer datatype that is 8 bytes in size, while UNIX systems have a long datatype that is also 8 bytes.
Note The Microsoft compiler still has a long that is 4-bytes. For situations where it matters, and for maximum portability, you may wish to avoid the use of the long datatype entirely).

At the outset of the porting process one might naively assume that the job is simply a matter of widening structures as required to hold the larger datatypes. However, there are a couple of places where this could get you into trouble:

142

MKS Toolkit

Porting to 64-bit UNIX Platforms

If your application communicates over the network with 32-bit applications, data packets should be written in a form that the 32-bit application can still understand. Blindly widening data structures to hold a larger pointer may cause the 32-bit application to no longer be able to understand the communications with the 64-bit application. If your application writes data to a file in a binary format, and this file must be shared with 32-bit applications, you should pay close attention to the data structures used. There are other more subtle differences between 32-bit and 64-bit UNIX platforms. Examples include: 64-bit quantities such as pointers must be aligned on 8 byte boundaries. Normally, the compiler does this work for you, but it is possible to create an improperly aligned pointer through a variety of means (examples would include copying a pointer into an unaligned byte array). Pointer alignment may become an important factor if a data structure containing a pointer must be passed to a 32-bit applications. When you are comparing datatypes of differing sizes, the smaller one is promoted to the larger size to facilitate comparison.

Best Practices

While the process of porting an application to a 64-bit platform may have what appear to be some hidden pitfalls, there are some best practices that you can use to make the process go more smoothly. Use header files to fully prototype all functions that your application uses. You may wish to treat all compiler warnings of the form: foo.c(4) : warning C4013: 'malloc' undefined; assuming extern returning int as an error that you should resolve. Avoid adding function prototypes to individual .c files, and instead place the prototype in common header files that are used by all source files that require prototypes for the function in question. Avoid using K&R function prototypes, as these are less strongly typed than their ANSI C equivalents. Consider using the /WX compiler switch, which causes the Microsoft compiler to treat a warning as an error. This forces you to resolve all compiler warnings by one means or another. Use derived types such as size_t, ptrdiff_t, and off_t wherever appropriate instead of simple integer types such as int and long.

UNIX to Windows Porting Guide

143

Porting Applications to 64-bit Windows

When you require a datatype of a specific size (for example, for a network packet), consider using explicitly sized datatypes such as u_int_64_t instead of attempting to configure on a case-by-case basis with the use of #define. When using printf() style format specifiers, use the %p specifier to display a pointer value rather than %x. Pay close attention to the following compiler warnings: C4244. Conversion from type1 to type2, possible loss of data. C4267. Conversion from type1 to type2, possible loss of data. C4311. type_cast : pointer truncation from type1 * to type2. C4312. type_cast : conversion from type1 to type2 of greater size. Consider using type casts to eliminate these warnings where you feel them to be harmless. Analyze existing type casts as these can mask a problem that was benign on 32 bit-platforms and is the source of a bug on 64-bit architectures.

144

MKS Toolkit

Porting to 64-bit UNIX Platforms

UNIX to Windows Porting Guide

145

Porting Applications to 64-bit Windows

146

MKS Toolkit

Deploying Applications

12

making it work correctly in the development environment. This chapter concerns taking your application from your development system, installing it on an end-user system, and having it function correctly.

The previous chapters discuss porting a UNIX application to Windows and

Concepts
This section covers the concepts you need to understand to prepare your NuTCRACKER Platform application for deployment: runtime components your application needs, packaging/licensing issues, and deployment mechanisms.

Runtime Components

NuTCRACKER Platform applications, the applications you build with the MKS Toolkit UNIX APIs and a NuTCRACKER Platform development environment, depend on the NuTCRACKER Platform to provide runtime services. The NuTCRACKER Platform comes in two forms: NuTCRACKER Workstation the runtime package that supports desktop applications. NuTCRACKER Workstation supports single-user applications. NuTCRACKER Server the runtime package that supports server applications. NuTCRACKER Server supports multi-user applications. You must ensure that the correct version of the NuTCRACKER Platform is present on the end-user's system when you install your NuTCRACKER Platform application. Your application may also require MKS Toolkit utilities at runtime. For example, if your application uses shell scripts or Perl scripts, you must ensure that these are available on the end-user's system when your application is installed.

UNIX to Windows Porting Guide

147

Deploying Applications

Finally, your application may depend on third-party packages, such as X Servers, that you received as part of your MKS Toolkit package. If your application uses these capabilities, you must deploy this add-on to the enduser's system as well.

Packaging/ Licensing

There are two packaging/licensing models available for you to obtain your runtime components. Which is the best approach depends on your individual needs. First, each member of the MKS Toolkit product family includes a copy of NuTCRACKER Workstation. You can choose to deploy one of these products to each desktop system on which your application runs. For example, if you need a collection of MKS Toolkit utilities as well as NuTCRACKER Workstation for your application, you might choose to deploy a copy of MKS Toolkit for System Administrators to each desktop. If you needed an X Server, you might choose to deploy a copy of MKS Toolkit for Interoperability. This allows you to purchase runtime solutions through volume channels.

See the MKS Web site, or contact your MKS sales representative for more information.

The other model is to purchase runtime licenses (distribution rights) from your MKS sales representative. This allows you to tailor your runtime license purchases to your specific need. For example, if you have a simple character-based application, for which you only need NuTCRACKER Workstation, you can purchase the right to deploy a specific number of copies of NuTCRACKER Workstation with your application. Note that if you are deploying a server-based application, you must purchase NuTCRACKER Server licenses from MKS. The NuTCRACKER Deployment Wizard prepares a NuTCRACKER Platform deployment package for you. If you choose to deploy runtime components by purchasing MKS Toolkit family products, then you are responsible for installing this package on the end user's system before or during your application's installation. The package prepared by the NuTCRACKER Deployment Wizard installs any updates or patches that you have installed on your development system, which ensures that the set of runtime components on the end-user's system is at the same (or perhaps later) version than those on your development system. This ensures that your application has the correct runtime components. If you choose to purchase direct deployment licenses, the package prepared by the NuTCRACKER Deployment Wizard installs the runtime components on the end user's system during installation of your application. If there are already runtime components on the end-user's system, they are updated to match those on your development system (if they are out of date).

Deployment Mechanisms

148

MKS Toolkit

Definitions

Whichever model you choose, you follow the same steps to prepare for NuTCRACKER Platform deployment. The rest of this chapter discusses this procedure.

Definitions
This section reviews the terminology just introduced and defines additional terms that the remainder of this chapter uses: Development MachineA machine where you installed the MKS Toolkit UNIX APIs and a NuTCRACKER Platform development environment. This is the machine where you developed your application. End-User MachineYour customer's machine, where the customer intends to install your NuTCRACKER Platform application. NuTCRACKER PlatformThe NuTCRACKER runtime component, used by the NuTCRACKER Platform application. Workstation, Server, 32-bit, and 64-bit versions for various chip architectures are available. The 32-bit and 64-bit NuTCRACKER platforms can coexist on the same machine and share resources. Third-Party OptionA licensed redistributable option that is included with a MKS Toolkit product family member, such as an X Server that is not an MKS product. To redistribute these options, you must purchase deployment rights either from the original vendor or directly from MKS. MKS Toolkit UtilitiesUtilities from one of the MKS Toolkit product family members. NuTCRACKER Deployment WizardThe graphical tool that you use to select components for your NuTCRACKER application and which prepares them for redistribution. Deployment LicenseThe physical key that enables the NuTCRACKER Deployment Wizard. By default, the NuTCRACKER Deployment Wizard assumes that you provide runtime components by deploying a member of the MKS Toolkit product family, and builds an appropriate package. However, if you choose to purchase deployment rights directly from MKS, you are provided with a deployment license key that you enter into the wizard to identify your redistribution rights. This enables the wizard to build an appropriate package for you.

UNIX to Windows Porting Guide

149

Deploying Applications

Deployment RightsYou must license 32-bit and 64-bit deployment separately, although both can be built using the same deployment wizard provided it has access to a valid license. Staging DirectoryThe directory from which you intend to build a CD image of your product (or otherwise distribute it). This chapter assumes for purposes of illustration that you are distributing your application, including the NuTCRACKER Platform runtime components, on a single CD. The process is similar no matter how you physically distribute your application. When you build a CD image, on a file system on your network, you first create a directory containing a replica of the file structure you want on your CD. You then use mastering software that converts this directory and all its files and subdirectories to a binary image to burn onto the CD. The directory that holds your CD replica is the staging directory, the place where you stage all the files that are going onto your CD. Take for example a hypothetical software product called YourApp. YourApp is staged to the directory D:\YourApp. Under this directory, there is a bin directory for the executables, a lib directory for the DLLs, a conf directory for configuration and resource files, and a doc directory for help files. In the staging directory, there is also an installer for YourApp, setup.exe. A typical staging directory resembles:
D:\ YourApp\ bin\ conf\ doc\ lib\ setup.exe

When you burn your CD, the root directory contains:


bin\ conf\ doc\ lib\ setup.exe

NuTCRACKER Staging SubdirectoryThe subdirectory in your staging directory where the NuTCRACKER Deployment Wizard places the necessary components. In the structure above, this might be the directory D:\YourApp\nutc.

150

MKS Toolkit

Deployment Overview

StagingThe process of copying the selected components to the NuTCRACKER staging subdirectory. Components are prepackaged in compressed files on your original MKS Toolkit media. Staging is the last thing that the NuTCRACKER Deployment Wizard does. InstallationThe process of installing your application, including the NuTCRACKER Platform components, by running your installer on the end-user machine. Your installer calls the NuTCRACKER Installation API, which invokes the NuTCRACKER Platform installer to install the NuTCRACKER Platform components. NuTCRACKER Root DirectoryThe directory containing the NuTCRACKER Platform on a machine, ROOTDIR.

Deployment Overview
This section summarizes the steps for deploying a NuTCRACKER Platform application. The remainder of this chapter discusses each step in detail. 1. Ensure that your application can coexist with other NuTCRACKER Platform applications on the end-user machine. Test your application fully on the development machine. 2. If necessary, purchase and install your NuTCRACKER Deployment License. This is only necessary if you choose to deploy the NuTCRACKER Platform (and any other runtime components) directly. If you need to deploy 32-bit and 64-bit binaries to the same machine remember to ask for a combined NuTCRACKER Platform license so that a single unified NuTCRACKER Platform installation can be created. 3. Run the NuTCRACKER Deployment Wizard to package the components to redistribute, and to stage them to your platform staging subdirectory. 4. If you have not already done so, move all of the parts of your application to your staging directory and write a native Windows installer for your application. 5. Call the NuTCRACKER Installation API from your installer to install the NuTCRACKER Platform and to register your application. 6. If you are redistributing any third-party options, call the appropriate third-party option installer from your installer. 7. Call the NuTCRACKER Installation API in your uninstall procedure to deregister your application.

UNIX to Windows Porting Guide

151

Deploying Applications

While it may seem strange to perform all of these steps even when you are deploying the NuTCRACKER Platform as part of a MKS Toolkit product family member, there is an important reason. Doing this ensures that the version of the NuTCRACKER Platform deployed with your application exactly matches (or is newer than) the one you used on your development system. This includes installing any updates or patches that may be needed. You need to perform all of these steps, regardless of the deployment model you select.

Ensuring an Application Can Coexist


Before packaging and distributing your application, you should understand that the NuTCRACKER Platform is a shared resource. This places certain restrictions and requirements on your application. The NuTCRACKER Platform installer enforces most of these requirements and restrictions to ensure that multiple NuTCRACKER Platform applications can coexist on the end-user machine. In particular, the NuTCRACKER Platform installer sets up the following shared facilities during installation on the end-user machine: Core DLLs and servicesNuTCRACKER installs the most current versions in the system directories (where the operating system is installed). Registry hierarchyNuTCRACKER controls the layout to ensure that all NuTCRACKER Platform applications have a consistent registry hierarchy. File system layoutNuTCRACKER defines a NuTCRACKER Platform root directory hierarchy under ROOTDIR for installed support files and components. This ensures that all NuTCRACKER Platform applications can find needed files in well-defined locations. However, there are certain global resources that affect coexistence and whose consistency NuTCRACKER cannot enforce. Because NuTCRACKER cannot enforce consistency, your application must do it. The most common global resource to cause coexistence problems is the environment. NuTCRACKER tries to maintain environment consistency by using appropriate defaults, such as the settings for TERM (set to nutc for NuTCRACKER console-mode applications) and DISPLAY (set to :0.0 for local display of X applications). If you use the defaults, your application coexists well.

152

MKS Toolkit

Installing the Deployment License Key

If you cannot use the defaults, however, there may be problems. For example, if your application uses terminals attached to serial lines, you might be tempted to change TERM to vt100 or some other terminal type. Doing this may cause other NuTCRACKER Platform applications to behave incorrectly. One possible solution is to wrap your executables with a shell script or batch file that sets TERM appropriately for your application, rather than modifying the global environment.
See Distributing Third-Party Options on page 160 for more details.

Another area of conflict between applications is dependence on third-party options, such as a specific X server. It is best to avoid dependence on any particular X server; the user may already have installed another server. The X server is not part of the NuTCRACKER Platform; if your application requires an X server, it is your responsibility to redistribute and install it.

Installing the Deployment License Key


This step is optional if you choose to deploy the NuTCRACKER Platform by installing a MKS Toolkit product family member on the end-user's system. If you choose to purchase direct deployment rights (for example, if you are deploying a server-based solution and need NuTCRACKER Server deployment rights), you need to install the Deployment License key you received from MKS. If you need to purchase a Deployment License, contact your MKS sales representative or distributor. Any time that you purchase additional NuTCRACKER Platform options, you receive a new deployment license, which defines the complete set of options you have purchased. You must install this new key to enable deployment of the newly purchased options. You can install, display, and modify your key with the MKS Toolkit control panel applet. You can also do this from the initial dialog of the NuTCRACKER Deployment Wizard.

Running the NuTCRACKER Deployment


Wizard
The NuTCRACKER Deployment Wizard performs two major tasks: it lets you select which NuTCRACKER Platform runtime components to distribute with your application (selection), and it copies those components to your NuTCRACKER staging subdirectory (staging). The Wizard does not build an installer for your application, it only prepares things so that you can

UNIX to Windows Porting Guide

153

Deploying Applications

install the necessary NuTCRACKER Platform components with a single call to the NuTCRACKER Installation API from your installer. Invoke the Deployment Wizard under Development in the MKS Toolkit Start menu.

Selecting Components

Your deployment license defines the set of NuTCRACKER Platform options that you can redistribute. The Wizard uses a tree control to show the components that you can redistribute. It computes the set of components by combining the list of installed options with the options specified in your deployment license. The Wizard assumes that if your deployment license entitles you to redistribute an option, but you have not installed the corresponding option, that you do not need to deploy the components for that option. Some NuTCRACKER Platform options have more than one component. The tree hierarchy shows this relationship. In addition, because some components depend on others, the Wizard automatically selects dependent components for you. In this tree, select only the components that you need for your application. If you have any questions about the contents of a component (a leaf node in the tree), select the component (but do not check the check box) to see its contents. You will see the names of utilities and features, but you will not see the explicit names of services and DLLs. You should not need to know what the services or DLLs are named, or even how many of them there are.

Staging the Components

After selecting the components to redistribute, the next step is to stage those components from your development machine to your NuTCRACKER staging subdirectory. The Wizard prompts you for the path to the NuTCRACKER staging subdirectory. You should specify a subdirectory under your staging directory that is dedicated to NuTCRACKER Platform components. For example, if you are using the directory D:\YourApp as your staging directory, you would use a directory such as D:\YourApp\nutc for the NuTCRACKER staging subdirectory. The Wizard stages the required files directly from your development machine, and thereby automatically includes any patches that you may have installed. As it locates each component, the Wizard copies the component files and patches, if any, into a directory hierarchy under the NuTCRACKER Platform staging subdirectory you specified. The NuTCRACKER Platform installer, which you invoke from your application installer, physically installs these files onto the end-user machine during installation.

154

MKS Toolkit

Writing an Installer

Writing an Installer
At this point, you should write an installer for your application, if you have not already written one for testing. We recommend that you use a third-party installation tool such as InstallShield. You can also write a program to install your application. If you use a third-party installation tool, make sure that it can call functions exported from a DLL. To invoke the NuTCRACKER Platform installer, you must call NuTCRACKER Installation API functions in the NuTCRACKER Installer DLL. Some tools, certain versions of InstallShield for example, cannot call DLL interfaces. InstallShield Professional works fine; some other versions do not. When building your installer, remember that it must be a pure Win32 application. You cannot link it with the NuTCRACKER Platform. If you link it with the NuTCRACKER Platform, the installer may work on your development machine, because the NuTCRACKER Platform is already installed there, but it will fail on the end-user machine when it tries to use the NuTCRACKER Platform before it is installed. At a minimum, your installer should perform the following steps in roughly this order: 1. Install your application, including nutins.dll, the NuTCRACKER Platform installer DLL. 2. Optionally, display a progress meter or busy icon because installing the NuTCRACKER Platform may take a few minutes. The NuTCRACKER Platform installer can run silently or verbosely. If you are hiding the fact that the NuTCRACKER Platform is being installed, install the NuTCRACKER Platform silently and display your own progress dialog. 3. Install the NuTCRACKER Platform. 4. If your application depends on a third-party option such as an X server, determine if the option should be installed (there may already be one on the machine) and install it. 5. Potentially, ask the user to reboot to complete the NuTCRACKER Platform installation.
Note The NuTCRACKER Platform installer makes no entries in the Start menu. Your installer is responsible for making any entries that your application requires.

UNIX to Windows Porting Guide

155

Deploying Applications

Using the Installation API


The NuTCRACKER Installation API provides functions to install the NuTCRACKER Platform, to register your application, to register a preferred X server, and to deregister your application when you uninstall it.

Installation Overview

The following are the typical steps for calling the NuTCRACKER Installation API in your installer: 1. Verify that the user installing your application has the necessary permissions to install the NuTCRACKER components. 2. Call the NuTCRACKER Platform installer to install the NuTCRACKER Platform components. The installer does the following: a) It checks to see if the NuTCRACKER Platform is already on the machine. b) If so, it updates the existing NuTCRACKER Platform with components that are not already installed and with components that are newer than those already installed. c) If not, it installs the NuTCRACKER Platform in the location that you specify. d) It tells your installer if a reboot is necessary to complete installation. 3. Register your installed application. 4. If you are distributing an X server, tell NuTCRACKER the command to automatically invoke the X server when an X application is started (and no server is already running).

An example of this type of installation modification can be found in the MKS Toolkit Resource Kit.

5. Locate the NuTCRACKER Platform root directory, if you need to install support files (for example, an X application-defaults file) in the NuTCRACKER Platform root directory hierarchy. The Installation API uses the following files, located in ROOTDIR/etc/redist, on your development machine.
File nutins.h nutinsis.h nutins.lib Purpose This C/C++ header file defines the Installation API, documenting the functions and their error return codes. This is a version of nutins.h suitable for inclusion in InstallShield script files. This is the import library for the Installation API, used when building a C/C++ installation program.

Files

156

MKS Toolkit

Using the Installation API

nutins.dll

This DLL implements the Installation API. This file is needed at runtime, during installation, and uninstallation.

You must include nutins.dll in your installation and it must be installed before you call any of the NuTCRACKER installation functions. How to distribute the DLL depends on your installation tool. The DLL must be available to your procedures for installing and uninstalling your application.

The Installation API

The following sections briefly describe the major functions of the Installation API. Refer to the header files for details.

Error Handling
All functions in the installer API return TRUE if the function succeeded and FALSE otherwise. If a function returns FALSE, you can call nutinsGetLastError(), which returns one of the error codes documented in the header files or a standard Win32 error code.

Checking Permissions
Because the NuTCRACKER Platform contains a service and Windows NT/2000/XP/2003 requires administrator privileges to install a service, NuTCRACKER Platform components must be installed by a user with permissions to administer the machine. Hence, one of the first actions your installer should take is to determine if the user has sufficient permissions, using nutinsProcessHasRights().

Installing the Components


To install the components, call nutinsInstall(), specifying where to install the NuTCRACKER Platform, if one is not already installed. Because the NuTCRACKER Platform is a shared resource, we recommend that you choose an appropriate shared system directory (for example, D:\win32app\nutcroot), rather than a directory beneath your application's installation directory. You may want to offer your customer a default location and offer the chance to change the location, or you may want to hide the fact that the NuTCRACKER platform is being installed.

Note The installation DLL is a pure Win32 application. It only understands paths in Win32-format (D:\dir\file). It does not understand UNIX- or NuTCRACKER Platform-style paths.

UNIX to Windows Porting Guide

157

Deploying Applications

The installer can run in silent or verbose mode. If you run the NuTCRACKER Platform installer in silent mode, we recommend that you display some form of progress dialog while the installer is running. This function tells you if the user needs to reboot the machine to complete installation.

Note Because the machine on which you are installing may already have a

NuTCRACKER platform, you cannot rely on the NuTCRACKER Platform being installed in the directory you specified. If you need to know where the NuTCRACKER Platform is installed, call nutinsGetRootDir(), discussed later in this chapter.

Registering Your Application


A registry of all NuTCRACKER Platform applications is installed on the machine. You can see the registered NuTCRACKER Platform applications in the MKS Toolkit control panel applet. You must call nutinsRegisterApp() after successfully installing the NuTCRACKER Platform components, to register your application.

Selecting a Preferred X Server


If you are installing an X server with your application, you can optionally register a preferred X server for the NuTCRACKER Platform to start if one is not running when an application starts, using nutinsSetPreferredXServer().
For more information, see Distributing Third-Party Options on page 160.

The user or another application may have already registered a preferred X server (and that server may be a different server than you are installing). You should avoid changing a preferred X server unless necessary.

Installing Files in the Root Directory


Occasionally you must install files in the NuTCRACKER Platform root directory, ROOTDIR. For example, an X Windows applications-default file that needs to be installed in usr/lib/x11/app-defaults under the NuTCRACKER Platform root directory. As discussed earlier, your installer cannot know the location of this root directory, because another application may have already created it in some location unknown to your installer. You can obtain this path with nutinsGetOERootDir().

158

MKS Toolkit

Distributing Third-Party Options

Distributing Third-Party Options


For information on registering an X server, see Selecting a Preferred X Server on page 159.

Third-party options such as X servers are not included in the NuTCRACKER Platform. You may license these options from MKS, or from a third party. If you distribute any third-party options, you must install them as part of your application's installation. If you are distributing an X server, and want the NuTCRACKER Platform to be able to automatically start the X server when an X application runs, you must register the X server. Because third-party options are usually shared resources, you should consider the following issues: There may already be an X server or telnet server installed on the machine. The user could have installed one, or a previously installed NuTCRACKER Platform application may have installed one. There is no reliable way to detect whether or not these options already exist on the machine. You likely need to prompt the user for this information and make installation optional. Because there can only be one X server running on a given display, you must be careful when using features of a specific X server. If your application requires a certain feature of a specific X server, and a different X server is running on the machine, your application may not function correctly. The NuTCRACKER Platform can automatically start an X server if none is running when an X application starts. An installer may do this by registering a preferred X server via an Installation API function. The function lets you override an existing preferred X server. You should override an existing preferred X server with caution, because having another X server start may confuse the user. For third-party options you have licensed from MKS, you should install these options after installing the NuTCRACKER Platform. To protect these products, their installers depend on unlock codes that the NuTCRACKER Platform installer prepares during its installation. MKS has Technical Notes for installing each third-party option that we distribute. These notes cover issues such as how to silently install each option. Please contact your MKS support representative or distributor to obtain the documents you need for your application.

UNIX to Windows Porting Guide

159

Deploying Applications

Uninstalling Your Application


When you uninstall your application, you do not uninstall the NuTCRACKER Platform, because it is a shared resource, and removing it might adversely impact other applications on the machine. It is the endusers responsibility to remove it when it is no longer needed. The only thing you need to do when you uninstall your application is to deregister it, using nutinsDeregisterApp(). If you are providing instructions to the end-user for removing the NuTCRACKER Platform, you can find instructions on the MKS Web site. Each component must be uninstalled separately and the NuTCRACKER Platform component must be uninstalled last.

160

MKS Toolkit

Uninstalling Your Application

UNIX to Windows Porting Guide

161

Deploying Applications

162

MKS Toolkit

Environment Variables

13

This section describes the environment variables that the NuTCRACKER


Platform uses.
Note Environment variables should not be used in application ported using the NuTCRACKER Platform, except for debugging purposes. If your application depends on environment variables and you deploy the application on a target machine, problems could arise if another NuTCRACKER Platform-ported application is installed which overrides your application environment variable settings.

CP_MAX_PORTS_ENVVAR

Usage: Specifies number of communications ports being used. Value: 12


DISPLAY

Usage: Identifies the name of the X display that you are using. Value: :0.0
HOME

Usage: Identifies the users home directory. Used to fill the password structure.
Value: %HOMEDRIVE%%HOMEPATH% INCLUDE

Usage: Specifies the search path for include files. Value: %ROOTDIR%\include;%INCLUDE%
LANG

Usage: Specifies the current locale. Value: Locale specific.

UNIX to Windows Porting Guide

163

Environment Variables

LIB

Usage: Specifies the search path for library files. Value: %ROOTDIR%\lib;%LIB%
LOGNAME

Usage: Specifies the users login name. Value: %USERNAME%


NLSPATH

Usage: Search path for message catalogs. Value: Various directories under %ROOTDIR\etc\locale
NUT_CASE_INSENSITIVE

Usage: Controls whether or not NuTCRACKER treats characters in a case-insensitive manner when processing wild cards on the command line. Value: Not set by default; wildcards are treated as case-sensitive.
NUT_DEFAULT_WIN32_FAULT

Usage: If there is no signal handler, instead of performing the UNIX default action for the signal, NuTCRACKER performs the Windows default action for the signal (which is generally to pop up a dialog that lets you attach the debugger). Value: Not set by default.
NUT_DUMP_CORE

Usage: Dumps a file named core.pid, where pid is the process ID, if an unhandled signal whose default action is core occurs. Value: Not set by default.
NUT_ENV_CONVERT, NUT_ENV_LITERAL

Usage: In general, NuTCRACKER translates UNIX path names in the environment to NuTCRACKER path names. These two environment variables influence the conversion, but the following rules apply: The following variables are always converted: PATH, NLSPATH, TEMP, TMP, TMPDIR, COMSPEC, SHELL, ROOTDIR, and WIN32BIN. The following variables are never converted: DISPLAY, HOMEDRIVE, systemdrive, TZ, and the variables listed in NUT_ENV_LITERAL.

164

MKS Toolkit

To prevent conversion of a variable, add it to NUT_ENV_LITERAL. If NUT_ENV_CONVERT is set to a list of environment variables, these are the only environment converted, subject to the rules above. Value: Neither is set by default. Both take comma-separated lists as their values.
NUT_NT_LIMITED_LOCKING

Usage: Modifies the file control locking functionality to depend on the limits provided by Windows NT/2000/XP/2003 LockFile() and LockFileEx(). Some UNIX file control locking semantics may not work correctly when this variable is set. Value: Not set by default.
NUT_PIPE_BUFFER_SIZE

Usage: Changes the buffer size used for anonymous and NT named pipes (but not FIFOs). It can also be controlled programmatically by using _NutConf(). Value: 5120
NUT_PRIMARY_GROUP

Usage: Sets the primary group for a user, primarily for the purpose of overriding the default group of None when logging into a local machine. Value: Not set by default; the NuTCRACKER Platform uses the process token primary group.
NUT_SEC_ATTR_OFF

Usage: Causes the NuTCRACKER Platform to use a NULL security descriptor for all object creation APIs. The umask and file creation bits are ignored and the security on the object is the default security as provided by Windows NT/2000/XP/2003. Value: Security attributes are used by default.
NUT_SUFFIXED_SEARCHING

Usage: When executing access(, X_OK) or one of the exec() family of functions, causes the NuTCRACKER Platform to append the .exe suffix to the name of the executable and retry the operation, if the executable originally had no extension and was not located by that name. For example, searches for myprog, and if it is not found, for myprog.exe. Value: Not set by default.

UNIX to Windows Porting Guide

165

Environment Variables

NUT_TEXT_MODE

Usage: Sets the default mode for opening files (including stdin, stdout, and stderr) to text mode. Value: Not set by default; regular files open in binary mode. C++ streams open in text mode by default.
NUT_VALIDATE_HEAPS

Usage: Validates the heaps on each malloc() and free(), and pops up a warning dialog when heap is corrupt. Value: Not set by default.
NUTCROOT

Usage: Identifies the MKS Toolkit installation root directory; use of this variable is deprecated. Use ROOTDIR. Value: Determined at installation.
PATH

Usage: Specifies the search path for executable files. Value: %ROOTDIR%\bin;%ROOTDIR%\bin\x11;
%ROOTDIR%\mksnt;%PATH% ROOTDIR

Usage: Identifies the MKS Toolkit installation root directory. Value: Determined at installation.
SHELL

Usage: Identifies the command shell. This variable is used by make, as well as by system() and popen().
Value: %ROOTDIR%\mksnt\sh.exe TERM

Usage: Specifies the terminal type. Value: nutc


TERMCAP

Usage: Specifies the terminal capabilities file. Value: %ROOTDIR%\etc\termcap


TERMINFO

Usage: Specifies the root directory of the terminfo library. Value: %ROOTDIR%\usr\lib\terminfo

166

MKS Toolkit

Console Escape Sequences

14
Escape Sequence ESC [ A ESC [ B ESC [ C ESC [ D ESC [ 5 ~ ESC [ 6 ~ ESC [ H ESC [ 4 ~ ESC [ 2 ~ ESC [ 3 ~ ESC [ 0 P ESC [ 0 Q ESC [ 0 R ESC [ 0 S

The tables in this section present the set of escape sequences generated by the keyboard for NuTCRACKER Platform console applications, as well as the output escape sequences recognized. Portable applications should, however, use the curses libraries rather than directly manipulating escape sequences.

Keyboard Keycaps
Keyboard Keycap Up Arrow Down Arrow Right Arrow Left Arrow Page Up Page Down Home End Insert Delete F1 F2 F3 F4

UNIX to Windows Porting Guide

167

Console Escape Sequences

Keyboard Keycap F5 F6 F7 F8 F9 F10 F11 F12 Tab Shift-Tab Backspace Return

Escape Sequence ESC [ 0 T ESC [ 1 7 ~ ESC [ 1 8 ~ ESC [ 1 9 ~ ESC [ 2 0 ~ ESC [ 2 1 ~ ESC [ 2 3 ~ ESC [ 2 4 ~ Ctrl-I (\t) Ctrl-B Ctrl-H (\b) Ctrl-J (\n)

Screen Functions
Screen Function Set cursor to normal (as inherited) Save cursor position. Cursor invisible Restore cursor position Cursor visible Enable line wrap Disable line wrap Cursor left Cursor right Cursor up Cursor down Absolute cursor position Escape Sequence ESC [ = r ESC [ = s ESC [ = t ESC [ = u ESC [ = v ESC [ = 7 h ESC [ = 7 l ESC [ Pn D ESC [ Pn C ESC [ Pn A ESC [ Pn B ESC [ Pl ; Pc H

168

MKS Toolkit

Screen Functions

Screen Function Absolute cursor position Erase in page Erase in line Select graphic rendition Clear page

Escape Sequence ESC [ Pl ; Pc f ESC [ J ESC [ K ESC [ Ps ; ... ; Ps m ESC [ 2 J

The Pn value specifies the number of lines/columns affected by the escape sequence; if no number is specified, 1 is assumed. The Pl and Pc values specify line and column positions. The Ps value may be any of the values in the following table. These values may be combined.

Graphic Rendition 0 7 27 30 31 32 33 34 35 36 37 39 40 41 42 43

Text Attributes or Colors All attributes to default. negative (reverse) video positive (normal) video black foreground red foreground green foreground yellow foreground blue foreground magenta foreground cyan foreground white foreground default foreground color black background red background green background yellow background

UNIX to Windows Porting Guide

169

Console Escape Sequences

Graphic Rendition 44 45 46 47 49

Text Attributes or Colors blue background magenta background cyan background white background default background color

The term default means the attributes that were in effect at the time the first NuTCRACKER Platform application started running in this console window.

170

MKS Toolkit

Evolving Applications with COM


For details on using the NuTCRACKER Platform with COM and to review sample code, see the Building COM Automation Objects with NuTCRACKER paper in the MKS Toolkit Resource Kit. For more information, see Building Standalone DLLs on page 109.

15

After porting your UNIX application to the NuTCRACKER Platform on

Windows using the MKS Toolkit UNIX APIs there are many ways to evolve your application to take more advantage of the Windows platform. This chapter discusses Microsoft's reusable Component Object Model (COM) technology and creating reusable COM objects from existing UNIX applications by way of the NuTCRACKER Platform.

To wrap UNIX code as a COM object, you must understand the concepts of standalone DLLs. You can, however, understand most of the COM concepts without reading about standalone DLLs. For more information on COM, we recommend the following: The Microsoft COM Web site at http://www.microsoft.com/com. Understanding ActiveX and OLE, by David Chappell (Microsoft Press, 1996). Inside OLE 2, by Craig Brockshmidt (Microsoft Press, 1995).

Introduction
Several years ago, Microsoft introduced Object Linking and Embedding (OLE), a mechanism for creating compound documents, such as an Excel spreadsheet embedded in a Word report. This rudimentary technology evolved into OLE 2, which was based on the Component Object Model (COM). COM describes a common paradigm for objects to interact with each other, without having to know specifics about how they are implemented.

COM Overview

COM is an extremely simple technology to describe. It is a specification for binary compatibility between cooperating objects, objects that do not (have to) know or care with whom they are cooperating, how they are implemented, or even where they reside. ActiveX and OLE are standard sets

UNIX to Windows Porting Guide

171

Evolving Applications with COM

of controls and interfaces to COM objects. ActiveX defines interfaces for inplace activation, also called visual editing. OLE defines interfaces for compound documents. In the world of COM object programming, software comprises one or more COM objects and each COM object provides interfaces to the outside world. COM objects and software interact by invoking methods in an interface. The following diagram shows the structure of a COM object:
Implementation method A COM Object Interface 1 Interface method A Interface method B Interface method C Interface method D Interface 2 Implementation method C Implementation method D Implementation method B

This diagram also illustrates the terminology used in the remainder of this chapter. Each object contains one or more interfaces. An interface is more closely analogous to a C++ class than it is to traditional single API, because each interface contains several methods. We use the term interface method to distinguish the specification of a method from its implementation, which we call an implementation method. To interact with an object, software invokes methods from the objects various interfaces. When a method is invoked, ultimately some code is executed. Your software does not know or care in what language this code is implemented, on which machine the code is executing or even about calling conventions. This enforced separation of interface and implementation is one of COM's greatest strengths. Every COM object runs in a server. The server executes the code that implements the object. There are three kinds of servers: in-process, local, and remote. An in-process server is expressed as a DLL. The DLL is loaded into the client that needs the object's services, hence the name in-process server. A local server is a standalone executable that runs on the same machine as the client. A local server generally provides its own user interface. A remote server is one that runs on a remote machine via DCOM (Distributed COM).

COM Benefits

COM offers many benefits, including:

172

MKS Toolkit

Using the NuTCRACKER Platform and COM

Desktop Integration. You can elegantly integrate mission-critical UNIX applications (e.g., a Financial Trading application) with standard, off-the-shelf Windows desktop productivity tools (e.g., Word, Excel, PowerPoint). You get real plug-and-play software. Web Enabling. You can web-enable existing UNIX code. COMwrapped UNIX components can be readily embedded in Hypertext Markup Language (HTML), Active Server Pages (ASP), and Extended Markup Language (XML), which web-enables the underlying legacy UNIX code. Tapping the Component Market. You can package portions of larger applications for generalized reuse or resale. You have the potential to find completely new markets for your legacy business logic. Alternatively, you can combine existing components with yours to create new products. Architecture Modernization. You can modernize the architecture of legacy applications by restructuring as reusable components. Or you can separate user interface from business logic, by replacing a UNIX character- or X11-based user interface with Java, MFC, or Visual Basic, while maintaining your existing and well-tested business logic. Component Standardization. You can provide standard components for specific industries (for example, Healthcare and Manufacturing). Distributed Services. You can create shared services that can be invoked consistently across distributed organizations using DCOM. Generalized scaling and distribution require the Windows 2000/XP/2003 Active Directory.
For more information, see
http://msdn.microsoft.com /scripting/default.htm?/s cripting/windowshost/.

Scripting. You can use the Windows Scripting Host with Visual Basic scripts and JScript (Java scripts) to automate your components. Reuse Existing User Interface Technology. You can reuse existing Windows facilities, such as ActiveX controls, to quickly add a new graphical user interface to your legacy business logic. Language Independence. The implementation of COM objects can be in many languages, from Visual Basic to C++. You can use the services of any object regardless of the language in which the interface methods are actually written.

Using the NuTCRACKER Platform and COM


There are only a few issues that you must keep in mind when using the NuTCRACKER Platform with COM:

UNIX to Windows Porting Guide

173

Evolving Applications with COM

Selecting a server type. With the NuTCRACKER Platform, the applications best suited to become in-process servers are those without a graphical interface and those with a graphical interface that is more or less easily separable from the underlying business logic. Use a local server for code that is graphical (for example, where you want to reuse an existing X Windows user interface). Build environment. If you are using the Active Template Library (ATL) or the Microsoft Foundation Classes (MFC), you certainly want to use the Visual C++ IDE to develop your objects and graphical interfaces. Once you have designed and coded the object definition layer, you may want to build outside of the IDE, by driving msdev from your makefiles. If you do this, you should remember that a NuTCRACKER environment is set up during the make (that is, it sets the environment to find MKS Toolkit UNIX API header files and link libraries). When building pure Windows code such as your object definition layer, if you are invoking from a NuTCRACKER Platform make file, you must set the environment for Windows before invoking msdev or nmake and restore it when it returns. Linkage issues. When developing objects with COM, you must be aware of potential linkage issues and you should always strive to keep your pure Windows code separate from your ported UNIX code, to facilitate linkage. In particular, MFC and the NuTCRACKER Platform collide and must be linked into separate modules. We prefer letting the main program handle the MFC code and putting the UNIX code in a NuTCRACKER Platform DLL. If you are very careful, you can mix ATL and NuTCRACKER Platform code, because you can control the build environment to avoid linkage issues. The samples and the Building COM Automation Objects with NuTCRACKER paper in the MKS Toolkit Resource Kit show how to do this. Multiple event loops. Both COM and X Windows have event driven programming models. Some event occurs that causes some action to occur (for example, an implementation method or callback to be invoked). These two event loops must be separate and distinct, or COM events would be blocked while you are waiting for X events and vice versa. In other words, your application would deadlock. We recommend that you enable multi-threaded X, use pthread_create() to spawn a new thread, and run your X event loop inside that thread, letting the main thread handle the COM events. You must synchronize and perhaps pass information between the two threads. A COM sample in the MKS Toolkit Resource Kit shows one means of doing this.

174

MKS Toolkit

Using Components

Do not fork(). An in-process server is a DLL and you cannot fork in a NuTCRACKER Platform DLL. Do not fork() in a local server either, for it is not clear what it means to fork() COM objects. Using vfork() and exec() may be an alternative. In general, you should design your objects to avoid forking. Threading model. A COM object specifies the threading model that each of its instances use. The builder of a COM object may choose apartment threading (single-threaded apartment), multithreading (multithreaded apartment), or both. If your code is already thread safe, you can probably use the multithreaded apartment model. However, to be safe, you should start with the single-threaded apartment model until you fully understand the COM threading models and their impact on your code. Wrapping implementation methods. When you run NuTCRACKER Platform code in a Win32 thread, you must be sure that the NuTCRACKER Platform is enabled. Using COM, you can be running NuTCRACKER Platform code in a Win32 thread and you may not even be aware of it. Your code may be running in a Win32 thread if it is a DLL (for example, an in-process server or a library that is explicitly loaded into a Win32 program) or if your code is a COM executable for which you have chosen a multithreaded apartment model.
For more information, see Building Standalone DLLs on page 109.

To enable NuTCRACKER, you must wrap the implementation methods with _NutEnableNuTC() and _NutDisableNuTC(). You can do this either in the implementation method which makes calls into your DLL, or inside each entry point in your DLL. We recommend placing the calls in your implementation method, rather than in the actual method code in the DLL, because fewer modifications to the existing UNIX code are needed this way. Finally, if you are in doubt about whether to enable the NuTCRACKER Platform or not, enable it. The performance overhead of enabling the NuTCRACKER Platform when it is already enabled is trivial.

Using Components
Once you build a component, you can use it in various ways, including:

UNIX to Windows Porting Guide

175

Evolving Applications with COM

Using a desktop tool as a container. For example, you can use Word or Excel as a container for your object. The whois sample in the MKS Toolkit Resource Kit shows an example of this. For instance, if you produce an EDA tool for designing circuitry logic and you convert that tool to COM objects, your customers could write design documents containing live design objects. By editing the circuit design, they would be editing the circuit design document as wellthe two would never be inconsistent. Invoking objects from Visual Basic. You can write Visual Basic interfaces for objects, or drive objects from VB scripts. Using Java or HTML in an Active Server Page. The whois sample in the MKS Toolkit Resource Kit shows an example of this.

176

MKS Toolkit

The Communications Port Interface

16

This chapter describes the NuTCRACKER Platform serial communications


port (com port) interface. Because Windows does not support logging into the system through a serial port, the NuTCRACKER Platform supports com ports for data transfer onlya com port cannot be the controlling terminal of a process. Beyond this limitation, the NuTCRACKER Platform provides a comprehensive implementation of the standard termios interfaces, and a partial implementation of the SVR4 termiox extensions.

Com Port Devices


The NuTCRACKER Platform recognizes two forms of device names for com ports:
/dev/com/n

This corresponds to the Windows device COMn. This device assumes a hardwired serial connection, and ignores the carrier-detect serial line.
/dev/com/nM

This is the modem-control version of the Windows device COMn (hence the trailing M). An attempt to open this device blocks until the carrierdetect line becomes active, unless the port is explicitly opened in nonblocking mode. By default, the NuTCRACKER Platform supports 12 com ports. You can increase this limit by using _NutConf() to change _NC_SET_MAX_COM_PORTS.This must be done before the first com port is opened in the process. Com ports cannot be sharedthe port can be opened by only one process at a time. The only way to share access to a com port is to duplicate the file descriptor, either explicitly via dup(), or through inheritance from one process to another.

UNIX to Windows Porting Guide

177

The Communications Port Interface

You can read() from and write() to com ports just as you would with UNIX serial ports. The select() function supports read, write and exception notification for com ports. Com ports are controlled through ioctl(), fcntl() and a number of purpose-specific functions, as discussed below. Because of limitations in the operating system interface, data that has not yet been transmitted may be discarded when the port is closed. You should not rely on closing a com port to flush the data.

Com Port Control


See the struct termios and struct termiox reference pages for details on how the NuTCRACKER Platform implements these structures.

Com ports are controlled by the standard termios and termiox structures, with related ioctl(), fcntl(), and other specific functions. This sections summarizes the interface.

The termios and termiox Structures

When setting the port for non-canonical input, the NuTCRACKER Platform must map the requested inter-byte timeout to one supported by the operating system. Therefore, the inter-byte timeout used might not be exactly the time specified by the VTIME setting in the termios structure. The NuTCRACKER Platform does not support setting the ports speed in the c_cflag field of the termios structure. You should get and set the baud rate using one of the functions described below. The NuTCRACKER Platform supports speeds up to 256k bps; the actual speed depends on the underlying hardware, and is usually limited to 115k bps on PC-type hardware.

See the struct termios reference page for specific information. See the struct termiox reference page for specific information.

The NuTCRACKER Platform supports most, but not all, of the standard termios settings, because of limitations in the underlying operating system. The NuTCRACKER Platform supports the SVR4 termiox extensions, for setting hardware flow control parameters.

178

MKS Toolkit

Com Port Control

Supported ioctl() Operations

The following ioctl() commands are documented in more detail on the struct termios reference page:
Command TCGETS TCSETS TCSETSW TCSETSF TCSBRK TCXONC TCFLSH Send a break on a com port. Used for flow control on a com port. This ioctl() command flushes pending input and output on a com port. Description Get and set termios parameters on a com port.

The following ioctl() commands are documented in more detail on the struct termiox reference page:
Command TCGETX TCSETX TCSETXW TCSETXF Description Get and set termiox parameters on a com port.

The following ioctl() commands are equivalent to fcntl() commands discussed below:
Command FIOGETOWN FIOSETOWN FIOASYNC FIONBIO Description

Equivalent to the F_GETOWN and F_SETOWN fcntl() commands.


Equivalent to using the F_SETFL fcntl() command to set the O_ASYNC flag. Equivalent to using the F_SETFL fcntl() command to set the O_NONBLOCK flag.

UNIX to Windows Porting Guide

179

The Communications Port Interface

Supported fcntl() Operations

The following fcntl() commands are supported:


Command F_GETFL F_SETFL F_GETOWN F_SETOWN Description Get and set the port parameter flags. In particular, the FASYNC flag can be set or cleared to enable or disable asynchronous IO notification via a SIGIO signal. Get and set the process ID of the process which receives SIGIO signals when asynchronous IO notification has been enabled. This process must have installed a handler for SIGIO, as the default action is to ignore the signal.

See the fcntl() reference page for more information.

In addition, the standard F_DUPFD, F_GETFD, and F_SETFD commands are supported. The following functions are used to manipulate com ports. For more information, see the appropriate reference pages in the online MKS Toolkit UNIX APIs Reference.
Function cfgetispeed() cfgetospeed() cfsetispeed() cfsetospeed() cfmakeraw() tcgetattr() tcsetattr() tcdrain() tcflow() tcflush() tcsendbreak() Sets the fields of a termios structure for noncanonical character-at-a-time input (raw mode). Get and set the termios parameters for a com port. Wait for all queued output on a com port to be transmitted. Used for flow control on a com port Flush pending input and output on a com port. Send a break on a com port. Description Get and set the input and output speeds in a termios structure.

Other Operations

180

MKS Toolkit

Index

Symbols
$CP_MAX_PORTS_ENVVAR 163 $DISPLAY 163 $HOME 163 $INCLUDE 163 $LANG 163 $LIB 164 $LOGNAME 164 $NLSPATH 164 $NUT_CASE_INSENSITIVE 164 $NUT_DEFAULT_WIN32_FAULT 8, 48, 164 $NUT_DUMP_CORE 8, 164 $NUT_ENV_CONVERT 78, 164 $NUT_ENV_LITERAL 78, 164 $NUT_NT_LIMITED_LOCKING 165 $NUT_PIPE_BUFFER_SIZE 165 $NUT_PRIMARY_GROUP 165 $NUT_SEC_ATTR_OFF 165 $NUT_SUFFIXED_SEARCHING 165 $NUT_TEXT_MODE 166 $NUT_VALIDATE_HEAPS 49, 166 $PATH 166 $ROOTDIR 166 $SHELL 166 $TERM 166 $TERMCAP 166 $TERMINFO 166 $WINTIF_MODE 96 $XBMLANGPATH 95 /etc/groups 13 /etc/hosts 28 /etc/passwd 13 /etc/services 28 <sys/fs/s5_inode.h> 38 _BSD_SOURCE 40 _exit() 56, 83

_NUTC_SOURCE 40 _NutConf() 21, 56, 177 _NutConfStr() 77 _NutDebugBreak() 48, 78, 133 _NutDisableNuTC() 45, 111, 124, 175 _NutDisableThreadLibraryCalls() 107 _NutEnableNuTC() 45, 110, 124, 175 _NutFastStat() 71 _NutFdToHandle() 71 _NutForkExec() 16 _NutForkExec() family 4, 57, 127 _NutHandleToFd() 28, 71 _NutIsNuTCProcess() 60 _NutLibMSetLibraryType() 76 _NutPathToNutc() 69 _NutPathToWin32() 69 _NutPathToWin32FS() 69 _NutQueryPid() 4, 60 _NutQueryWinNetFileDir() 28 _NutQueryWinSysDir() 70 _NutValidatePassword() 65 _POSIX_C_SOURCE 39 _POSIX_SOURCE 39 _SVID_SOURCE 40 _XOPEN_SOURCE 39 _XOPEN_SOURCE_EXTENDED 39

Numerics

64-bit Extension Technology 135 64-bit Windows platform (Win64) 135145

A
access permissions 11, 15 rights 11

UNIX to Windows Porting Guide

181

Index

Access Control Entries 10 Allow 10 Deny 10 Access Control List 10 access() 66, 165 accessing source files 33 ACE 10 ACL 10 activation, in-place 172 Active Directory Services 173 active server page, COM and 173, 176 Active Template Library 174 ActiveX 171173 address family AF_INET 27 AF_UNIX 27 administrative utility 14 alarm() 58 AMD Athelon 135 AMD Opteron 135 ANSI C 41 apartment threading (COM) 175 API Monitor 49 are 28 argv 19 Aspen threads 115, 117, 119 asynchronous signal 125 atan() 76 atan2() 76 atexit() 55, 83 ATL COM and 174 linking with 174 automation, COM 171

Visual C++ 89 byte ordering 44

C
C++ functions in DLL 111 in DLLs 106 runtime libraries 82 static destructor 83 Call Attributed Profiler 49 carriage return 34 case, file extension 34 cc command 46, 81 CDFS file system 17 cfgetispeed() 180 cfgetospeed() 180 cfmakeraw() 180 cfsetispeed() 180 cfsetospeed() 180 chdir() 68 chmod() 14, 66 chown() 67 chroot() 69 clean64 command 139140, 143 clipboard accessing 23 integrating applications using 50 clock() 55 code page 28 colors, console 28, 169 COM 171 active server page, and 173, 176 ActiveX, and 173 ATL, and 174 automation 171 building applications 174 fork(), and 175 HTML, and 173, 176 implementation method 172, 175 interface method 172 Java, and 173, 176 JScript, and 173 object 171172 scripts, and 173, 176 server 172 selecting 174 threading models 175

B
barriers 118 baud rate 178 binary I/O mode 2021, 41, 70, 110 bind() 73 block device 23 brk() 6, 61 bsd_sginal() 62 building applications ATL 174 COM 174 MFC 174

182

MKS Toolkit

Index

Visual Basic, and 173 web enabling with 173 X Windows, and 174175 XML, and 173 command line application, running from 92 communications port device names 177 serial 22, 177 compilation flags 81, 104 issues with 46 options, Visual C++ 86 compilation environment 3738 compile-time flags 39 Component Object Model 171 component, COM 171 compound documents 172 confstr() 77 console code page 28 colors 28, 169 cursor positioning 168 escape sequences 167 file descriptor 22 I/O 28 specifying 22 subsystem, Win32 92 window size 28 control panel applet 14, 26 Information tab 48 controlling terminals 6, 61, 177 core dump, causing 8 cos() 76 cpio command 34 creat() 70 creating FIFOs 27, 74 crypt() 65 ctermid() 73 ctime() 77 curses library 29 cursor positioning, console 168 cxx command 46, 81, 83

D
DACL 10

daemon converting to a service 130 porting 129 data corruption 127 database group 13 hosts 28 password 13 registered services 129 SAM 64 services 28 user 13 DCE threads 119, 122 DCOM 173 DDE integrating applications using 50 support for 23 debugging _NutDebugBreak() 48 applications 47 Just-In-Time 8 service 133 default font, Wintif 96 Deployment Wizard 51 destructors, static 83 device //./PhysicalDriven 23 //./pipe/pipename 24 //.D: 23 //machine/pape/pipename 24 /dev/clipboard 23 /dev/com 22, 177 /dev/console 22 /dev/dde 23 /dev/lp 22 /dev/null 22 /dev/tty 22, 73 /dev/zero 22 naming 177 NUL: 22 special files 22 directory fifos 27, 74 NutTrash4 21 reading 72 root 18 Discretionary Access Control List 10 Distributed COM 173

UNIX to Windows Porting Guide

183

Index

DLL 24 building 103 determining linked 48 in-process COM server 172 load address 103 locating 25 search order 25 DllMain() 107 dlopen() 77, 107 document, compound 172 domain 9 Dr. Watson 8 drive letter, in path name 18 Dynamic Link Library 24 dynamic linking 24

E
editing, visual 172 end of line, indicating 34 endianness 44 environ 78 environment 110 compilation 38 modifying 19 paths, converting 78 putenv 19 variables 163 errno 41, 7577, 113 exec() 16, 55, 165 exit() 56 exp() 76 extended 64-bit architectures 135136, 141 Extended Markup Language 173 extensionless files 56, 66

F
FAT file system 16 fchmod() 66 fchown() 67 fcntl() 71 fibers 124 FIFOs creating 27, 7374 directory 27 file control _NutFastStat() 71

_NutFdToHandle() 71 _NutHandleToFd() 71 creat() 70 fcntl() 71 fopen() 70 fstat() 7273 open() 70 read() 71 rename() 72 stat() 7273 write() 71 file extensions, case 34 file I/O _NutFastStat() 71 _NutFdToHandle() 71 _NutHandleToFd() 71 creat() 70 fcntl() 71 fopen() 70 fstat() 7273 open() 70 read() 71 rename() 72 stat() 7273 write() 71 file locks 71 file management 16, 67 file mode flags 65 switching 71 file security 65 access() 66 chmod() 66 chown() 67 fchmod() 66 fchown() 67 umask() 67 Windows Me 14 Windows NT/2000/XP/2003 14 file selection widget 99 file systems CDFS 17 differences 34 FAT 16 fstatvfs() 68 Joliet 17 large 68 lchown() 68

184

MKS Toolkit

Index

link() 68 lstat() 68 mount() 68 NTFS 16 readlink() 68 root directory 18 statvfs() 68 symlink() 68 UDF 17 umount() 68 VFAT 16 files access mode 14 binary mode 21, 41, 70 bitmap 95 case-independent 17 case-preservation 17, 34 case-sensitive 34 copying 34 core 8 deleting 21 extensionless 56, 66 mode, initialization 16 module definition 103, 105 NTFS Owner 15 opening 70 ownership 14 path names 18 permissions 15 pixmap 95 resource 95 security 65 sharing 35 special 22 text mode 20, 41, 70 textmode.obj 21 unlinking 21 flip command 34 fopen() 21, 70 fork() 16, 49, 56 COM, and 175 replacing with _NutForkExec() 4 vfork() 4 replacing with a thread 127 runtime issues 33 Fortran, using with NuTCRACKER 83 free() 49

fstat() 7273 fstatvfs() 68

G
GetCurrentThread() 124 getcwd() 69 getegid() 64 getenv() 78 geteuid() 64 getgid() 64 getgrgid() 13, 64 getgrnam() 13, 64 getgroups() 64 gethostbyaddr() 27, 74 gethostbyname() 27, 74 getitimer() 56 getpgid() 59 getpgrp() 59 getpid() 5, 60 getppid() 60 getpriority() 59 getpwnam() 13, 6465 getpwuid() 13, 64 getsid() 59 getuid() 64 global system variables 41 globbing 43 graphical applications 92 group database 13 group ID impersonation 13 mapping 12 root 13 group security getegid() 64 getgid() 64 getgrgid() 64 getgrnam() 64 getgroups() 64 setegid() 65 setgid() 65 GUI applications 92

H
h_errno 77 hard drive block device 23

UNIX to Windows Porting Guide

185

Index

hard links 68 header file <sys/fs/s5_inode.h> 38 header files compilation environments 37 issues 37 heap 166 process 6 validating 49 hosts file 28 HTML, COM and 173, 176 htonl() 44 htons() 44

support 26 ioctl() 179 IP address 27 IPC 26 issues compiling 46 linking 46 Itanium (IA64) architecture 135136, 141

J
Java, COM and 173, 176 job control signals 8 Joliet file system 17 JScript, COM and 173

I
I/O binary mode 21, 41 console 28 text mode 20, 41 IA64 (Itanium) architecture 135136, 141 IA64 architecture 135 icons changing 95 pixmap 95 using 94 IDE, Visual C++ 35, 174 imake 91 impersonation group ID 13 user ID 13 implementation method, COM 172, 175 initialization,file mode 16 inode 14, 17 in-place activation 172 in-process COM server 172, 174175 integrated development environment 35 interface method, COM 172 interprocess communication bind() 73 gethostbyaddr() 74 gethostbyname() 74 mkfifo() 74 poll() 74 recvmsg() 74 select() 74 sendmsg() 74 shmat() 75

K L

kill() 62

large file systems 68 lchown() 68 ld command 46, 81 $LD_LIBRARY_PATH 25 $LD_RUN_PATH 26 libraries used at runtime 33 libraries, shared 103 line terminator carriage return 20 line-feed 20, 34 line-feed 20, 34 link() 68 linker flags 81, 105 Visual C++ 87 linking ATL, with 174 dynamic 24 issues with 46 MFC, with 174 static 24 links hard 68 -llwp threads 123 load address, DLL 103 local COM server 172, 174

186

MKS Toolkit

Index

locales 28 locks, file 71 log() 76 log10() 76 logging messages 53 Windows Me 53 logical drive block device 23 longjmp() 57 lstat() 68

M
make utilities 166 COM and 174 imake 35 make 35 nmake 35, 174 malloc() 49, 61, 127 math libraries _NutLibMSetLibraryType() 76 atan() 76 atan2() 76 cos() 76 exp() 76 IEEE mode 75 intrinsic functions 76 log() 76 log10() 76 matherr() 7576 mode 75 optimization issues 76 POSIX mode 75 sin() 76 sqrt() 76 SVID mode 75 tan() 76 XOPEN mode 75 matherr() 7576 memory management 6 brk() 61 malloc() 61 mmap() 61 mprotect() 62 msync() 62 munmap() 62 sbrk() 61 message queues 26 method

COM implementation 172, 175 COM interface 172 MFC 173174 linking with 174 Microsoft Foundation Classes 173 mkfifo() 74 mknod() 73 mktemp() 78 mmap() 61 modem 22, 177 module definition file 103, 105 Motif, transition to Wintif 100 mount points 16 mount() 68 mprotect() 62 msdev 48 msdev command 47, 174 msync() 62 munmap() 62 mutex 117118, 123, 127

named pipe 24 nanosleep() 58 nap() 58 ncf77 command 83 ncf90 command 83 networking bind() 73 configuration files 28 gethostbyaddr() 74 gethostbyname() 74 mkfifo() 74 poll() 74 recvmsg() 74 select() 74 sendmsg() 74 shmat() 75 support 26 nice() 59 nmake 50 building with 50 utility 35 nmake command 174 NT File System 14 NTFS file ownership 15

UNIX to Windows Porting Guide

187

Index

file system 16 ntohl() 44 ntohs() 44 NUL: 22 NuTCRACKER service 14 service framework 131 threads 123124 NuTCRACKER Platform environment variables 163 _NutFdToHandle() 28 _NutQueryRootDir() 27 NutTrash4 directory 21

O
object access 11 security 10 object, COM 171172 OLE 171172 ONC RPC 44 open() 70 ordering byte 44 ownership determining 14 file 14

P
packaging applications 51 passwords database 13 validating 65 $PATH 26 path names _NutPathToNutc() 69 _NutPathToWin32() 69 _NutPathToWin32FS() 69 _NutQueryWinSysDir() 70 chdir() 68 chroot() 69 conventions 18 converting 69 determining 69 drive letter in 18

file 18 formats 19 getcwd() 69 UNIX-style 43 Windows-style 43 pax command 34 permissions files 15 Windows NT/2000/XP/2003 14 perror() 47, 77 pipe() 73 pipes bi-directional, creating 73 named 24 unidirectional 73 pixmap, icon 95 poll() 74 popen() 57, 166 porting concepts 3 determining scope of 33 issues 55 process overview 31 ports communication (COM) 22 modem-control 22 serial 22 POSIX 75 POSIX threads 115, 119123 Draft 10 121 Draft 4 122 Draft 7 121 mapping from DCE threads 122 printers accessing 22 specifying 22 printf() 127 process command 118 control 3 debugging 8 group 6, 59 heap 6 ID child 5 NuTCRACKER 4 Windows Me 6, 53 Windows NT/2000/XP/2003 6

188

MKS Toolkit

Index

management 55 stack 6 process and thread scheduling getpriority() 59 nice() 59 pthread_attr_setpolicy() 59 pthread_setscjedparam() 59 setpriority() 59 process command 48 process control _exit() 56 _NutForkExec() 57 atexit() 55 clock() 55 exec() 55 exit() 56 fork() 56 getitimer() 56 longjmp() 57 nanosleep() 58 nap() 58 popen() 57 pthread_atfork() 58 setitimer() 56 siglongjmp() 57 sleep() 58 system() 58 times() 58 usleep() 58 vfork() 58 wait3() 58 wait4() 58 waitpid() 58 process identification _NutIsNuTCProcess() 60 _NutQueryPid() 60 getpgid() 59 getpgrp() 59 getpid() 60 getppid() 60 getsid() 59 pthread_self() 60 setpgrp() 61 setsid() 61 pthread_atfork() 58 pthread_attr_setpolicy() 59 pthread_cond_getname_np() 118 pthread_cond_setname_np() 118

pthread_create() 123124, 175 pthread_getname_np() 118 pthread_join() 121 pthread_mutex_getname_np() 118 pthread_mutex_lock() 123 pthread_mutex_setname_np() 118 pthread_mutex_t 123 pthread_self() 60 pthread_setname_np() 118 pthread_setsched_param() 59 pthread_sigmask() 121, 125 pthread_yield() 121 putenv() 78

R
read() 71 readdir() 72 readdir_r() 72 reader/writer locks 118 readlink() 68 recvmsg() 74 relative identifier 9 remote COM server 172 rename() 72 resource defaults, Wintif 96 resource file 95 RID 9 root group ID 13 user ID 13 root directory 18 running Visual C++ applications 89 runtime libraries 82

S
SACL 10 SAM 9 sbrk() 6, 61 sched_yield() 121 SCM 52 screen management 28 scripts, COM and 173, 176 security 64 descriptor 10 identifiers 9 object 10

UNIX to Windows Porting Guide

189

Index

Windows Me 52 Windows NT/2000/XP/2003 9 Security Accounts Manager communicating with 71 database 9, 64 select() 74 semaphores 26 sendmsg() 74 serial port 22, 177 server, COM 172, 174 Service Control Manager 52, 129 services daemons 129 debugging 133 file 28 framework 131 installing 134 NuTCRACKER 14 testing 134 sessions 6 setegid() 65 seteuid() 65 setgid() 13, 65 setitimer() 56, 58, 112 setpgrp() 61 setpriority() 59 setsid() 61 setuid() 13, 65 shared library, porting 103 shared memory 26 shmat() 75 SID 9 sigaction() 63 SIGALRM 58 sigaltstack() 63 SIGIO 180 siglongjmp() 57 signal asynchronous 125 bsd_signal() 62 handler thread 127 handling 48 job control 8 kill() 62 managment 7 sigaction() 63 sigaltstack() 63

sigstack() 63 sigvec() 64 SIGWINCH 28 Win32 exceptions 8 sigprocmask() 125 sigqueue() 63 sigstack() 63 sigthreadmask() 121 sigvec() 64 sigwait() 125 SIGWINCH 28 sin() 76 sleep() 58 sockets handle conversion 28 implementation 27 standard 27 Solaris threads 120 source code, issues 40 source files accessing 33 sharing 35 transferring 34 special files 22 ctermid() 73 mknod() 73 pipe() 73 ttyname() 73 ttyname_r() 73 spinlocks 118 sproc() 123 sqrt() 76 stack, process 6 Standard Template Library 82 stat() 7273 file attributes 66 file mode flags 65 structures returned from 65 static destructors 83 static linking 24 statvfs() 68 strerror() 47, 77 subsystems choosing type of 92 console 92 Windows 92 SunOS threads 120, 123 symbolic links 16

190

MKS Toolkit

Index

symlink() 68 sys_errlist 41 sysconf() 51, 79 syslog() 79 System Access Control List 10 system calls, tracing 48 System V File System 38 system() 58, 166

U
UDF file system 17 UI threads 120, 123 umask command 165 umask() 16, 67 umount() 68 UNC 16 Universal Naming Convention (UNC) 16 UNIX International threads 120, 122 unlink() 22 user database 13 user ID impersonation 13 mapping 12 root 13 user security _NutValidatePassword() 65 geteuid() 64 getgroups() 64 getpwnam() 64 getpwuid() 64 getuid() 64 seteuid() 65 setuid() 65 usleep() 58

T
tan() 76 tar 34 tcdrain() 180 tcflow() 180 tcflush() 180 tcgetattr() 180 tcsendbreak() 180 tcsetattr() 180 templates, using 82 terminal, controlling 6, 61, 177 termios 177 termiox 177 text I/O mode 20, 41, 70, 110 textmode.obj 21 threads Aspen 115, 117, 119 COM and 175 DCE 119 ID 122123 in X Windows applications 118 initialization 125 -llwp 123 POSIX 115 signal handler 127 Solaris 120 sproc() 123 SunOS 123 UI 120 UNIX International 120 Win32 115, 124 thread-specific data 108 times() 58 TLI 27 troubleshooting 3 truss command 48 ttyname() 73 ttyname_r() 73

V
variables, global system 41 VFAT file system 16 vfork() 4, 58, 127, 175 Visual Basic 112 COM, and 173, 176 Visual C++ 81, 85 building applications 89 IDE 35, 174 running applications 89 setting compiler options 86 setting linker options 87 visual editing 172

W
wait() 8 wait3() 58 wait4() 58 WaitForMultipleObjects() 123

UNIX to Windows Porting Guide

191

Index

waitpid() 8, 58 web enabling with COM 173 Win32 console subsystem 92 Windows subsystem 92 Win32 API Profiler 49 Win64 (64-bit Windows platform) 135145 windbg debugger 47 Windows subsystem, Win32 92 Windows Me 51 logging messages 53 process IDs 53 Registry Backup 134 security 52 service registry 130 Windows NT/2000/XP/2003, differences between

Service Control Manager 129 Windows Me, differences between 52 Windows Scripting Host 173 Wintif default font 96 file selection 99 new resources 97 resource defaults 96 transition from Motif 100 using 95 write() 71

X
X Windows 91 COM, and 174175 threaded applications 118 XDR 44 XML, COM and 173 XTI 27

52

Windows NT/2000/XP/2003 permissions 14 security 9

192

MKS Toolkit

You might also like