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@freenet.de>
8 * Copyright (C) 2006 Peter K��mmel  <syntheticpp@gmx.net>
9 * Copyright (C) 2006 Christian Ehrlicher <ch.ehrlicher@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.  */
43static char *
44stpcpy (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!  */
60static char *
61get_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. */
137static char *
138read_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
196static char *
197find_inst_dir ()
198{
199  return read_w32_registry_string ("HKEY_LOCAL_MACHINE",
200				  "Software\\freedesktop\\DBus",
201				  "Install Directory");
202}
203
204
205static char *
206find_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
214static char *
215find_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
238static char *
239find_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
262static char *
263find_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
285char *environ[MAX_ENV + 1];
286
287char *
288getenv (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
327int
328putenv (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
367clock_t
368clock (void)
369{
370  return GetTickCount ();
371}
372
373
374void
375abort (void)
376{
377  /* This is what windows does.  */
378  exit (3);
379}
380
381
382void
383GetSystemTimeAsFileTime (LPFILETIME ftp)
384{
385  SYSTEMTIME st;
386  GetSystemTime (&st);
387  SystemTimeToFileTime (&st, ftp);
388}
389
390
391unsigned 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
399HANDLE 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
429BOOL
430MoveFileExA (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
444BOOL
445SetHandleInformation (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
456DWORD
457SearchPathA (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 */
497dbus_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
515BOOL
516LookupAccountNameW (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
524BOOL
525IsValidSid (PSID psid)
526{
527  /* Currently not needed.  */
528  return FALSE;
529}
530
531
532HANDLE
533CreateFileA (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
557BOOL
558DeleteFileA (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
577BOOL
578MoveFileA (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
606DWORD
607GetFileAttributesA(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
626BOOL
627GetFileAttributesExA (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
647HANDLE
648CreateFileMappingA (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
676BOOL
677CreateDirectoryA (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
696BOOL
697RemoveDirectoryA (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
716static BOOL
717convert_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
741HANDLE
742FindFirstFileA (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
773BOOL
774FindNextFileA (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
788HANDLE
789CreateMutexA (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
814BOOL
815CreateProcessA (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
862LONG
863RegOpenKeyExA (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
888LONG
889RegQueryValueExA (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
975DWORD
976FormatMessageA (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
1028DWORD
1029GetModuleFileNameA (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
1070DWORD
1071GetTempPathA (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
1125BOOL
1126SHGetSpecialFolderPathA (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
1149void
1150OutputDebugStringA (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