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