r352 - trunk

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Wed Sep 26 05:02:36 EDT 2007


Author: icculus
Date: 2007-09-26 05:02:35 -0400 (Wed, 26 Sep 2007)
New Revision: 352

Added:
   trunk/platform_windows.c
Modified:
   trunk/platform_unix.c
Log:
First bulk of Windows platform layer. Probably doesn't even compile yet.


Modified: trunk/platform_unix.c
===================================================================
--- trunk/platform_unix.c	2007-09-25 10:29:03 UTC (rev 351)
+++ trunk/platform_unix.c	2007-09-26 09:02:35 UTC (rev 352)
@@ -574,7 +574,7 @@
             retval = true;
     } // if
     return retval;
-} // MojoPlatform_issymlink
+} // MojoPlatform_isfile
 
 
 void *MojoPlatform_open(const char *fname, uint32 flags, uint16 mode)
@@ -845,7 +845,7 @@
 
     // /dev/shm may be able to avoid writing to physical media...try it first.
     const char *dirs[] = { "/dev/shm", getenv("TMPDIR"), P_tmpdir, "/tmp" };
-    const char *tmpl = "mojosetup-gui-plugin-XXXXXX";
+    const char *tmpl = "mojosetup-plugin-XXXXXX";
     char fname[PATH_MAX];
     void *retval = NULL;
     int i = 0;

Added: trunk/platform_windows.c
===================================================================
--- trunk/platform_windows.c	                        (rev 0)
+++ trunk/platform_windows.c	2007-09-26 09:02:35 UTC (rev 352)
@@ -0,0 +1,1395 @@
+/**
+ * MojoSetup; a portable, flexible installation application.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#if PLATFORM_WINDOWS
+
+#include "platform.h"
+#include "gui.h"
+
+// Much of this file was lifted from PhysicsFS, http://icculus.org/physfs/ ...
+//  I wrote all this code under the same open source license, and own the
+//  copyright on it anyhow, so transferring it here is "safe".
+
+/* Forcibly disable UNICODE, since we manage this ourselves. */
+#ifdef UNICODE
+#undef UNICODE
+#endif
+
+#include <windows.h>
+
+// is Win95/Win98/WinME?  (no Unicode, etc)
+static boolean osIsWin9x = false;
+static uint32 osMajorVer = 0;
+static uint32 osMinorVer = 0;
+static uint32 osBuildVer = 0;
+
+static uint32 startupTime = 0;
+
+// These allocation macros are much more complicated in PhysicsFS.
+#define smallAlloc(x) xmalloc(x)
+#define smallFree(x) xfree(x)
+
+// ...so is this.
+#define BAIL_IF_MACRO(cond, err, ret) if (cond) return ret;
+#define BAIL_MACRO(err, ret) return ret;
+
+#define LOWORDER_UINT64(pos) (PHYSFS_uint32) \
+    (pos & 0x00000000FFFFFFFF)
+#define HIGHORDER_UINT64(pos) (PHYSFS_uint32) \
+    (((pos & 0xFFFFFFFF00000000) >> 32) & 0x00000000FFFFFFFF)
+
+/*
+ * Users without the platform SDK don't have this defined.  The original docs
+ *  for SetFilePointer() just said to compare with 0xFFFFFFFF, so this should
+ *  work as desired.
+ */
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
+#endif
+
+/* just in case... */
+#ifndef INVALID_FILE_ATTRIBUTES
+#define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF
+#endif
+
+/* Not defined before the Vista SDK. */
+#ifndef IO_REPARSE_TAG_SYMLINK
+#define IO_REPARSE_TAG_SYMLINK 0xA000000C
+#endif
+
+#define UTF8_TO_UNICODE_STACK_MACRO(w_assignto, str) { \
+    if (str == NULL) \
+        w_assignto = NULL; \
+    else { \
+        const uint64 len = (uint64) ((strlen(str) * 4) + 1); \
+        w_assignto = (WCHAR *) smallAlloc(len); \
+        if (w_assignto != NULL) \
+            utf8ToUcs2(str, (uint16 *) w_assignto, len); \
+    } \
+} \
+
+static uint64 wStrLen(const WCHAR *wstr)
+{
+    uint64 len = 0;
+    while (*(wstr++))
+        len++;
+    return(len);
+} // wStrLen
+
+
+static char *unicodeToUtf8Heap(const WCHAR *w_str)
+{
+    char *retval = NULL;
+    if (w_str != NULL)
+    {
+        void *ptr = NULL;
+        const uint64 len = (wStrLen(w_str) * 4) + 1;
+        retval = (char *) xmalloc(len);
+        utf8FromUcs2((const uint16 *) w_str, retval, len);
+        retval = xrealloc(retval, strlen(retval) + 1);  // shrink.
+    } // if
+    return(retval);
+} // unicodeToUtf8Heap
+
+
+static char *codepageToUtf8Heap(const char *cpstr)
+{
+    char *retval = NULL;
+    if (cpstr != NULL)
+    {
+        const int len = (int) (strlen(cpstr) + 1);
+        WCHAR *wbuf = (WCHAR *) smallAlloc(len * sizeof (WCHAR));
+        BAIL_IF_MACRO(wbuf == NULL, ERR_OUT_OF_MEMORY, NULL);
+        MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, cpstr, len, wbuf, len);
+        retval = (char *) xmalloc(len * 4);
+        utf8FromUcs2(wbuf, retval, len * 4);
+        smallFree(wbuf);
+    } /* if */
+    return(retval);
+} /* codepageToUtf8Heap */
+
+
+/* pointers for APIs that may not exist on some Windows versions... */
+static HANDLE libKernel32 = NULL;
+static HANDLE libUserEnv = NULL;
+static HANDLE libAdvApi32 = NULL;
+static HANDLE libShell32 = NULL;
+static DWORD (WINAPI *pGetModuleFileNameW)(HMODULE, LPWCH, DWORD);
+static BOOL (WINAPI *pGetUserProfileDirectoryW)(HANDLE, LPWSTR, LPDWORD);
+static BOOL (WINAPI *pGetUserNameW)(LPWSTR, LPDWORD);
+static DWORD (WINAPI *pGetFileAttributesW)(LPCWSTR);
+static HANDLE (WINAPI *pFindFirstFileW)(LPCWSTR, LPWIN32_FIND_DATAW);
+static BOOL (WINAPI *pFindNextFileW)(HANDLE, LPWIN32_FIND_DATAW);
+static DWORD (WINAPI *pGetCurrentDirectoryW)(DWORD, LPWSTR);
+static BOOL (WINAPI *pDeleteFileW)(LPCWSTR);
+static BOOL (WINAPI *pRemoveDirectoryW)(LPCWSTR);
+static BOOL (WINAPI *pCreateDirectoryW)(LPCWSTR, LPSECURITY_ATTRIBUTES);
+static BOOL (WINAPI *pGetFileAttributesExA)
+    (LPCSTR, GET_FILEEX_INFO_LEVELS, LPVOID);
+static BOOL (WINAPI *pGetFileAttributesExW)
+    (LPCWSTR, GET_FILEEX_INFO_LEVELS, LPVOID);
+static DWORD (WINAPI *pFormatMessageW)
+    (DWORD, LPCVOID, DWORD, DWORD, LPWSTR, DWORD, va_list *);
+static HANDLE (WINAPI *pCreateFileW)
+    (LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
+static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPTSTR);
+static BOOL (WINAPI *pMoveFileW)(LPCWSTR, LPCWSTR);
+static void (WINAPI *pOutputDebugStringW)(LPCWSTR);
+
+/*
+ * Fallbacks for missing Unicode functions on Win95/98/ME. These are filled
+ *  into the function pointers if looking up the real Unicode entry points
+ *  in the system DLLs fails, so they're never used on WinNT/XP/Vista/etc.
+ * They make an earnest effort to convert to/from UTF-8 and UCS-2 to 
+ *  the user's current codepage.
+ */
+
+static BOOL WINAPI fallbackGetUserNameW(LPWSTR buf, LPDWORD len)
+{
+    const DWORD cplen = *len;
+    char *cpstr = smallAlloc(cplen);
+    BOOL retval = GetUserNameA(cpstr, len);
+    if (buf != NULL)
+        MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, cpstr, cplen, buf, *len);
+    smallFree(cpstr);
+    return(retval);
+} /* fallbackGetUserNameW */
+
+static DWORD WINAPI fallbackFormatMessageW(DWORD dwFlags, LPCVOID lpSource,
+                                           DWORD dwMessageId, DWORD dwLangId,
+                                           LPWSTR lpBuf, DWORD nSize,
+                                           va_list *Arguments)
+{
+    char *cpbuf = (char *) smallAlloc(nSize);
+    DWORD retval = FormatMessageA(dwFlags, lpSource, dwMessageId, dwLangId,
+                                  cpbuf, nSize, Arguments);
+    if (retval > 0)
+        MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,cpbuf,retval,lpBuf,nSize);
+    smallFree(cpbuf);
+    return(retval);
+} /* fallbackFormatMessageW */
+
+static DWORD WINAPI fallbackGetModuleFileNameW(HMODULE hMod, LPWCH lpBuf,
+                                               DWORD nSize)
+{
+    char *cpbuf = (char *) smallAlloc(nSize);
+    DWORD retval = GetModuleFileNameA(hMod, cpbuf, nSize);
+    if (retval > 0)
+        MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,cpbuf,retval,lpBuf,nSize);
+    smallFree(cpbuf);
+    return(retval);
+} /* fallbackGetModuleFileNameW */
+
+static DWORD WINAPI fallbackGetFileAttributesW(LPCWSTR fname)
+{
+    DWORD retval = 0;
+    const int buflen = (int) (wStrLen(fname) + 1);
+    char *cpstr = (char *) smallAlloc(buflen);
+    WideCharToMultiByte(CP_ACP, 0, fname, buflen, cpstr, buflen, NULL, NULL);
+    retval = GetFileAttributesA(cpstr);
+    smallFree(cpstr);
+    return(retval);
+} /* fallbackGetFileAttributesW */
+
+static DWORD WINAPI fallbackGetCurrentDirectoryW(DWORD buflen, LPWSTR buf)
+{
+    DWORD retval = 0;
+    char *cpbuf = NULL;
+    if (buf != NULL)
+        cpbuf = (char *) smallAlloc(buflen);
+    retval = GetCurrentDirectoryA(buflen, cpbuf);
+    if (cpbuf != NULL)
+    {
+        MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,cpbuf,retval,buf,buflen);
+        smallFree(cpbuf);
+    } /* if */
+    return(retval);
+} /* fallbackGetCurrentDirectoryW */
+
+static BOOL WINAPI fallbackRemoveDirectoryW(LPCWSTR dname)
+{
+    BOOL retval = 0;
+    const int buflen = (int) (wStrLen(dname) + 1);
+    char *cpstr = (char *) smallAlloc(buflen);
+    WideCharToMultiByte(CP_ACP, 0, dname, buflen, cpstr, buflen, NULL, NULL);
+    retval = RemoveDirectoryA(cpstr);
+    smallFree(cpstr);
+    return(retval);
+} /* fallbackRemoveDirectoryW */
+
+static BOOL WINAPI fallbackCreateDirectoryW(LPCWSTR dname, 
+                                            LPSECURITY_ATTRIBUTES attr)
+{
+    BOOL retval = 0;
+    const int buflen = (int) (wStrLen(dname) + 1);
+    char *cpstr = (char *) smallAlloc(buflen);
+    WideCharToMultiByte(CP_ACP, 0, dname, buflen, cpstr, buflen, NULL, NULL);
+    retval = CreateDirectoryA(cpstr, attr);
+    smallFree(cpstr);
+    return(retval);
+} /* fallbackCreateDirectoryW */
+
+static BOOL WINAPI fallbackDeleteFileW(LPCWSTR fname)
+{
+    BOOL retval = 0;
+    const int buflen = (int) (wStrLen(fname) + 1);
+    char *cpstr = (char *) smallAlloc(buflen);
+    WideCharToMultiByte(CP_ACP, 0, fname, buflen, cpstr, buflen, NULL, NULL);
+    retval = DeleteFileA(cpstr);
+    smallFree(cpstr);
+    return(retval);
+} /* fallbackDeleteFileW */
+
+static HANDLE WINAPI fallbackCreateFileW(LPCWSTR fname, 
+                DWORD dwDesiredAccess, DWORD dwShareMode,
+                LPSECURITY_ATTRIBUTES lpSecurityAttrs,
+                DWORD dwCreationDisposition,
+                DWORD dwFlagsAndAttrs, HANDLE hTemplFile)
+{
+    HANDLE retval;
+    const int buflen = (int) (wStrLen(fname) + 1);
+    char *cpstr = (char *) smallAlloc(buflen);
+    WideCharToMultiByte(CP_ACP, 0, fname, buflen, cpstr, buflen, NULL, NULL);
+    retval = CreateFileA(cpstr, dwDesiredAccess, dwShareMode, lpSecurityAttrs,
+                         dwCreationDisposition, dwFlagsAndAttrs, hTemplFile);
+    smallFree(cpstr);
+    return(retval);
+} /* fallbackCreateFileW */
+
+static BOOL WINAPI fallbackMoveFileW(LPCWSTR src, LPCWSTR dst)
+{
+    BOOL retval;
+    const int srcbuflen = (int) (wStrLen(src) + 1);
+    char *srccpstr = (char *) smallAlloc(srcbuflen);
+    const int dstbuflen = (int) (wStrLen(dst) + 1);
+    char *dstcpstr = (char *) smallAlloc(dstbuflen);
+    WideCharToMultiByte(CP_ACP,0,src,srcbuflen,srccpstr,srcbuflen,NULL,NULL);
+    WideCharToMultiByte(CP_ACP,0,dst,dstbuflen,dstcpstr,dstbuflen,NULL,NULL);
+    retval = MoveFileA(srccpstr, dstcpstr);
+    smallFree(srccpstr);
+    smallFree(dstcpstr);
+    return(retval);
+} /* fallbackMoveFileW */
+
+static void WINAPI fallbackOutputDebugStringW(LPCWSTR str)
+{
+    const int buflen = (int) (wStrLen(str) + 1);
+    char *cpstr = (char *) smallAlloc(buflen);
+    WideCharToMultiByte(CP_ACP, 0, str, buflen, cpstr, buflen, NULL, NULL);
+    retval = OutputDebugStringA(cpstr);
+    smallFree(cpstr);
+} // fallbackOutputDebugStringW
+
+
+/* A blatant abuse of pointer casting... */
+static int symLookup(HMODULE dll, void **addr, const char *sym)
+{
+    return( (*addr = GetProcAddress(dll, sym)) != NULL );
+} /* symLookup */
+
+
+static int findApiSymbols(void)
+{
+    const boolean osHasUnicode = !osIsWin9x;
+    HMODULE dll = NULL;
+
+    #define LOOKUP_NOFALLBACK(x, reallyLook) { \
+        if (reallyLook) \
+            symLookup(dll, (void **) &p##x, #x); \
+        else \
+            p##x = NULL; \
+    }
+
+    #define LOOKUP(x, reallyLook) { \
+        if ((!reallyLook) || (!symLookup(dll, (void **) &p##x, #x))) \
+            p##x = fallback##x; \
+    }
+
+    /* Apparently Win9x HAS the Unicode entry points, they just don't WORK. */
+    /*  ...so don't look them up unless we're on NT+. (see osHasUnicode.) */
+
+    dll = libUserEnv = LoadLibraryA("userenv.dll");
+    if (dll != NULL)
+        LOOKUP_NOFALLBACK(GetUserProfileDirectoryW, osHasUnicode);
+
+    /* !!! FIXME: what do they call advapi32.dll on Win64? */
+    dll = libAdvApi32 = LoadLibraryA("advapi32.dll");
+    if (dll != NULL)
+        LOOKUP(GetUserNameW, osHasUnicode);
+
+    /* !!! FIXME: what do they call kernel32.dll on Win64? */
+    dll = libKernel32 = LoadLibraryA("kernel32.dll");
+    if (dll != NULL)
+    {
+        LOOKUP_NOFALLBACK(GetFileAttributesExA, 1);
+        LOOKUP_NOFALLBACK(GetFileAttributesExW, osHasUnicode);
+        LOOKUP_NOFALLBACK(FindFirstFileW, osHasUnicode);
+        LOOKUP_NOFALLBACK(FindNextFileW, osHasUnicode);
+        LOOKUP(GetModuleFileNameW, osHasUnicode);
+        LOOKUP(FormatMessageW, osHasUnicode);
+        LOOKUP(GetFileAttributesW, osHasUnicode);
+        LOOKUP(GetCurrentDirectoryW, osHasUnicode);
+        LOOKUP(CreateDirectoryW, osHasUnicode);
+        LOOKUP(RemoveDirectoryW, osHasUnicode);
+        LOOKUP(CreateFileW, osHasUnicode);
+        LOOKUP(DeleteFileW, osHasUnicode);
+        LOOKUP(MoveFileW, osHasUnicode);
+        LOOKUP(OutputDebugStringW, osHasUnicode);
+    } /* if */
+
+    /* !!! FIXME: what do they call shell32.dll on Win64? */
+    dll = libShell32 = LoadLibraryA("shell32.dll");
+    if (dll != NULL)
+        LOOKUP_NOFALLBACK(SHGetFolderPathA, 1);
+
+    #undef LOOKUP_NOFALLBACK
+    #undef LOOKUP
+
+    return(1);
+} /* findApiSymbols */
+
+
+
+// ok, now the actual platform layer implementation...
+
+static struct timeval startup_time;
+
+char *MojoPlatform_currentWorkingDir(void)
+{
+    char *retval = NULL;
+    WCHAR *wbuf = NULL;
+    DWORD buflen = 0;
+
+    buflen = pGetCurrentDirectoryW(buflen, NULL);
+    wbuf = (WCHAR *) smallAlloc((buflen + 2) * sizeof (WCHAR));
+    BAIL_IF_MACRO(wbuf == NULL, ERR_OUT_OF_MEMORY, NULL);
+    pGetCurrentDirectoryW(buflen, wbuf);
+
+    if (wbuf[buflen - 2] == '\\')
+        wbuf[buflen - 1] = '\0';  /* just in case... */
+    else
+    {
+        wbuf[buflen - 1] = '\\'; 
+        wbuf[buflen] = '\0'; 
+    } /* else */
+
+    retval = unicodeToUtf8Heap(wbuf);
+    smallFree(wbuf);
+    return(retval);
+} // MojoPlatform_currentWorkingDir
+
+
+char *MojoPlatform_readlink(const char *linkname)
+{
+    STUBBED("should use symlinks (reparse points) on Vista");
+    return NULL;
+} // MojoPlatform_readlink
+
+
+// !!! FIXME: this code sort of sucks.
+char *MojoPlatform_realpath(const char *path)
+{
+    // !!! FIXME: this should return NULL if (path) doesn't exist?
+    // !!! FIXME: Need to handle symlinks in Vista...
+    // !!! FIXME: try GetFullPathName() instead?
+
+    // this function should be UTF-8 clean.
+    char *retval = NULL;
+    char *p = NULL;
+
+    if ((path == NULL) || (*path == '\0'))
+        return NULL;
+
+    retval = (char *) xmalloc(MAX_PATH);
+
+    /*
+     * If in \\server\path format, it's already an absolute path.
+     *  We'll need to check for "." and ".." dirs, though, just in case.
+     */
+    if ((path[0] == '\\') && (path[1] == '\\'))
+        strcpy(retval, path);
+
+    else
+    {
+        char *currentDir = MojoPlatform_currentWorkingDir();
+        if (currentDir == NULL)
+        {
+            free(retval);
+            return NULL;
+        } // if
+
+        if (path[1] == ':')   /* drive letter specified? */
+        {
+            // Apparently, "D:mypath" is the same as "D:\\mypath" if
+            //  D: is not the current drive. However, if D: is the
+            //  current drive, then "D:mypath" is a relative path. Ugh.
+
+            if (path[2] == '\\')  // maybe an absolute path?
+                strcpy(retval, path);
+            else  // definitely an absolute path.
+            {
+                if (path[0] == currentDir[0]) // current drive; relative.
+                {
+                    strcpy(retval, currentDir);
+                    strcat(retval, path + 2);
+                } /* if */
+
+                else  // not current drive; absolute.
+                {
+                    retval[0] = path[0];
+                    retval[1] = ':';
+                    retval[2] = '\\';
+                    strcpy(retval + 3, path + 2);
+                } // else
+            } // else
+        } // if
+
+        else  // no drive letter specified.
+        {
+            if (path[0] == '\\')  // absolute path.
+            {
+                retval[0] = currentDir[0];
+                retval[1] = ':';
+                strcpy(retval + 2, path);
+            } /* if */
+            else
+            {
+                strcpy(retval, currentDir);
+                strcat(retval, path);
+            } // else
+        } // else
+
+        free(currentDir);
+    } // else
+
+    // (whew.) Ok, now take out "." and ".." path entries...
+
+    p = retval;
+    while ( (p = strstr(p, "\\.")) != NULL)
+    {
+        // it's a "." entry that doesn't end the string.
+        if (p[2] == '\\')
+            memmove(p + 1, p + 3, strlen(p + 3) + 1);
+
+        // it's a "." entry that ends the string.
+        else if (p[2] == '\0')
+            p[0] = '\0';
+
+        // it's a ".." entry.
+        else if (p[2] == '.')
+        {
+            char *prevEntry = p - 1;
+            while ((prevEntry != retval) && (*prevEntry != '\\'))
+                prevEntry--;
+
+            if (prevEntry == retval)  // make it look like a "." entry.
+                memmove(p + 1, p + 2, strlen(p + 2) + 1);
+            else
+            {
+                if (p[3] != '\0') // doesn't end string.
+                    *prevEntry = '\0';
+                else // ends string.
+                    memmove(prevEntry + 1, p + 4, strlen(p + 4) + 1);
+
+                p = prevEntry;
+            } // else
+        } // else if
+
+        else
+        {
+            p++;  // look past current char.
+        } // else
+    } // while
+
+    // shrink the retval's memory block if possible...
+    return((char *) xrealloc(retval, strlen(retval) + 1));
+} // MojoPlatform_realpath
+
+
+char *MojoPlatform_appBinaryPath(void)
+{
+    DWORD buflen = 64;
+    LPWSTR modpath = NULL;
+    char *retval = NULL;
+    DWORD rc = 0;
+
+    while (true)
+    {
+        void *ptr = xrealloc(modpath, buflen * sizeof(WCHAR));
+
+        modpath = (LPWSTR) ptr;
+
+        rc = pGetModuleFileNameW(NULL, modpath, buflen);
+        if (rc == 0)
+        {
+            free(modpath);
+            return NULL;
+        } // if
+
+        if (rc < buflen)
+        {
+            buflen = rc;
+            break;
+        } // if
+
+        buflen *= 2;
+    } // while
+
+    if (buflen > 0)  // just in case...
+    {
+        WCHAR *ptr = (modpath + buflen) - 1;
+        while (ptr != modpath)
+        {
+            if (*ptr == '\\')
+                break;
+            ptr--;
+        } // while
+
+        if ((ptr != modpath) || (*ptr == '\\'))  // should always be true...
+        {
+            *(ptr + 1) = '\0';  // chop off filename.
+            retval = unicodeToUtf8Heap(modpath);
+        } // else
+    } // else
+
+    free(modpath);
+    return(retval);
+} // MojoPlatform_appBinaryPath
+
+
+// Try to make use of GetUserProfileDirectoryW(), which isn't available on
+//  some common variants of Win32. If we can't use this, we just punt and
+//  use the binary path for the user dir, too.
+//
+// On success, module-scope variable (userDir) will have a pointer to
+//  a malloc()'d string of the user's profile dir, and a non-zero value is
+//  returned. If we can't determine the profile dir, (userDir) will
+//  be NULL, and zero is returned.
+
+char *MojoPlatform_homedir(void)
+{
+    char *userDir = NULL;
+
+    // GetUserProfileDirectoryW() is only available on NT 4.0 and later.
+    //  This means Win95/98/ME (and CE?) users have to do without, so for
+    //  them, we'll default to the base directory when we can't get the
+    //  function pointer. Since this is originally an NT API, we don't
+	//  offer a non-Unicode fallback.
+
+    if (pGetUserProfileDirectoryW != NULL)
+    {
+        HANDLE accessToken = NULL;       // Security handle to process
+        HANDLE processHandle = GetCurrentProcess();
+        if (OpenProcessToken(processHandle, TOKEN_QUERY, &accessToken))
+        {
+            DWORD psize = 0;
+            WCHAR dummy = 0;
+            LPWSTR wstr = NULL;
+            BOOL rc = 0;
+
+            // Should fail. Will write the size of the profile path in
+            //  psize. Also note that the second parameter can't be
+            //  NULL or the function fails.
+    		rc = pGetUserProfileDirectoryW(accessToken, &dummy, &psize);
+            if (rc == 0)  // this should always be true!
+            {
+                // Allocate memory for the profile directory
+                wstr = (LPWSTR) smallAlloc(psize * sizeof (WCHAR));
+                if (wstr != NULL)
+                {
+                    if (pGetUserProfileDirectoryW(accessToken, wstr, &psize))
+                        userDir = unicodeToUtf8Heap(wstr);
+                    smallFree(wstr);
+                } // else
+            } // if
+
+            CloseHandle(accessToken);
+        } // if
+    } // if
+
+    if (userDir == NULL)  // couldn't get profile for some reason.
+    {
+        // Might just be a non-NT system; try SHGetFolderPathA()...
+        if (pSHGetFolderPath != NULL)  // can be NULL if IE5+ isn't installed!
+        {
+            char shellPath[MAX_PATH];
+            HRESULT status = pSHGetFolderPath(NULL, CSIDL_PERSONAL, NULL,
+                                              SHGFP_TYPE_CURRENT, shellPath);
+            if (SUCCEEDED(status))
+                userDir = codepageToUtf8Heap(shellPath);
+        } // if
+    } // if
+
+    if (userDir == NULL)  // Still nothing?!
+    {
+        // this either means we had a catastrophic failure, or we're on a
+        // Win95 system without at least Internet Explorer 5.0. Bleh!
+        userDir = xstrdup("C:\\My Documents");  // good luck with that.
+    } // if
+
+    return userDir;
+} // MojoPlatform_homedir
+
+
+// This implementation is a bit naive.
+boolean MojoPlatform_locale(char *buf, size_t len)
+{
+    boolean retval = false;
+    char lang[16];
+    char country[16];
+
+	const int langrc = GetLocaleInfoA(LOCALE_USER_DEFAULT,
+                                      LOCALE_SISO639LANGNAME,
+                                      lang, sizeof (lang));
+
+	const int ctryrc =  GetLocaleInfoA(LOCALE_USER_DEFAULT,
+                                       LOCALE_SISO3166CTRYNAME,
+                                       country, sizeof (country));
+
+    // Win95 systems will fail, because they don't have LOCALE_SISO*NAME ...
+    if (langrc != 0) && (ctryrc != 0)
+    {
+        snprintf(buf, len, "%s_%s", lang, country);
+        retval = true;
+    } // if
+
+    return retval;
+} // MojoPlatform_locale
+
+
+boolean MojoPlatform_osType(char *buf, size_t len)
+{
+    if (osIsWin9x)
+        xstrncpy(buf, "win9x", len);
+    else
+        xstrncpy(buf, "winnt", len);
+
+    return true;
+} // MojoPlatform_ostype
+
+
+boolean MojoPlatform_osVersion(char *buf, size_t len)
+{
+    snprintf(buf, len, "%u.%u.%u",
+             (unsigned int) osMajorVer,
+             (unsigned int) osMinorVer,
+             (unsigned int) osBuildVer);
+    return true;
+} // MojoPlatform_osversion
+
+
+void MojoPlatform_sleep(uint32 ticks)
+{
+    Sleep(ticks);
+} // MojoPlatform_sleep
+
+
+uint32 MojoPlatform_ticks(void)
+{
+    return GetTickCount() - startupTime;
+} // MojoPlatform_ticks
+
+
+void MojoPlatform_die(void)
+{
+    STUBBED("Win32 equivalent of _exit()?");
+    _exit(86);
+} // MojoPlatform_die
+
+
+boolean MojoPlatform_unlink(const char *fname)
+{
+    int retval = 0;
+    LPWSTR wpath;
+    UTF8_TO_UNICODE_STACK_MACRO(wpath, fname);
+    if (pGetFileAttributesW(wpath) == FILE_ATTRIBUTE_DIRECTORY)
+        retval = (pRemoveDirectoryW(wpath) != 0);
+    else
+        retval = (pDeleteFileW(wpath) != 0);
+    smallFree(wpath);
+    return retval;
+} // MojoPlatform_unlink
+
+
+boolean MojoPlatform_symlink(const char *src, const char *dst)
+{
+    STUBBED("Vista has symlink support");
+    return false;
+} // MojoPlatform_symlink
+
+
+boolean MojoPlatform_mkdir(const char *path, uint16 perms)
+{
+    // !!! FIXME: error if already exists?
+    // !!! FIXME: perms?
+    WCHAR *wpath;
+    DWORD rc;
+    UTF8_TO_UNICODE_STACK_MACRO(wpath, path);
+    rc = pCreateDirectoryW(wpath, NULL);
+    smallFree(wpath);
+    return (rc != 0);
+} // MojoPlatform_mkdir
+
+
+boolean MojoPlatform_rename(const char *src, const char *dst)
+{
+    WCHAR *srcwpath;
+    WCHAR *dstwpath;
+    BOOL rc;
+    MojoPlatform_unlink(dst);  // to match Unix rename()...
+    UTF8_TO_UNICODE_STACK_MACRO(srcwpath, src);
+    UTF8_TO_UNICODE_STACK_MACRO(dstwpath, dst);
+    rc = pMoveFileW(srcwpath, dstwpath);
+    smallFree(srcwpath);
+    smallFree(dstwpath);
+    return (rc != 0);
+} // MojoPlatform_rename
+
+
+boolean MojoPlatform_exists(const char *dir, const char *fname)
+{
+    WCHAR *wpath;
+    char *fullpath = NULL;
+    boolean retval = false;
+
+    if (fname == NULL)
+        fullpath = xstrdup(dir);
+    else
+    {
+        const size_t len = strlen(dir) + strlen(fname) + 1;
+        fullpath = (char *) xmalloc(len);
+        snprintf(fullpath, len, "%s\\%s", dir, fname);
+    } // else
+
+    UTF8_TO_UNICODE_STACK_MACRO(wpath, fullpath);
+    retval = (pGetFileAttributesW(wpath) == INVALID_FILE_ATTRIBUTES);
+    smallFree(wpath);
+    free(fullpath);
+
+    return retval;
+} // MojoPlatform_exists
+
+
+boolean MojoPlatform_writable(const char *fname)
+{
+    boolean retval = false;
+    DWORD attr = 0;
+    WCHAR *wpath;
+    UTF8_TO_UNICODE_STACK_MACRO(wpath, fname);
+    attr = pGetFileAttributesW(wpath);
+    smallFree(wpath);
+    if (attr != INVALID_FILE_ATTRIBUTES)
+        retval = ((attr & FILE_ATTRIBUTE_READONLY) == 0);
+    return retval;
+} // MojoPlatform_writable
+
+
+boolean MojoPlatform_isdir(const char *dir)
+{
+    boolean retval = false;
+    LPWSTR wpath;
+    UTF8_TO_UNICODE_STACK_MACRO(wpath, dir);
+    retval = ((pGetFileAttributesW(wpath) & FILE_ATTRIBUTE_DIRECTORY) != 0);
+    smallFree(wpath);
+    return retval;
+} // MojoPlatform_isdir
+
+
+static boolean isSymlinkAttrs(const DWORD attr, const DWORD tag)
+{
+    return ( (attr & FILE_ATTRIBUTE_REPARSE_POINT) && 
+             (tag == PHYSFS_IO_REPARSE_TAG_SYMLINK) );
+} // isSymlinkAttrs
+
+
+boolean MojoPlatform_issymlink(const char *fname)
+{
+    /* !!! FIXME:
+     * Windows Vista can have NTFS symlinks. Can older Windows releases have
+     *  them when talking to a network file server? What happens when you
+     *  mount a NTFS partition on XP that was plugged into a Vista install
+     *  that made a symlink?
+     */
+
+    boolean retval = false;
+    LPWSTR wpath;
+    HANDLE dir;
+    WIN32_FIND_DATAW entw;
+
+    // no unicode entry points? Probably no symlinks.
+    if (pFindFirstFileW == NULL)
+        return false;
+
+    // !!! FIXME: filter wildcard chars?
+    UTF8_TO_UNICODE_STACK_MACRO(wpath, fname);
+    dir = pFindFirstFileW(wpath, &entw);
+    smallFree(wpath);
+
+    if (dir != INVALID_HANDLE_VALUE)
+    {
+        retval = isSymlinkAttrs(entw.dwFileAttributes, entw.dwReserved0);
+        FindClose(dir);
+    } // if
+
+    return retval;
+} // MojoPlatform_issymlink
+
+
+boolean MojoPlatform_isfile(const char *dir)
+{
+    return ((!MojoPlatform_isdir(dir)) && (!MojoPlatform_issymlink(dir)));
+} // MojoPlatform_isfile
+
+
+void *MojoPlatform_open(const char *fname, uint32 flags, uint16 mode)
+{
+    HANDLE *retval = NULL;
+    DWORD accessMode = 0;
+    DWORD createMode = 0;
+    DWORD shareMode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
+    WCHAR *wpath = NULL;
+    HANDLE fd = 0;
+
+    if (flags & MOJOFILE_READ)
+        accessMode |= GENERIC_READ;
+    if (flags & MOJOFILE_WRITE)
+        accessMode |= GENERIC_WRITE;
+    if (accessMode == 0)
+        return NULL;  // have to specify SOMETHING.
+
+//    if (flags & MOJOFILE_APPEND)
+//        unixflags |= O_APPEND;
+
+    if ((flags & MOJOFILE_CREATE) && (flags & MOJOFILE_EXCLUSIVE))
+        createMode = CREATE_NEW;
+    else if ((flags & MOJOFILE_CREATE) && (flags & MOJOFILE_TRUNCATE))
+        createMode = CREATE_ALWAYS;
+    else if (flags & MOJOFILE_CREATE)
+        createMode = OPEN_ALWAYS;
+    else if (flags & MOJOFILE_TRUNCATE)
+        createMode = TRUNCATE_EXISTING;
+    else
+        createMode = OPEN_EXISTING;
+
+    // !!! FIXME
+    STUBBED("file permissions");
+
+    UTF8_TO_UNICODE_STACK_MACRO(wpath, fname);
+    fd = pCreateFileW(wpath, accessMode, shareMode, NULL, createMode,
+                      FILE_ATTRIBUTE_NORMAL, NULL);
+    smallFree(wpath);
+
+    if (fd != INVALID_HANDLE_VALUE)
+    {
+        retval = (HANDLE *) xmalloc(sizeof (HANDLE));
+        *retval = fd;
+    } // if
+
+    return retval;
+} // MojoPlatform_open
+
+
+int64 MojoPlatform_read(void *fd, void *buf, uint32 bytes)
+{
+    HANDLE handle = *((HANDLE *) fd);
+    DWORD br = 0;
+
+    // Read data from the file
+    // !!! FIXME: uint32 might be a greater # than DWORD
+    if(!ReadFile(handle, buf, bytes, &br, NULL))
+        return -1;
+
+    return (int64) br;
+} // MojoPlatform_read
+
+
+int64 MojoPlatform_write(void *fd, const void *buf, uint32 bytes)
+{
+    HANDLE handle = *((HANDLE *) fd);
+    DWORD bw = 0;
+
+    // Read data from the file
+    // !!! FIXME: uint32 might be a greater # than DWORD
+    if(!WriteFile(handle, buf, bytes, &bw, NULL))
+        return -1;
+
+    return (int64) bw;
+} // MojoPlatform_write
+
+
+int64 MojoPlatform_tell(void *fd)
+{
+    return MojoPlatform_seek(fd, 0, MOJOSEEK_CURRENT);
+} // MojoPlatform_tell
+
+
+int64 MojoPlatform_seek(void *fd, int64 offset, MojoFileSeek whence)
+{
+    HANDLE handle = *((HANDLE *) fd);
+    DWORD HighOrderPos = HIGHORDER_UINT64(pos);
+    DWORD winwhence = 0;
+    DWORD rc = 0;
+
+    switch (whence)
+    {
+        case MOJOSEEK_SET: winwhence = FILE_BEGIN; break;
+        case MOJOSEEK_CURRENT: winwhence = FILE_CURRENT; break;
+        case MOJOSEEK_END: winwhence = FILE_END; break;
+        default: return -1;  // !!! FIXME: maybe just abort?
+    } // switch
+
+    rc = SetFilePointer(handle,LOWORDER_UINT64(pos),&HighOrderPos,winwhence);
+    if ( (rc == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR) )
+        return -1;
+
+    return (int64) ((((uint64) HighOrderPos) << 32) | ((uint64) rc));
+} // MojoPlatform_seek
+
+
+int64 MojoPlatform_flen(void *fd)
+{
+    HANDLE handle = *((HANDLE *) fd);
+    int64 retval = 0;
+    DWORD SizeHigh = 0;
+    DWORD SizeLow = GetFileSize(handle, &SizeHigh);
+
+    if ((SizeLow == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
+        return -1;
+    else
+    {
+        // Combine the high/low order to create the 64-bit position value
+        retval = (int64) ((((uint64) SizeHigh) << 32) | ((uint64) SizeLow));
+        assert(retval >= 0);
+    } // else
+
+    return retval;
+} // MojoPlatform_flen
+
+
+boolean MojoPlatform_flush(void *fd)
+{
+    HANDLE handle = *((HANDLE *) fd);
+    return (FlushFileBuffers(handle) != 0);
+} // MojoPlatform_flush
+
+
+boolean MojoPlatform_close(void *fd)
+{
+    HANDLE handle = *((HANDLE *) fd);
+    boolean retval = (CloseHandle(handle) != 0);
+    if (retval)
+        free(fd);
+    return retval;
+} // MojoPlatform_close
+
+
+typedef struct
+{
+    HANDLE dir;
+    boolean done;
+    WIN32_FIND_DATA ent;
+    WIN32_FIND_DATAW entw;
+} WinApiDir;
+
+void *MojoPlatform_opendir(const char *dirname)
+{
+    const int unicode = (pFindFirstFileW != NULL) && (pFindNextFileW != NULL);
+    size_t len = strlen(dirname);
+    char *searchPath = NULL;
+    WCHAR *wSearchPath = NULL;
+    WinApiDir *retval = (WinApiDir *) xmalloc(sizeof (WinApiDir));
+
+    retval->dir = INVALID_HANDLE_VALUE;
+    retval->done = false;
+
+    // Allocate a new string for path, maybe '\\', "*", and NULL terminator
+    searchPath = (char *) smallAlloc(len + 3);
+
+    // Copy current dirname
+    strcpy(searchPath, dirname);
+
+    // if there's no '\\' at the end of the path, stick one in there.
+    if (searchPath[len - 1] != '\\')
+    {
+        searchPath[len++] = '\\';
+        searchPath[len] = '\0';
+    } // if
+
+    // Append the "*" to the end of the string
+    strcat(searchPath, "*");
+
+    UTF8_TO_UNICODE_STACK_MACRO(wSearchPath, searchPath);
+
+    if (unicode)
+        retval->dir = pFindFirstFileW(wSearchPath, &retval->entw);
+    else
+    {
+        const int len = (int) (wStrLen(wSearchPath) + 1);
+        char *cp = (char *) smallAlloc(len);
+        WideCharToMultiByte(CP_ACP, 0, wSearchPath, len, cp, len, 0, 0);
+        retval->dir = FindFirstFileA(cp, &retval->ent);
+        smallFree(cp);
+    } // else
+
+    smallFree(wSearchPath);
+    smallFree(searchPath);
+    if (retval->dir == INVALID_HANDLE_VALUE)
+    {
+        free(retval);
+        return NULL;
+    } // if
+
+    return retval;
+} // MojoPlatform_opendir
+
+
+char *MojoPlatform_readdir(void *_dirhandle)
+{
+    const int unicode = (pFindFirstFileW != NULL) && (pFindNextFileW != NULL);
+    const WinApiDir *dir = (WinApiDir *) _dirhandle;
+    char *utf8 = NULL;
+
+    if (dir->done)
+        return NULL;
+
+    if (unicode)
+    {
+        do
+        {
+            const DWORD attr = dir->entw.dwFileAttributes;
+            const DWORD tag = dir->entw.dwReserved0;
+            const WCHAR *fn = dir->entw.cFileName;
+            if ((fn[0] == '.') && (fn[1] == '\0'))
+                continue;
+            if ((fn[0] == '.') && (fn[1] == '.') && (fn[2] == '\0'))
+                continue;
+
+            utf8 = unicodeToUtf8Heap(fn);
+            dir->done = (pFindNextFileW(dir->dir, &dir->entw) == 0);
+            return utf8;
+        } while (pFindNextFileW(dir->dir, &dir->entw) != 0);
+    } // if
+
+    else  // ANSI fallback.
+    {
+        do
+        {
+            const DWORD attr = ent.dwFileAttributes;
+            const DWORD tag = ent.dwReserved0;
+            const char *fn = ent.cFileName;
+            if ((fn[0] == '.') && (fn[1] == '\0'))
+                continue;
+            if ((fn[0] == '.') && (fn[1] == '.') && (fn[2] == '\0'))
+                continue;
+
+            utf8 = codepageToUtf8Heap(fn);
+            dir->done = (FindNextFileA(dir, &ent) == 0);
+            return utf8;
+        } while (FindNextFileA(dir, &ent) != 0);
+    } // else
+
+    dir->done = true;
+    return NULL;
+} // MojoPlatform_readdir
+
+
+void MojoPlatform_closedir(void *dirhandle)
+{
+    WinApiDir *dir = (WinApiDir *) dirhandle;
+    if (dir)
+    {
+        FindClose(dir->dir);
+        free(dir);
+    } // if
+} // MojoPlatform_closedir
+
+
+int64 MojoPlatform_filesize(const char *fname)
+{
+    // !!! FIXME: this is lame.
+    int64 retval = -1;
+    void *fd = MojoPlatform_open(const char *fname, MOJOFILE_READ, 0);
+    STUBBED("use a stat()-like thing instead");
+    if (fd != NULL)
+    {
+        retval = MojoPlatform_seek(fd, 0, MOJOSEEK_END);
+        MojoPlatform_close(fd);
+    } // if
+
+    return retval;
+} // MojoPlatform_filesize
+
+
+boolean MojoPlatform_perms(const char *fname, uint16 *p)
+{
+    STUBBED("Windows permissions");
+    *p = 0;
+    return true;
+} // MojoPlatform_perms
+
+
+uint16 MojoPlatform_defaultFilePerms(void)
+{
+    STUBBED("Windows permissions");
+    return 0644;
+} // MojoPlatform_defaultFilePerms
+
+
+uint16 MojoPlatform_defaultDirPerms(void)
+{
+    STUBBED("Windows permissions");
+    return 0755;
+} // MojoPlatform_defaultDirPerms
+
+
+uint16 MojoPlatform_makePermissions(const char *str, boolean *_valid)
+{
+    STUBBED("Windows permissions");
+    *_valid = true;
+    return 0;
+} // MojoPlatform_makePermissions
+
+
+boolean MojoPlatform_chmod(const char *fname, uint16 p)
+{
+    STUBBED("Windows permissions");
+    return true;
+    //return (chmod(fname, p) != -1);
+} // MojoPlatform_chmod
+
+
+static BOOL mediaInDrive(const char *drive)
+{
+    // Prevent windows warning message appearing when checking media size
+    UINT oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+    DWORD tmp = 0;
+    // If the function succeeds, there's media in the drive
+    BOOL retval = GetVolumeInformationA(drive,NULL,0,NULL,NULL,&tmp,NULL,0);
+
+    // Revert back to old windows error handler
+    SetErrorMode(oldErrorMode);
+    return retval;
+} // mediaInDrive
+
+
+char *MojoPlatform_findMedia(const char *uniquefile)
+{
+    // !!! FIXME: Probably shouldn't just check drive letters...
+
+    char drive_str[4] = { 'x', ':', '\\', '\0' };
+    char ch;
+    UINT rc;
+    boolean found = false;
+
+    for (ch = 'A'; ch <= 'Z'; ch++)
+    {
+        drive_str[0] = ch;
+        rc = GetDriveTypeA(drive_str);
+        if ((rc != DRIVE_UNKNOWN) && (rc != DRIVE_NO_ROOT_DIR))
+        {
+            if (mediaInDrive(drive_str))
+            {
+                drive_str[2] = '\0';
+                found = (MojoPlatform_exists(drive_str, uniquefile));
+                drive_str[2] = '\\';
+                if (found)
+                    return xstrdup(drive_str);
+            } // if
+        } // if
+    } // for
+
+    return NULL;
+} // MojoPlatform_findMedia
+
+
+void MojoPlatform_log(const char *str)
+{
+    if (pOutputDebugStringW != NULL) // in case this gets called before init...
+    {
+        WCHAR *wstr;
+        UTF8_TO_UNICODE_STACK_MACRO(wstr, str);
+        STUBBED("OutputDebugString() is probably not best here");
+        pOutputDebugStringW(wstr);
+        smallFree(wstr);
+    } // if
+} // MojoPlatform_log
+
+
+typedef struct
+{
+    HINSTANCE dll;
+    HANDLE file;
+} WinApiDll;
+
+void *MojoPlatform_dlopen(const uint8 *img, size_t len)
+{
+    WinApiDll *retval = NULL;
+    char path[MAX_PATH];
+    char fname[MAX_PATH];
+    DWORD bw = 0;
+    HANDLE handle;
+    HINSTANCE dll;
+
+    GetTempPath(sizeof (path), path);
+    GetTempFileName(path, "mojosetup-plugin-", 0, fname);
+
+    handle = CreateFileA(fname, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+    if (handle == INVALID_HANDLE_VALUE)
+        return NULL;
+
+    WriteFile(handle, img, len, &bw, NULL);  // dump it to the temp file.
+
+    CloseHandle(handle);
+    if (bw != len)
+    {
+        DeleteFile(fname);
+        return NULL;
+    } // if
+
+    // The DELETE_ON_CLOSE will cause the kernel to remove the file when
+    //  we're done with it, including manually closing or the process
+    //  terminating (including crashing). We hold this handle until we close
+    //  the library.
+    handle = CreateFileA(fname, GENERIC_READ, FILE_SHARE_READ, NULL,
+                         OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);
+    if (handle == INVALID_HANDLE_VALUE)
+    {
+        DeleteFile(fname);
+        return NULL;
+    } // if
+
+    dll = LoadLibraryA(fname);
+    if (dll == NULL)
+    {
+        CloseHandle(handle);  // (also deletes temp file.)
+        return NULL;
+    } // if
+
+    retval = (WinApiDll *) xmalloc(sizeof (WinApiDll));
+    retval->dll = dll;
+    retval->file = handle;
+    return retval;
+} // MojoPlatform_dlopen
+
+
+void *MojoPlatform_dlsym(void *_lib, const char *sym)
+{
+    const WinApiDll *lib = (const WinApiDll *) _lib;
+    return ((lib) ? GetProcAddress(lib->dll, sym) : NULL);
+} // MojoPlatform_dlsym
+
+
+void MojoPlatform_dlclose(void *_lib)
+{
+    const WinApiDll *lib = (const WinApiDll *) _lib;
+    if (lib)
+    {
+        FreeLibrary(lib->dll);
+        CloseHandle(lib->handle);  // this also deletes the temp file.
+        free(lib);
+    } // if
+} // MojoPlatform_dlclose
+
+
+// Get OS info and save the important parts.
+//  Returns non-zero if successful, otherwise it returns zero on failure.
+static boolean getOSInfo(void)
+{
+    OSVERSIONINFO osVerInfo;
+    osVerInfo.dwOSVersionInfoSize = sizeof(osVerInfo);
+    if (!GetVersionEx(&osVerInfo))
+        return false;
+
+    osIsWin9x = (osVerInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
+    osMajorVer = (uint32) osVerInfo.dwMajorVersion;
+    osMinorVer = (uint32) osVerInfo.dwMinorVersion;
+    osBuildVer = (uint32) osVerInfo.dwBuildNumber;
+
+    return true;
+} // getOSInfo
+
+
+static boolean platformInit(void)
+{
+    startupTime = GetTickCount();
+
+    if (!getOSInfo())
+        return false;
+
+    if (!findApiSymbols())
+        return false;
+
+    return true;
+} // platformInit
+
+
+static void platformDeinit(void)
+{
+    HANDLE *libs[] = { &libKernel32, &libUserEnv, &libAdvApi32, &libShell32 };
+    int i;
+
+    for (i = 0; i < (sizeof (libs) / sizeof (libs[0])); i++)
+    {
+        const HANDLE lib = *(libs[i]);
+        if (lib)
+        {
+            FreeLibrary(lib);
+            *(libs[i]) = NULL;
+        } // if
+    } // for
+} // platformDeinit
+
+
+static void buildCommandlineArray(LPSTR szCmd, int *_argc, char **_argv)
+{
+    int argc = 0;
+    char **argv = NULL;
+
+    // !!! FIXME: STUBBED("parse command line string into array");
+
+    *_argc = argc;
+    *_argv = argv;
+} // buildCommandlineArray
+
+
+static void freeCommandlineArray(int argc, char **argv)
+{
+    while (argc--)
+        free(argv[argc]);
+    free(argv);
+} // freeCommandlineArray
+
+
+int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmd, int nCmdShow)
+{
+    int retval = 0;
+    int argc = 0;
+    char **argv = NULL;
+
+    if (!platformInit())
+        retval = 1;
+    else
+    {
+        buildCommandlineArray(szCmd, &argc, &argv);
+        //openlog("mojosetup", LOG_PID, LOG_USER);
+        //atexit(closelog);
+        STUBBED("signal handlers");
+        //install_signals();
+        retval = MojoSetup_main(argc, argv);
+        freeCommandlineArray(argc, argv);
+
+        platformDeinit();
+    } // else
+
+    return retval;
+} // main
+
+#endif  // PLATFORM_WINDOWS
+
+// end of windows.c ...
+




More information about the mojosetup-commits mailing list