Home | History | Annotate | Download | only in dbus
      1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
      2 /* dbus-sysdeps-wince-glue.c Wrappers for Windows CE around system/libc features (internal to D-BUS implementation)
      3  *
      4  * Copyright (C) 2002, 2003  Red Hat, Inc.
      5  * Copyright (C) 2003 CodeFactory AB
      6  * Copyright (C) 2005 Novell, Inc.
      7  * Copyright (C) 2006 Ralf Habacker <ralf.habacker (at) freenet.de>
      8  * Copyright (C) 2006 Peter Kmmel  <syntheticpp (at) gmx.net>
      9  * Copyright (C) 2006 Christian Ehrlicher <ch.ehrlicher (at) gmx.de>
     10  *
     11  * Licensed under the Academic Free License version 2.1
     12  *
     13  * This program is free software; you can redistribute it and/or modify
     14  * it under the terms of the GNU General Public License as published by
     15  * the Free Software Foundation; either version 2 of the License, or
     16  * (at your option) any later version.
     17  *
     18  * This program is distributed in the hope that it will be useful,
     19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     21  * GNU General Public License for more details.
     22  *
     23  * You should have received a copy of the GNU General Public License
     24  * along with this program; if not, write to the Free Software
     25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     26  *
     27  */
     28 
     29 #include <config.h>
     30 #include "dbus-internals.h"
     31 #include "dbus-sysdeps.h"
     32 #include "dbus-sysdeps-win.h"
     33 
     34 #include <windows.h>
     35 /* Including shlobj.h creates trouble on some compilers.  Just chicken
     36    out here by defining just what we need.  */
     37 #ifndef CSIDL_PERSONAL
     38 #define CSIDL_PERSONAL 5
     39 #endif
     40 
     41 
     42 /* Copy SRC to DEST, returning the address of the terminating '\0' in DEST.  */
     43 static char *
     44 stpcpy (char *dest, const char *src)
     45 {
     46   char *d = dest;
     47   const char *s = src;
     48 
     49   do
     50     *d++ = *s;
     51   while (*s++ != '\0');
     52 
     53   return d - 1;
     54 }
     55 
     56 
     57 /* This is special cased, because we must avoid using many dbus
     58    functions (such as memory allocations): Those functions may in turn
     59    cause verbose output and check the flag!  */
     60 static char *
     61 get_verbose_setting()
     62 {
     63   const wchar_t dir[] = L"Software\\freedesktop\\DBus";
     64   const wchar_t name[] = L"Verbose";
     65   HKEY root_key;
     66   HKEY key_handle;
     67   DWORD nbytes;
     68   DWORD n1;
     69   DWORD type;
     70   wchar_t *result_w = NULL;
     71   char *result;
     72   int len;
     73 
     74   root_key = HKEY_LOCAL_MACHINE;
     75   if (RegOpenKeyExW (root_key, dir, 0, KEY_READ, &key_handle))
     76     return NULL;
     77 
     78   nbytes = 1;
     79   if (RegQueryValueExW (key_handle, name, 0, NULL, NULL, &nbytes))
     80     {
     81       RegCloseKey (key_handle);
     82       return NULL;
     83     }
     84   /* Round up to multiple of wchar_t, convert to number of wchar_t's, and add 1.  */
     85   n1 = ((nbytes + sizeof(wchar_t) - 1) / sizeof (wchar_t)) + 1;
     86   result_w = malloc (n1 * sizeof (wchar_t));
     87   if (!result_w)
     88     {
     89       RegCloseKey (key_handle);
     90       return NULL;
     91     }
     92   if (RegQueryValueExW (key_handle, name, 0, &type, (LPBYTE) result_w, &nbytes))
     93     {
     94       RegCloseKey (key_handle);
     95       free (result_w);
     96       return NULL;
     97     }
     98   RegCloseKey (key_handle);
     99   result_w[n1 - 1] = 0; /* Make sure it is really a string.  */
    100 
    101   /* NOTE: REG_MULTI_SZ and REG_EXPAND_SZ not supported, because they
    102      are not needed in this module.  */
    103   if (type != REG_SZ)
    104     {
    105       free (result_w);
    106       return NULL;
    107     }
    108 
    109   len = WideCharToMultiByte (CP_UTF8, 0, result_w, -1, NULL, 0, NULL, NULL);
    110   if (len < 0)
    111     {
    112       free (result_w);
    113       return NULL;
    114     }
    115 
    116   result = malloc (len + 1);
    117   if (!result)
    118     {
    119       free (result_w);
    120       return NULL;
    121     }
    122 
    123   len = WideCharToMultiByte (CP_UTF8, 0, result_w, -1, result, len, NULL, NULL);
    124   free (result_w);
    125   if (len < 0)
    126     {
    127       free (result);
    128       return NULL;
    129     }
    130   return result;
    131 }
    132 
    133 
    134 /* Return a string from the W32 Registry or NULL in case of error.
    135    Caller must release the return value.  A NULL for root is an alias
    136    for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */
    137 static char *
    138 read_w32_registry_string (const char *root, const char *dir, const char *name)
    139 {
    140   HKEY root_key, key_handle;
    141   DWORD n1, nbytes, type;
    142   char *result = NULL;
    143 
    144   if ( !root )
    145     root_key = HKEY_CURRENT_USER;
    146   else if ( !strcmp( root, "HKEY_CLASSES_ROOT" ) )
    147     root_key = HKEY_CLASSES_ROOT;
    148   else if ( !strcmp( root, "HKEY_CURRENT_USER" ) )
    149     root_key = HKEY_CURRENT_USER;
    150   else if ( !strcmp( root, "HKEY_LOCAL_MACHINE" ) )
    151     root_key = HKEY_LOCAL_MACHINE;
    152   else if ( !strcmp( root, "HKEY_USERS" ) )
    153     root_key = HKEY_USERS;
    154   else
    155     return NULL;
    156 
    157   if (RegOpenKeyExA (root_key, dir, 0, KEY_READ, &key_handle))
    158     {
    159       if (root)
    160         return NULL; /* no need for a RegClose, so return direct */
    161       /* It seems to be common practise to fall back to HKLM. */
    162       if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
    163         return NULL; /* still no need for a RegClose, so return direct */
    164     }
    165 
    166   nbytes = 1;
    167   if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
    168     {
    169       if (root)
    170         goto out;
    171       /* Try to fallback to HKLM also for a missing value.  */
    172       RegCloseKey (key_handle);
    173       if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
    174         return NULL; /* Nope.  */
    175       if (RegQueryValueExA (key_handle, name, 0, NULL, NULL, &nbytes))
    176         goto out;
    177     }
    178   n1 = nbytes + 1;
    179   result = malloc (n1);
    180   if (!result)
    181     goto out;
    182   if (RegQueryValueExA (key_handle, name, 0, &type, result, &n1))
    183     {
    184       free(result);
    185       result = NULL;
    186       goto out;
    187     }
    188   result[nbytes] = 0; /* Make sure it is really a string.  */
    189 
    190  out:
    191   RegCloseKey (key_handle);
    192   return result;
    193 }
    194 
    195 
    196 static char *
    197 find_inst_dir ()
    198 {
    199   return read_w32_registry_string ("HKEY_LOCAL_MACHINE",
    200 				  "Software\\freedesktop\\DBus",
    201 				  "Install Directory");
    202 }
    203 
    204 
    205 static char *
    206 find_env_in_registry (const char *name)
    207 {
    208   return read_w32_registry_string ("HKEY_LOCAL_MACHINE",
    209                                    "Software\\freedesktop\\DBus",
    210                                    name);
    211 }
    212 
    213 
    214 static char *
    215 find_program_in_inst_dir (const char *name)
    216 {
    217   char *result = NULL;
    218   char *tmp;
    219 
    220   tmp = find_inst_dir ();
    221   if (!tmp)
    222     return NULL;
    223 
    224   result = malloc (strlen (tmp) + 5 + strlen (name) + 1);
    225   if (!result)
    226     {
    227       free (tmp);
    228       return NULL;
    229     }
    230 
    231   strcpy (stpcpy (stpcpy (result, tmp), "\\bin\\"), name);
    232   free (tmp);
    233 
    234   return result;
    235 }
    236 
    237 
    238 static char *
    239 find_inst_subdir (const char *name)
    240 {
    241   char *result = NULL;
    242   char *tmp;
    243 
    244   tmp = find_inst_dir ();
    245   if (!tmp)
    246     return NULL;
    247 
    248   result = malloc (strlen (tmp) + 1 + strlen (name) + 1);
    249   if (!result)
    250     {
    251       free (tmp);
    252       return NULL;
    253     }
    254 
    255   strcpy (stpcpy (stpcpy (result, tmp), "\\"), name);
    256   free (tmp);
    257 
    258   return result;
    259 }
    260 
    261 
    262 static char *
    263 find_my_documents_folder ()
    264 {
    265   /* One for safety, just in case.  */
    266   char dir[MAX_PATH + 1];
    267   char *result;
    268 
    269   dir[0] = '\0';
    270   /* May return false even if successful.  */
    271   SHGetSpecialFolderPathA (0, dir, CSIDL_PERSONAL, 0);
    272   if (dir[0] == '\0')
    273     return NULL;
    274 
    275   result = malloc (strlen (dir) + 1);
    276   if (!result)
    277     return NULL;
    278   strcpy (result, dir);
    279   return result;
    280 }
    281 
    282 
    283 #define MAX_ENV 30
    284 
    285 char *environ[MAX_ENV + 1];
    286 
    287 char *
    288 getenv (const char *name)
    289 {
    290   static char *past_result;
    291   char **envp;
    292   int idx;
    293 
    294   if (past_result)
    295     {
    296       free (past_result);
    297       past_result = NULL;
    298     }
    299 
    300   if (! strcmp (name, "DBUS_VERBOSE"))
    301     return past_result = get_verbose_setting ();
    302   else if (! strcmp (name, "HOMEPATH"))
    303     return past_result = find_my_documents_folder ();
    304   else if (! strcmp (name, "DBUS_DATADIR"))
    305     return past_result = find_inst_subdir ("share");
    306 
    307   for (envp = environ; *envp != 0; envp++)
    308     {
    309       const char *varp = name;
    310       char *ep = *envp;
    311       int same_name = 0;
    312 
    313       while (*varp == *ep && *varp != '\0')
    314 	{
    315 	  ++ep;
    316 	  ++varp;
    317 	};
    318 
    319       if (*varp == '\0' && *ep == '=')
    320 	return ep + 1;
    321     }
    322 
    323   return NULL;
    324 }
    325 
    326 
    327 int
    328 putenv (char *str)
    329 {
    330   char **envp;
    331   int idx;
    332   for (envp = environ; *envp != 0; envp++)
    333     {
    334       char *varp = str;
    335       char *ep = *envp;
    336       int same_name = 0;
    337 
    338       while (*varp == *ep && *varp != '\0')
    339 	{
    340 	  if (*varp == '=')
    341 	    same_name = 1;
    342 	  ++ep;
    343 	  ++varp;
    344 	};
    345 
    346       if (*varp == *ep && *varp == '\0')
    347 	return 0;
    348       if (same_name)
    349 	{
    350 	  *envp = str;
    351 	  return 0;
    352 	}
    353     }
    354 
    355   idx = envp - environ;
    356   if (idx > MAX_ENV)
    357     {
    358       _dbus_win_set_errno (ENOMEM);
    359       return -1;
    360     }
    361 
    362   environ[idx] = str;
    363   return 0;
    364 }
    365 
    366 
    367 clock_t
    368 clock (void)
    369 {
    370   return GetTickCount ();
    371 }
    372 
    373 
    374 void
    375 abort (void)
    376 {
    377   /* This is what windows does.  */
    378   exit (3);
    379 }
    380 
    381 
    382 void
    383 GetSystemTimeAsFileTime (LPFILETIME ftp)
    384 {
    385   SYSTEMTIME st;
    386   GetSystemTime (&st);
    387   SystemTimeToFileTime (&st, ftp);
    388 }
    389 
    390 
    391 unsigned char*
    392 _mbsrchr (const unsigned char* str, unsigned int ch)
    393 {
    394   /* FIXME.  This is not multi-byte safe.  */
    395   return strrchr (str, ch);
    396 }
    397 
    398 
    399 HANDLE OpenFileMappingA(DWORD dwDesiredAccess,
    400 			BOOL bInheritHandle,
    401 			LPCSTR lpName)
    402 {
    403   DWORD flProtect = 0;
    404   HANDLE hMapping;
    405 
    406   if (dwDesiredAccess & FILE_MAP_READ)
    407     flProtect |= PAGE_READONLY;
    408 
    409   if (dwDesiredAccess & FILE_MAP_WRITE)
    410     flProtect |= PAGE_READWRITE;
    411 
    412   SetLastError (0);
    413   hMapping = CreateFileMappingA(INVALID_HANDLE_VALUE,
    414 				NULL, flProtect, 0, 0, lpName);
    415   if (hMapping != INVALID_HANDLE_VALUE)
    416     {
    417       /* Just in case Windows CE changes its behaviour, we check for
    418          the right error value here.  */
    419       if (GetLastError () != ERROR_ALREADY_EXISTS)
    420         {
    421           CloseHandle(hMapping);
    422           hMapping = INVALID_HANDLE_VALUE;
    423         }
    424     }
    425   return hMapping;
    426 }
    427 
    428 
    429 BOOL
    430 MoveFileExA (LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags)
    431 {
    432   _dbus_assert (dwFlags == MOVEFILE_REPLACE_EXISTING);
    433 
    434   if (_dbus_file_exists (lpNewFileName))
    435     {
    436       BOOL result = DeleteFileA (lpNewFileName);
    437       if (result == 0)
    438 	return FALSE;
    439     }
    440   return MoveFileA (lpExistingFileName, lpNewFileName);
    441 }
    442 
    443 
    444 BOOL
    445 SetHandleInformation (HANDLE hObject, DWORD dwMask, DWORD dwFlags)
    446 {
    447   _dbus_assert (dwMask == (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE));
    448   _dbus_assert (dwFlags == 0);
    449 
    450   /* Not supported on Windows CE, and actually the default.  So just
    451      return overwhelming success.  */
    452   return 1;
    453 }
    454 
    455 
    456 DWORD
    457 SearchPathA (LPCSTR lpPath, LPCSTR lpFileName, LPCSTR lpExtension,
    458              DWORD nBufferLength, LPSTR lpBuffer, LPSTR* lpFilePart)
    459 {
    460   char *filename;
    461   char *filepart;
    462   int filename_len;
    463 
    464   _dbus_assert (lpPath == NULL);
    465   _dbus_assert (lpExtension == NULL);
    466 
    467   filename = find_program_in_inst_dir (lpFileName);
    468   if (!filename)
    469     {
    470       SetLastError (ERROR_FILE_NOT_FOUND);
    471       return 0;
    472     }
    473 
    474   filename_len = strlen (filename) + 1;
    475   if (filename_len > nBufferLength)
    476     {
    477       free (filename);
    478       return filename_len;
    479     }
    480 
    481   strcpy (lpBuffer, filename);
    482   free (filename);
    483 
    484   filepart = _mbsrchr (lpBuffer, '\\');
    485   if (!filepart)
    486     filepart = lpBuffer;
    487   *lpFilePart = filepart;
    488 
    489   return filename_len - 1;
    490 }
    491 
    492 
    493 /** Gets our SID
    494  * @param points to sid buffer, need to be freed with LocalFree()
    495  * @returns process sid
    496  */
    497 dbus_bool_t
    498 _dbus_getsid(char **sid)
    499 {
    500   /* There is nothing like this on Windows CE, so we fake it.  */
    501   static const char asid[] = "S-1-5-21-515967899-920026266-1708537768-1000";
    502   char *buf = LocalAlloc (LMEM_FIXED, sizeof (asid));
    503   if (!buf)
    504     {
    505       _dbus_win_warn_win_error ("LocalAlloc failed", GetLastError ());
    506       return FALSE;
    507     }
    508 
    509   memcpy (buf, asid, sizeof (asid));
    510   *sid = buf;
    511   return TRUE;
    512 }
    513 
    514 
    515 BOOL
    516 LookupAccountNameW (LPCWSTR lpSystemName, LPCWSTR lpAccountName, PSID Sid, PDWORD cbSid,
    517                     LPWSTR ReferencedDomainName, PDWORD cchReferencedDomainName, PSID_NAME_USE peUse)
    518 {
    519   /* Currently not needed.  */
    520   return FALSE;
    521 }
    522 
    523 
    524 BOOL
    525 IsValidSid (PSID psid)
    526 {
    527   /* Currently not needed.  */
    528   return FALSE;
    529 }
    530 
    531 
    532 HANDLE
    533 CreateFileA (LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwSharedMode,
    534 	     LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    535 	     DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
    536 	     HANDLE hTemplateFile)
    537 {
    538   wchar_t *filename;
    539   HANDLE result;
    540   int err;
    541 
    542   filename = _dbus_win_utf8_to_utf16 (lpFileName, NULL);
    543   if (!filename)
    544     return INVALID_HANDLE_VALUE;
    545 
    546   result = CreateFileW (filename, dwDesiredAccess, dwSharedMode,
    547 			lpSecurityAttributes, dwCreationDisposition,
    548 			dwFlagsAndAttributes, hTemplateFile);
    549 
    550   err = GetLastError ();
    551   dbus_free (filename);
    552   SetLastError (err);
    553   return result;
    554 }
    555 
    556 
    557 BOOL
    558 DeleteFileA (LPCSTR lpFileName)
    559 {
    560   wchar_t *filename;
    561   BOOL result;
    562   int err;
    563 
    564   filename = _dbus_win_utf8_to_utf16 (lpFileName, NULL);
    565   if (!filename)
    566     return FALSE;
    567 
    568   result = DeleteFileW (filename);
    569 
    570   err = GetLastError ();
    571   dbus_free (filename);
    572   SetLastError (err);
    573   return result;
    574 }
    575 
    576 
    577 BOOL
    578 MoveFileA (LPCSTR lpExistingFileName, LPCSTR lpNewFileName)
    579 {
    580   wchar_t *existing_filename;
    581   wchar_t *new_filename;
    582   BOOL result;
    583   int err;
    584 
    585   existing_filename = _dbus_win_utf8_to_utf16 (lpExistingFileName, NULL);
    586   if (! existing_filename)
    587     return FALSE;
    588 
    589   new_filename = _dbus_win_utf8_to_utf16 (lpNewFileName, NULL);
    590   if (! new_filename)
    591     {
    592       dbus_free (existing_filename);
    593       return FALSE;
    594     }
    595 
    596   result = MoveFileW (existing_filename, new_filename);
    597 
    598   err = GetLastError ();
    599   dbus_free (existing_filename);
    600   dbus_free (new_filename);
    601   SetLastError (err);
    602   return result;
    603 }
    604 
    605 
    606 DWORD
    607 GetFileAttributesA(LPCSTR lpFileName)
    608 {
    609   wchar_t *filename;
    610   DWORD result;
    611   int err;
    612 
    613   filename = _dbus_win_utf8_to_utf16 (lpFileName, NULL);
    614   if (!filename)
    615     return INVALID_FILE_ATTRIBUTES;
    616 
    617   result = GetFileAttributesW (filename);
    618 
    619   err = GetLastError ();
    620   dbus_free (filename);
    621   SetLastError (err);
    622   return result;
    623 }
    624 
    625 
    626 BOOL
    627 GetFileAttributesExA (LPCSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
    628                       PVOID lpFileInformation)
    629 {
    630   wchar_t *filename;
    631   DWORD result;
    632   int err;
    633 
    634   filename = _dbus_win_utf8_to_utf16 (lpFileName, NULL);
    635   if (!filename)
    636     return INVALID_FILE_ATTRIBUTES;
    637 
    638   result = GetFileAttributesExW (filename, fInfoLevelId, lpFileInformation);
    639 
    640   err = GetLastError ();
    641   dbus_free (filename);
    642   SetLastError (err);
    643   return result;
    644 }
    645 
    646 
    647 HANDLE
    648 CreateFileMappingA (HANDLE hFile, LPSECURITY_ATTRIBUTES lpAttributes,
    649 		    DWORD flProtect, DWORD dwMaximumSizeHigh,
    650 		    DWORD dwMaximumSizeLow, LPCSTR lpName)
    651 {
    652   wchar_t *name;
    653   HANDLE result;
    654   int err;
    655 
    656   if (lpName)
    657     {
    658       name = _dbus_win_utf8_to_utf16 (lpName, NULL);
    659       if (!name)
    660 	return INVALID_HANDLE_VALUE;
    661     }
    662   else
    663     name = NULL;
    664 
    665   result = CreateFileMappingW (hFile, lpAttributes, flProtect,
    666 			       dwMaximumSizeHigh, dwMaximumSizeLow,
    667 			       name);
    668 
    669   err = GetLastError ();
    670   dbus_free (name);
    671   SetLastError (err);
    672   return result;
    673 }
    674 
    675 
    676 BOOL
    677 CreateDirectoryA (LPCSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
    678 {
    679   wchar_t *pathname;
    680   BOOL result;
    681   int err;
    682 
    683   pathname = _dbus_win_utf8_to_utf16 (lpPathName, NULL);
    684   if (!pathname)
    685     return FALSE;
    686 
    687   result = CreateDirectoryW (pathname, lpSecurityAttributes);
    688 
    689   err = GetLastError ();
    690   dbus_free (pathname);
    691   SetLastError (err);
    692   return result;
    693 }
    694 
    695 
    696 BOOL
    697 RemoveDirectoryA (LPCSTR lpPathName)
    698 {
    699   wchar_t *pathname;
    700   BOOL result;
    701   int err;
    702 
    703   pathname = _dbus_win_utf8_to_utf16 (lpPathName, NULL);
    704   if (!pathname)
    705     return FALSE;
    706 
    707   result = RemoveDirectoryW (pathname);
    708 
    709   err = GetLastError ();
    710   dbus_free (pathname);
    711   SetLastError (err);
    712   return result;
    713 }
    714 
    715 
    716 static BOOL
    717 convert_find_data (LPWIN32_FIND_DATAW fdw, LPWIN32_FIND_DATAA fda)
    718 {
    719   char *filename;
    720   int len;
    721 
    722   fda->dwFileAttributes = fdw->dwFileAttributes;
    723   fda->ftCreationTime = fdw->ftCreationTime;
    724   fda->ftLastAccessTime = fdw->ftLastAccessTime;
    725   fda->ftLastWriteTime = fdw->ftLastWriteTime;
    726   fda->nFileSizeHigh = fdw->nFileSizeHigh;
    727   fda->nFileSizeLow = fdw->nFileSizeLow;
    728 
    729   filename = _dbus_win_utf16_to_utf8 (fdw->cFileName, NULL);
    730   if (!filename)
    731     return FALSE;
    732 
    733   len = sizeof (fda->cFileName);
    734   strncpy (fda->cFileName, filename, len);
    735   fda->cFileName[len - 1] = '\0';
    736 
    737   return TRUE;
    738 }
    739 
    740 
    741 HANDLE
    742 FindFirstFileA (LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData)
    743 {
    744   wchar_t *pathname;
    745   WIN32_FIND_DATAW find_file_data;
    746   HANDLE result;
    747   int err;
    748 
    749   pathname = _dbus_win_utf8_to_utf16 (lpFileName, NULL);
    750   if (!pathname)
    751     return INVALID_HANDLE_VALUE;
    752 
    753   result = FindFirstFileW (pathname, &find_file_data);
    754   if (result != INVALID_HANDLE_VALUE)
    755     {
    756       BOOL res = convert_find_data (&find_file_data, lpFindFileData);
    757       if (! res)
    758         {
    759           err = GetLastError ();
    760           FindClose (result);
    761           SetLastError (err);
    762           result = INVALID_HANDLE_VALUE;
    763         }
    764     }
    765 
    766   err = GetLastError ();
    767   dbus_free (pathname);
    768   SetLastError (err);
    769   return result;
    770 }
    771 
    772 
    773 BOOL
    774 FindNextFileA (HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData)
    775 {
    776   WIN32_FIND_DATAW find_file_data;
    777   BOOL result;
    778   int err;
    779 
    780   result = FindNextFileW (hFindFile, &find_file_data);
    781   if (result)
    782     result = convert_find_data (&find_file_data, lpFindFileData);
    783 
    784   return result;
    785 }
    786 
    787 
    788 HANDLE
    789 CreateMutexA (LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner,
    790 	      LPCSTR lpName)
    791 {
    792   wchar_t *name;
    793   HANDLE result;
    794   int err;
    795 
    796   if (lpName)
    797     {
    798       name = _dbus_win_utf8_to_utf16 (lpName, NULL);
    799       if (!name)
    800 	return INVALID_HANDLE_VALUE;
    801     }
    802   else
    803     name = NULL;
    804 
    805   result = CreateMutexW (lpMutexAttributes, bInitialOwner, name);
    806 
    807   err = GetLastError ();
    808   dbus_free (name);
    809   SetLastError (err);
    810   return result;
    811 }
    812 
    813 
    814 BOOL
    815 CreateProcessA (LPCSTR pszImageName, LPSTR pszCmdLine,
    816                 LPSECURITY_ATTRIBUTES psaProcess,
    817                 LPSECURITY_ATTRIBUTES psaThread, BOOL fInheritHandles,
    818                 DWORD fdwCreate, PVOID pvEnvironment, LPCSTR pszCurDir,
    819                 LPSTARTUPINFOA psiStartInfo,
    820                 LPPROCESS_INFORMATION pProcInfo)
    821 {
    822   wchar_t *image_name = NULL;
    823   wchar_t *cmd_line = NULL;
    824   BOOL result;
    825   int err;
    826 
    827   _dbus_assert (psaProcess == NULL);
    828   _dbus_assert (psaThread == NULL);
    829   _dbus_assert (fInheritHandles == FALSE);
    830   _dbus_assert (pvEnvironment == NULL);
    831   _dbus_assert (pszCurDir == NULL);
    832   /* psiStartInfo is generally not NULL.  */
    833 
    834   if (pszImageName)
    835     {
    836       image_name = _dbus_win_utf8_to_utf16 (pszImageName, NULL);
    837       if (!image_name)
    838 	return 0;
    839     }
    840   if (pszCmdLine)
    841     {
    842       cmd_line = _dbus_win_utf8_to_utf16 (pszCmdLine, NULL);
    843       if (!cmd_line)
    844         {
    845           if (image_name)
    846             dbus_free (image_name);
    847           return 0;
    848         }
    849     }
    850 
    851   result = CreateProcessW (image_name, cmd_line, NULL, NULL, FALSE,
    852                            fdwCreate, NULL, NULL, NULL, pProcInfo);
    853 
    854   err = GetLastError ();
    855   dbus_free (image_name);
    856   dbus_free (cmd_line);
    857   SetLastError (err);
    858   return result;
    859 }
    860 
    861 
    862 LONG
    863 RegOpenKeyExA (HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions,
    864                REGSAM samDesired, PHKEY phkResult)
    865 {
    866   wchar_t *subkey;
    867   LONG result;
    868   int err;
    869 
    870   if (lpSubKey)
    871     {
    872       subkey = _dbus_win_utf8_to_utf16 (lpSubKey, NULL);
    873       if (!subkey)
    874 	return 0;
    875     }
    876   else
    877     subkey = NULL;
    878 
    879   result = RegOpenKeyEx (hKey, subkey, ulOptions, samDesired, phkResult);
    880 
    881   err = GetLastError ();
    882   dbus_free (subkey);
    883   SetLastError (err);
    884   return result;
    885 }
    886 
    887 
    888 LONG
    889 RegQueryValueExA (HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved,
    890                   LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
    891 {
    892   wchar_t *name;
    893   LONG err;
    894   BYTE *data;
    895   DWORD data_len;
    896   DWORD type;
    897 
    898   if (lpValueName)
    899     {
    900       name = _dbus_win_utf8_to_utf16 (lpValueName, NULL);
    901       if (!name)
    902 	return GetLastError ();
    903     }
    904   else
    905     name = NULL;
    906 
    907   data_len = 0;
    908   err = RegQueryValueExW (hKey, name, lpReserved, lpType, NULL, &data_len);
    909   if (err || !lpcbData)
    910     {
    911       dbus_free (name);
    912       return err;
    913     }
    914 
    915   data = malloc (data_len + sizeof (wchar_t));
    916   if (!data)
    917     {
    918       dbus_free (name);
    919       return ERROR_NOT_ENOUGH_MEMORY;
    920     }
    921 
    922   err = RegQueryValueExW (hKey, name, lpReserved, &type, data, &data_len);
    923   if (lpType)
    924     *lpType = type;
    925   dbus_free (name);
    926   /* If err is ERROR_MORE_DATA, there probably was a race condition.
    927      We can punt this to the caller just as well.  */
    928   if (err)
    929     {
    930       free (data);
    931       return err;
    932     }
    933 
    934   /* NOTE: REG_MULTI_SZ and REG_EXPAND_SZ not supported, because they
    935      are not needed in this module.  */
    936   if (type == REG_SZ)
    937     {
    938       char *data_c;
    939       int data_c_len;
    940 
    941       /* This is valid since we allocated one more above.  */
    942       data[data_len] = '\0';
    943       data[data_len + 1] = '\0';
    944 
    945       /* The cast is valid because malloc guarantees alignment of
    946          basic types.  */
    947       data_c = _dbus_win_utf16_to_utf8 ((wchar_t*) data, NULL);
    948       if (!data_c)
    949         {
    950           free (data);
    951           return GetLastError();
    952         }
    953 
    954       data_c_len = strlen (data_c) + 1;
    955       _dbus_assert (data_c_len <= data_len + sizeof (wchar_t));
    956       memcpy (data, data_c, data_c_len);
    957       data_len = data_c_len;
    958       dbus_free (data_c);
    959     }
    960 
    961   /* DATA and DATA_LEN now contain the result.  */
    962   if (lpData)
    963     {
    964       if (data_len > *lpcbData)
    965         err = ERROR_MORE_DATA;
    966       else
    967         memcpy (lpData, data, data_len);
    968     }
    969   free (data);
    970   *lpcbData = data_len;
    971   return err;
    972 }
    973 
    974 
    975 DWORD
    976 FormatMessageA (DWORD dwFlags, PCVOID lpSource, DWORD dwMessageId,
    977 		DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize,
    978 		va_list* Arguments)
    979 {
    980   LPWSTR buffer_w = NULL;
    981   LPSTR buffer_c;
    982   DWORD len;
    983   char *buffer_new;
    984   DWORD buffer_new_len;
    985   BOOL buffer_w_free;
    986 
    987   len = FormatMessageW (dwFlags | FORMAT_MESSAGE_ALLOCATE_BUFFER,
    988 			lpSource, dwMessageId, dwLanguageId,
    989 			(LPWSTR) &buffer_w, 0, Arguments);
    990   if (len == 0)
    991     return 0;
    992 
    993   buffer_c = _dbus_win_utf16_to_utf8 (buffer_w, NULL);
    994   if (! buffer_c)
    995     {
    996       LocalFree (buffer_w);
    997       return 0;
    998     }
    999 
   1000   if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER)
   1001     {
   1002       /* We need to return a buffer that's freeable with LocalFree.  */
   1003       buffer_new = (char *) buffer_w;
   1004       buffer_new_len = sizeof (wchar_t) * (len + 1);
   1005       buffer_w_free = FALSE;
   1006       /* Avoid alignment issue by using memcpy.  */
   1007       memcpy (lpBuffer, &buffer_new, sizeof (buffer_new));
   1008     }
   1009   else
   1010     {
   1011       buffer_new = lpBuffer;
   1012       buffer_new_len = nSize;
   1013       buffer_w_free = TRUE;
   1014     }
   1015 
   1016   strncpy (buffer_new, buffer_c, buffer_new_len);
   1017   dbus_free (buffer_c);
   1018   buffer_new[buffer_new_len - 1] = '\0';
   1019   if (buffer_w_free)
   1020     LocalFree (buffer_w);
   1021 
   1022   /* strlen is correct (not _mbstrlen), because we want storage and
   1023      not string length.  */
   1024   return strlen (buffer_new);
   1025 }
   1026 
   1027 
   1028 DWORD
   1029 GetModuleFileNameA (HINSTANCE hModule, LPSTR lpFilename, DWORD nSize)
   1030 {
   1031   wchar_t *filename_w;
   1032   char *filename_c;
   1033   DWORD len;
   1034 
   1035   if (nSize == 0)
   1036     {
   1037       /* Windows XP/2000.  */
   1038       SetLastError (0);
   1039       return 0;
   1040     }
   1041 
   1042   filename_w = malloc (sizeof (wchar_t) * nSize);
   1043   if (! filename_w)
   1044     return 0;
   1045 
   1046   len = GetModuleFileNameW (hModule, filename_w, nSize);
   1047   if (len == 0)
   1048     {
   1049       /* Note: If we fail with ERROR_INSUFFICIENT_BUFFER, this is still
   1050        (approximately) correct.  */
   1051       free (filename_w);
   1052       return 0;
   1053     }
   1054 
   1055   filename_w[nSize - 1] = '\0';
   1056   filename_c = _dbus_win_utf16_to_utf8 (filename_w, NULL);
   1057   free (filename_w);
   1058   if (! filename_c)
   1059     return 0;
   1060 
   1061   strncpy (lpFilename, filename_c, nSize);
   1062   dbus_free (filename_c);
   1063   lpFilename[nSize - 1] = '\0';
   1064   /* strlen is correct (not _mbstrlen), because we want storage and
   1065      not string length.  */
   1066   return strlen (lpFilename);
   1067 }
   1068 
   1069 
   1070 DWORD
   1071 GetTempPathA (DWORD nBufferLength, LPSTR lpBuffer)
   1072 {
   1073   wchar_t dummy[1];
   1074   DWORD len;
   1075 
   1076   len = GetTempPathW (0, dummy);
   1077   if (len == 0)
   1078     return 0;
   1079 
   1080   _dbus_assert (len <= MAX_PATH);
   1081 
   1082   /* Better be safe than sorry.  MSDN doesn't say if len is with or
   1083      without terminating 0.  */
   1084   len++;
   1085 
   1086   {
   1087     wchar_t *buffer_w;
   1088     DWORD len_w;
   1089     char *buffer_c;
   1090     DWORD len_c;
   1091 
   1092     buffer_w = malloc (sizeof (wchar_t) * len);
   1093     if (! buffer_w)
   1094       return 0;
   1095 
   1096     len_w = GetTempPathW (len, buffer_w);
   1097     /* Give up if we still can't get at it.  */
   1098     if (len_w == 0 || len_w >= len)
   1099       {
   1100         free (buffer_w);
   1101         return 0;
   1102       }
   1103 
   1104     /* Better be really safe.  */
   1105     buffer_w[len_w] = '\0';
   1106 
   1107     buffer_c = _dbus_win_utf16_to_utf8 (buffer_w, NULL);
   1108     free (buffer_w);
   1109     if (! buffer_c)
   1110       return 0;
   1111 
   1112     /* strlen is correct (not _mbstrlen), because we want storage and
   1113        not string length.  */
   1114     len_c = strlen (buffer_c) + 1;
   1115     if (len_c > nBufferLength)
   1116       return len_c;
   1117 
   1118     strcpy (lpBuffer, buffer_c);
   1119     dbus_free (buffer_c);
   1120     return len_c - 1;
   1121   }
   1122 }
   1123 
   1124 
   1125 BOOL
   1126 SHGetSpecialFolderPathA (HWND hwndOwner, LPSTR lpszPath, int nFolder,
   1127                          BOOL fCreate)
   1128 {
   1129   wchar_t path[MAX_PATH];
   1130   char *path_c;
   1131   BOOL result;
   1132 
   1133   path[0] = (wchar_t) 0;
   1134   result = SHGetSpecialFolderPathW (hwndOwner, path, nFolder, fCreate);
   1135   /* Note: May return false even if succeeds.  */
   1136 
   1137   path[MAX_PATH - 1] = (wchar_t) 0;
   1138   path_c = _dbus_win_utf16_to_utf8 (path, NULL);
   1139   if (! path_c)
   1140     return 0;
   1141 
   1142   strncpy (lpszPath, path_c, MAX_PATH);
   1143   dbus_free (path_c);
   1144   lpszPath[MAX_PATH - 1] = '\0';
   1145   return result;
   1146 }
   1147 
   1148 
   1149 void
   1150 OutputDebugStringA (LPCSTR lpOutputString)
   1151 {
   1152   wchar_t *str;
   1153   HANDLE result;
   1154   int err;
   1155 
   1156   str = _dbus_win_utf8_to_utf16 (lpOutputString, NULL);
   1157   if (!str)
   1158     return;
   1159 
   1160   OutputDebugStringW (str);
   1161 
   1162   err = GetLastError ();
   1163   dbus_free (str);
   1164   SetLastError (err);
   1165 }
   1166