Merge branch 'master' into windows
[ardour.git] / libs / pbd / msvc / msvc_pbd.cc
1 /*
2     Copyright (C) 2009 John Emmas
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifdef COMPILER_MSVC
21
22 #include <WTypes.h>
23
24 extern "C" WINBASEAPI BOOL WINAPI
25 CreateHardLinkA( LPCSTR lpFileName,
26                                  LPCSTR lpExistingFileName,
27                                  LPSECURITY_ATTRIBUTES lpSecurityAttributes ); // Needs kernel32.lib on anything higher than Win2K
28
29 #include <algorithm>
30 #include <string>
31 #include <io.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <sys/stat.h>
36 #include <pbd/error.h>
37 #include <ardourext/misc.h>
38 #include <ardourext/pthread.h> // Should ensure that we include the right
39                                // version - but we'll check anyway, later
40
41 #include <glibmm.h>
42
43 #define DELTA_EPOCH_IN_MICROSECS  11644473600000000Ui64
44
45 struct timezone
46 {
47         int  tz_minuteswest; /* minutes W of Greenwich */
48         int  tz_dsttime;     /* type of dst correction */
49 };
50
51 PBD_API int PBD_APICALLTYPE
52 gettimeofday(struct timeval *__restrict tv, __timezone_ptr_t tz) // Does this need to be exported ?
53 {
54 FILETIME ft;
55 unsigned __int64 tmpres = 0;
56 static int tzflag = 0;
57
58         if (NULL != tv)
59         {
60                 GetSystemTimeAsFileTime(&ft);
61
62                 tmpres |= ft.dwHighDateTime;
63                 tmpres <<= 32;
64                 tmpres |= ft.dwLowDateTime;
65
66                 /*converting file time to unix epoch*/
67                 tmpres /= 10;  /*convert into microseconds*/
68                 tmpres -= DELTA_EPOCH_IN_MICROSECS;
69                 tv->tv_sec = (long)(tmpres / 1000000UL);
70                 tv->tv_usec = (long)(tmpres % 1000000UL);
71         }
72
73         if (NULL != tz)
74         {
75                 struct timezone *ptz = static_cast<struct timezone*> (tz);
76                 if (!tzflag)
77                 {
78                         _tzset();
79                         tzflag++;
80                 }
81                 if (ptz)
82                 {
83                         ptz->tz_minuteswest = _timezone / 60;
84                         ptz->tz_dsttime = _daylight;
85                 }
86         }
87
88         return 0;
89 }
90
91 // Define the default comparison operators for Windows (ptw32) 'pthread_t' (not used
92 // by Ardour AFAIK but would be needed if an array of 'pthread_t' had to be sorted).
93 #ifndef PTHREAD_H   // Defined by PTW32 (Linux and other versions define _PTHREAD_H)
94 #error "An incompatible version of 'pthread.h' is #included. Use only the Windows (ptw32) version!"
95 #else
96 bool operator>  (const pthread_t& lhs, const pthread_t& rhs)
97 {
98         return (std::greater<void*>()(lhs.p, rhs.p));
99 }
100
101 bool operator<  (const pthread_t& lhs, const pthread_t& rhs)
102 {
103         return (std::less<void*>()(lhs.p, rhs.p));
104 }
105
106 bool operator!= (const pthread_t& lhs, const pthread_t& rhs)
107 {
108         return (std::not_equal_to<void*>()(lhs.p, rhs.p));
109 }
110
111 bool operator== (const pthread_t& lhs, const pthread_t& rhs)
112 {
113         return (!(lhs != rhs));
114 }
115 #endif
116
117 // Functions supplied (later) to std::transform
118 //***************************************************************
119 //
120 //      invert_backslash()
121 //
122 // Examines a supplied ASCII character and (if the character is
123 // a backslash) converts it to a forward slash,
124 //
125 //      Returns:
126 //
127 //    The supplied character (converted, if it was a backslash)
128 //
129 char invert_backslash(char character)
130 {
131         if ('\\' == character)
132                 character = '/';
133
134         return (character);
135 }
136
137 //***************************************************************
138 //
139 //      invert_forwardslash()
140 //
141 // Examines a supplied ASCII character and (if the character is
142 // a forward slash) converts it to a backslash,
143 //
144 //      Returns:
145 //
146 //    The supplied character (converted, if it was a fwd slash)
147 //
148 char invert_forwardslash(char character)
149 {
150         if ('/' == character)
151                 character = '\\';
152
153         return (character);
154 }
155
156
157 //***************************************************************
158 //
159 //      pread()
160 //
161 // Emulates pread() using _lseek()/_read()/_lseek().
162 //
163 //      Returns:
164 //
165 //    On Success: The number of bytes read from the file
166 //    On Failure: -1
167 //
168 PBD_API ssize_t PBD_APICALLTYPE
169 pread(int handle, void *buf, size_t nbytes, off_t offset)
170 {
171 int old_errno;
172 ssize_t ret;
173
174         off_t old_offset = _tell(handle);
175
176         if (0 > old_offset)
177                 ret = (-1);
178         else
179         {
180                 _lseek(handle, offset, SEEK_SET);
181                 ret = _read(handle, buf, nbytes);
182
183                 old_errno = errno;
184                 _lseek(handle, old_offset, SEEK_SET);
185                 errno = old_errno;
186         }
187
188         return (ret);
189 }
190
191
192 //***************************************************************
193 //
194 //      pwrite()
195 //
196 // Emulates pwrite() using _lseek()/_write()/_lseek().
197 //
198 //      Returns:
199 //
200 //    On Success: The number of bytes written to the file
201 //    On Failure: -1
202 //
203 PBD_API ssize_t PBD_APICALLTYPE
204 pwrite(int handle, const void *buf, size_t nbytes, off_t offset)
205 {
206 int old_errno;
207 ssize_t ret;
208
209         off_t old_offset = _lseek(handle, offset, SEEK_SET);
210
211         if (0 > old_offset)
212                 ret = (-1);
213         else
214         {
215                 ret = _write(handle, buf, nbytes);
216
217                 old_errno = errno;
218                 _lseek(handle, old_offset, SEEK_SET);
219                 errno = old_errno;
220         }
221
222         return (ret);
223 }
224
225 namespace PBD {
226
227 //***************************************************************
228 //
229 //      TestForMinimumSpecOS()
230 //
231 // Tests the user's OS to see if it is Win2K or later (could be
232 // expanded quite easily to accommodate other OS's)
233 //
234 //      Returns:
235 //
236 //    On Success: TRUE (if the user's OS matches the minimum spec)
237 //    On Failure: FALSE otherwise
238 //
239 PBD_API bool PBD_APICALLTYPE
240 TestForMinimumSpecOS(char *revision /* currently ignored */)
241 {
242 bool bRet = true;
243 #ifdef PLATFORM_WINDOWS
244         bRet = false;
245         HINSTANCE hKernelDll = (HINSTANCE)dlopen("kernel32.dll", RTLD_NOW);
246
247         if (hKernelDll)
248         {
249                 // 'CreateHardLink()' is only available from Win2K onwards.
250                 if (NULL != dlsym(hKernelDll, "CreateHardLinkA"))
251                         bRet = true;
252
253                 dlclose(hKernelDll);
254         }
255 #endif
256         // Other OS's could be accommodated here
257
258         return (bRet);
259 }
260
261
262 //***************************************************************
263 //
264 //      realpath()
265 //
266 // Emulates POSIX realpath() using Win32 _fullpath().
267 //
268 //      Returns:
269 //
270 //    On Success: A pointer to the resolved (absolute) path
271 //    On Failure: NULL
272 //
273 PBD_API char* PBD_APICALLTYPE
274 realpath (const char *original_path, char resolved_path[_MAX_PATH+1])
275 {
276 char *pRet = NULL;
277 bool bIsSymLink = 0; // We'll probably need to test the incoming path
278                      // to find out if it points to a Windows shortcut
279                      // (or a hard link) and set this appropriately.
280         if (bIsSymLink)
281         {
282                 // At the moment I'm not sure if Windows '_fullpath()' is directly
283                 // equivalent to POSIX 'realpath()' - in as much as the latter will
284                 // resolve the supplied path if it happens to point to a symbolic
285                 // link ('_fullpath()' probably DOESN'T do this but I'm not really
286                 // sure if Ardour needs such functionality anyway). Therefore we'll
287                 // possibly need to add that functionality here at a later date.
288         }
289         else
290         {
291                 char temp[(MAX_PATH+1)*6]; // Allow for maximum length of a path in UTF8 characters
292
293                 // POSIX 'realpath()' requires that the buffer size is at
294                 // least PATH_MAX+1, so assume that the user knew this !!
295                 pRet = _fullpath(temp, Glib::locale_from_utf8(original_path).c_str(), _MAX_PATH);
296                 if (NULL != pRet)
297                         strcpy(resolved_path, Glib::locale_to_utf8(temp).c_str());
298         }
299
300         return (pRet);
301 }
302
303
304 //***************************************************************
305 //
306 //      opendir()
307 //
308 // Creates a pointer to a DIR structure, appropriately filled in
309 // and ready to begin a directory search iteration.
310 //
311 //      Returns:
312 //
313 //    On Success: Pointer to a (heap based) DIR structure
314 //    On Failure: NULL
315 //
316 PBD_API DIR* PBD_APICALLTYPE
317 opendir (const char *szPath)
318 {
319 wchar_t wpath[PATH_MAX+1];
320 unsigned int rc;
321 DIR *pDir = 0;
322
323         errno = 0;
324
325         if (!szPath)
326                 errno = EFAULT;
327
328         if ((!errno) && ('\0' == szPath[0]))
329                 errno = ENOTDIR;
330
331         // Determine if the given path really is a directory
332
333         if (!errno)
334                 if (0 == MultiByteToWideChar (CP_UTF8, 0, (LPCSTR)szPath, -1, (LPWSTR)wpath, sizeof(wpath)))
335                         errno = EFAULT;
336
337         if ((!errno) && ((rc = GetFileAttributesW(wpath)) == -1))
338                 errno = ENOENT;
339
340         if ((!errno) && (!(rc & FILE_ATTRIBUTE_DIRECTORY)))
341                 // Error. Entry exists but not a directory. */
342                 errno = ENOTDIR;
343
344         if (!errno)
345         {
346                 // Allocate enough memory to store DIR structure, plus
347                 // the complete directory path originally supplied.
348                 pDir = (DIR *)malloc(sizeof(DIR) + strlen(szPath) + strlen("\\") + strlen ("*"));
349
350                 if (!pDir)
351                 {
352                         // Error - out of memory
353                         errno = ENOMEM;
354                 }
355         }
356
357         if (!errno)
358         {
359                 // Create the search expression
360                 strcpy(pDir->dd_name, szPath);
361
362                 // Add a backslash if the path doesn't already end with one
363                 if (pDir->dd_name[0] != '\0' &&
364                         pDir->dd_name[strlen(pDir->dd_name) - 1] != '/' &&
365                         pDir->dd_name[strlen(pDir->dd_name) - 1] != '\\')
366                 {
367                         strcat (pDir->dd_name, "\\");
368                 }
369
370                 // Add the search pattern
371                 strcat(pDir->dd_name, "*");
372
373                 // Initialize handle to -1 so that a premature closedir()
374                 // doesn't try to call _findclose() on it.
375                 pDir->dd_handle = (-1);
376
377                 // Initialize the status
378                 pDir->dd_stat = 0;
379
380                 // Initialize the dirent structure. 'ino' and 'reclen' are invalid under Win32
381                 // and 'name' simply points at the appropriate part of the findfirst_t struct.
382                 pDir->dd_dir.d_ino = 0;
383                 pDir->dd_dir.d_reclen = 0;
384                 pDir->dd_dir.d_namlen = 0;
385                 strcpy(pDir->dd_dir.d_name, pDir->dd_dta.name);
386
387                 return (pDir);  // Succeeded
388         }
389
390         if (pDir)
391                 free (pDir);
392         return (DIR *) 0; // Failed
393 }
394
395
396 //***************************************************************
397 //
398 //      readdir()
399 //
400 // Return a pointer to a dirent struct, filled with information
401 // about the next entry in the directory.
402 //
403 //      Returns:
404 //
405 //    On Success: A pointer to the supplied DIR's 'dirent' struct
406 //    On Failure: NULL
407 //
408 PBD_API struct dirent* PBD_APICALLTYPE
409 readdir (DIR* pDir)
410 {
411 int old_errno = 0;
412 errno = 0;
413
414         // Check for valid DIR struct
415         if (!pDir)
416                 errno = EFAULT;
417
418         if ((strcmp(pDir->dd_dir.d_name, pDir->dd_dta.name)) && (!errno))
419                 // The structure does not seem to be set up correctly
420                 errno = EINVAL;
421         else
422         {
423                 if (pDir->dd_stat < 0)
424                 {
425                         // We have already returned all files in this directory
426                         // (or the structure has an invalid dd_stat).
427                         return (struct dirent *)0;
428                 }
429                 else if (pDir->dd_stat == 0)
430                 {
431                         // We haven't started the search yet.
432                         // Start the search
433                         pDir->dd_handle = _findfirst (Glib::locale_from_utf8(pDir->dd_name).c_str(), &(pDir->dd_dta));
434
435                         if (pDir->dd_handle == -1)
436                                 // The directory is empty
437                                 pDir->dd_stat = -1;
438                         else
439                                 pDir->dd_stat = 1;
440                 }
441                 else
442                 {
443                         // Do not return ENOENT on last file in directory
444                         old_errno = errno;
445
446                         // Get the next search entry
447                         if (_findnext (pDir->dd_handle, &(pDir->dd_dta)))
448                         {
449                                 // We are off the end or otherwise error
450                                 errno = old_errno;
451                                 _findclose (pDir->dd_handle);
452                                 pDir->dd_handle = -1;
453                                 pDir->dd_stat = -1;
454                         }
455                         else
456                                 // Update to indicate the correct status number
457                                 pDir->dd_stat++;
458                 }
459
460                 if (pDir->dd_stat > 0)
461                 {
462                         // We successfully got an entry. Details about the file are
463                         // already appropriately filled in except for the length of
464                         // file name.
465                         strcpy(pDir->dd_dir.d_name, pDir->dd_dta.name);
466                         pDir->dd_dir.d_namlen = strlen (pDir->dd_dir.d_name);
467                         return (&pDir->dd_dir); // Succeeded
468                 }
469         }
470
471         return (struct dirent *) 0; // Failed
472 }
473
474
475 //***************************************************************
476 //
477 //      closedir()
478 //
479 // Frees the resources allocated by opendir().
480 //
481 //      Returns:
482 //
483 //    On Success: 0
484 //    On Failure: -1
485 //
486 PBD_API int PBD_APICALLTYPE
487 closedir (DIR *pDir)
488 {
489 int rc = 0;
490
491         errno = 0;
492
493         if (!pDir)
494                 errno = EFAULT;
495         else
496         {
497                 if ((-1) != pDir->dd_handle)
498                         rc = _findclose (pDir->dd_handle);
499
500                 // Free the DIR structure
501                 free (pDir);
502
503                 return rc; // Succeeded
504         }
505
506         return (-1); // Failed
507 }
508
509 //***************************************************************
510 //
511 //      mkstemp()
512 //
513 // Emulates Linux mkstemp() using Win32 _mktemp() and _open() etc.
514 //
515 //      Returns:
516 //
517 //    On Success: A file descriptor for the opened file.
518 //    On Failure: (-1)
519 //
520 PBD_API int PBD_APICALLTYPE
521 mkstemp (char *template_name)
522 {
523 int ret = (-1);
524 char *szFileName;
525 char szTempPath[PATH_MAX+100]; // Just ensure we have plenty of buffer space
526
527         if (NULL != (szFileName = _mktemp(template_name)))
528         {
529                 if (0 != ::GetTempPathA(sizeof(szTempPath), szTempPath))
530                 {
531                         strcat(szTempPath, szFileName);
532                         ret = _open(szTempPath, (_O_CREAT|_O_BINARY|_O_TEMPORARY|_O_RDWR|_O_TRUNC), _S_IWRITE);
533                 }
534         }
535
536         return (ret);
537 }
538
539
540 //***************************************************************
541 //
542 //      ntfs_link()
543 //
544 // Emulates Linux link() using Win32 CreateHardLink()(NTFS only).
545 //
546 //      Returns:
547 //
548 //    On Success: Non-zero.
549 //    On Failure: Zero (call 'GetLastError()' to retrieve info)
550 //
551 PBD_API int PBD_APICALLTYPE
552 ntfs_link (const char *existing_filepath, const char *link_filepath)
553 {
554 int ret = 1; // 'ERROR_INVALID_FUNCTION'
555 bool bValidPath = false;
556
557         // Make sure we've been sent a valid input string
558         if (existing_filepath && link_filepath)
559         {
560                 std::string strRoot = existing_filepath;
561
562                 if ((1 < strRoot.length()) && ('\\' == existing_filepath[0]) && ('\\' == existing_filepath[1]))
563                 {
564                         int slashcnt = 0;
565
566                         // We've been sent a network path. Convert backslashes to forward slashes temporarily.
567                         std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_backslash);
568
569                         // Now, if there are less than four slashes, add a fourth one or abort
570                         std::string::iterator iter = strRoot.begin();
571                         while ((slashcnt < 4) && (iter != strRoot.end()))
572                         {
573                                 if ('/' == (*iter))
574                                         slashcnt++;
575
576                                 ++iter;
577                         }
578
579                         if (slashcnt > 2)
580                         {
581                                 // If only 3 slashes were counted, add a trailing slash
582                                 if (slashcnt == 3)
583                                         strRoot += '/';
584
585                                 // Now find the position of the fourth slash
586                                 iter = strRoot.begin();
587                                 int charcnt = 0;
588                                 for (slashcnt=0; slashcnt<4;)
589                                 {
590                                         charcnt++;
591
592                                         if ('/' == (*iter))
593                                                 slashcnt++;
594
595                                         if (++iter == strRoot.end())
596                                                 break;
597                                 }
598
599                                 strRoot.resize(charcnt);
600                                 bValidPath = true;
601                         }
602                 }
603                 else
604                 {
605                         // Assume a standard Windows style path
606                         if (1 < strRoot.length() && (':' == existing_filepath[1]))
607                         {
608                                 // Convert backslashes to forward slashes temporarily.
609                                 std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_backslash);
610
611                                 if (2 == strRoot.length())
612                                         strRoot += '/';
613
614                                 if ('/' == strRoot[2])
615                                 {
616                                         strRoot.resize(3);
617                                         bValidPath = true;
618                                 }
619                         }
620                 }
621
622                 if (bValidPath)
623                 {
624                         char szFileSystemType[_MAX_PATH+1];
625
626                         // Restore the original backslashes
627                         std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_forwardslash);
628
629                         // Windows only supports hard links for the NTFS filing
630                         // system, so let's make sure that's what we're using!!
631                         if (::GetVolumeInformationA(strRoot.c_str(), NULL, 0, NULL, NULL, NULL, szFileSystemType, _MAX_PATH+1))
632                         {
633                                 std::string strRootFileSystemType = szFileSystemType;
634                                 std::transform(strRootFileSystemType.begin(), strRootFileSystemType.end(), strRootFileSystemType.begin(), ::toupper);
635 #if (_WIN32_WINNT >= 0x0500)
636                                 if (0 == strRootFileSystemType.compare("NTFS"))
637                                 {
638                                         if (TestForMinimumSpecOS()) // Hard links were only available from Win2K onwards
639                                                 if (0 == CreateHardLinkA(link_filepath, existing_filepath, NULL))
640                                                 {       // Note that the above API call cannot create a link to a directory, so
641                                                         // should we also be checking that the supplied path was actually a file?
642                                                         ret = GetLastError();
643                                                 }
644                                                 else
645                                                         SetLastError(ret = 0); // 'NO_ERROR'
646                                 }
647                                 else
648                                 {
649                                         ret = 4300; // 'ERROR_INVALID_MEDIA'
650                                 }
651 #endif
652                         }
653                 }
654                 else
655                         ret = 123; // 'ERROR_INVALID_NAME'
656         }
657         else
658                 ret = 161; // 'ERROR_BAD_PATHNAME'
659
660         if (ret)
661         {
662                 SetLastError(ret);
663                 return (-1);
664         }
665         else
666                 return (0);
667 }
668
669
670 //***************************************************************
671 //
672 //      ntfs_unlink()
673 //
674 // Emulates Linux unlink() using Win32 DeleteFile()(NTFS only).
675 //
676 //      Returns:
677 //
678 //    On Success: Non-zero.
679 //    On Failure: Zero (call 'GetLastError()' to retrieve info)
680 //
681 PBD_API int PBD_APICALLTYPE
682 ntfs_unlink (const char *link_filepath)
683 {
684 int ret = 1; // 'ERROR_INVALID_FUNCTION'
685 bool bValidPath = false;
686
687         // Make sure we've been sent a valid input string
688         if (link_filepath)
689         {
690                 std::string strRoot = link_filepath;
691
692                 if ((1 < strRoot.length()) && ('\\' == link_filepath[0]) && ('\\' == link_filepath[1]))
693                 {
694                         int slashcnt = 0;
695
696                         // We've been sent a network path. Convert backslashes to forward slashes temporarily.
697                         std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_backslash);
698
699                         // Now, if there are less than four slashes, add a fourth one or abort
700                         std::string::iterator iter = strRoot.begin();
701                         while ((slashcnt < 4) && (iter != strRoot.end()))
702                         {
703                                 if ('/' == (*iter))
704                                         slashcnt++;
705
706                                 ++iter;
707                         }
708
709                         if (slashcnt > 2)
710                         {
711                                 // If only 3 slashes were counted, add a trailing slash
712                                 if (slashcnt == 3)
713                                         strRoot += '/';
714
715                                 // Now find the position of the fourth slash
716                                 iter = strRoot.begin();
717                                 int charcnt = 0;
718                                 for (slashcnt=0; slashcnt<4;)
719                                 {
720                                         charcnt++;
721
722                                         if ('/' == (*iter))
723                                                 slashcnt++;
724
725                                         if (++iter == strRoot.end())
726                                                 break;
727                                 }
728
729                                 strRoot.resize(charcnt);
730                                 bValidPath = true;
731                         }
732                 }
733                 else
734                 {
735                         // Assume a standard Windows style path
736                         if (1 < strRoot.length() && (':' == link_filepath[1]))
737                         {
738                                 // Convert backslashes to forward slashes temporarily.
739                                 std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_backslash);
740
741                                 if (2 == strRoot.length())
742                                         strRoot += '/';
743
744                                 if ('/' == strRoot[2])
745                                 {
746                                         strRoot.resize(3);
747                                         bValidPath = true;
748                                 }
749                         }
750                 }
751
752                 if (bValidPath)
753                 {
754                         char szFileSystemType[_MAX_PATH+1];
755
756                         // Restore the original backslashes
757                         std::transform(strRoot.begin(), strRoot.end(), strRoot.begin(), invert_forwardslash);
758
759                         // Windows only supports hard links for the NTFS filing
760                         // system, so let's make sure that's what we're using!!
761                         if (::GetVolumeInformationA(strRoot.c_str(), NULL, 0, NULL, NULL, NULL, szFileSystemType, _MAX_PATH+1))
762                         {
763                                 std::string strRootFileSystemType = szFileSystemType;
764                                 std::transform(strRootFileSystemType.begin(), strRootFileSystemType.end(), strRootFileSystemType.begin(), ::toupper);
765 #if (_WIN32_WINNT >= 0x0500)
766                                 if (0 == strRootFileSystemType.compare("NTFS"))
767                                         if (TestForMinimumSpecOS()) // Hard links were only available from Win2K onwards
768                                                 if (0 == DeleteFileA(link_filepath))
769                                                         ret = GetLastError();
770                                                 else
771                                                         ret = 0; // 'NO_ERROR'
772 #endif
773                         }
774                 }
775                 else
776                         ret = 123; // 'ERROR_INVALID_NAME'
777         }
778         else
779                 ret = 161; // 'ERROR_BAD_PATHNAME'
780
781         if (ret)
782         {
783                 SetLastError(ret);
784                 return (-1);
785         }
786         else
787                 return (0);
788 }
789
790 }  // namespace PBD
791
792
793 //***************************************************************
794 //
795 //      dlopen()
796 //
797 // Emulates POSIX dlopen() using Win32 LoadLibrary().
798 //
799 //      Returns:
800 //
801 //    On Success: A handle to the opened DLL
802 //    On Failure: NULL
803 //
804 PBD_API void* PBD_APICALLTYPE
805 dlopen (const char *file_name, int mode)
806 {
807         // Note that 'mode' is ignored in Win32
808         return(::LoadLibraryA(Glib::locale_from_utf8(file_name).c_str()));
809 }
810
811
812 //***************************************************************
813 //
814 //      dlclose()
815 //
816 // Emulates POSIX dlclose() using Win32 FreeLibrary().
817 //
818 //      Returns:
819 //
820 //    On Success: A non-zero number
821 //    On Failure: 0
822 //
823 PBD_API int PBD_APICALLTYPE
824 dlclose (void *handle)
825 {
826         return (::FreeLibrary((HMODULE)handle));
827 }
828
829
830 //***************************************************************
831 //
832 //      dlsym()
833 //
834 // Emulates POSIX dlsym() using Win32 GetProcAddress().
835 //
836 //      Returns:
837 //
838 //    On Success: A pointer to the found function or symbol
839 //    On Failure: NULL
840 //
841 PBD_API void* PBD_APICALLTYPE
842 dlsym (void *handle, const char *symbol_name)
843 {
844         // First test for RTLD_DEFAULT and RTLD_NEXT
845         if ((handle == 0/*RTLD_DEFAULT*/) || (handle == ((void *) -1L)/*RTLD_NEXT*/))
846         {
847                 return 0; // Not yet supported for Win32
848         }
849         else
850                 return (::GetProcAddress((HMODULE)handle, symbol_name));
851 }
852
853 #define LOCAL_ERROR_BUF_SIZE 1024
854 static char szLastWinError[LOCAL_ERROR_BUF_SIZE];
855 //***************************************************************
856 //
857 //      dlerror()
858 //
859 // Emulates POSIX dlerror() using Win32 GetLastError().
860 //
861 //      Returns:
862 //
863 //    On Success: The translated message corresponding to the
864 //                last error
865 //    On Failure: NULL (if the last error was ERROR_SUCCESS)
866 //
867 PBD_API char* PBD_APICALLTYPE
868 dlerror ()
869 {
870         DWORD dwLastErrorId = GetLastError();
871         if (ERROR_SUCCESS == dwLastErrorId)
872                 return 0;
873         else
874         {
875                 if (0 == FormatMessage(
876                                         FORMAT_MESSAGE_FROM_SYSTEM,
877                                         NULL,
878                                         dwLastErrorId,
879                                         0,
880                                         szLastWinError,
881                                         LOCAL_ERROR_BUF_SIZE,
882                                         0))
883                 {
884                         sprintf(szLastWinError, "Could not decipher the previous error message");
885                 }
886
887                 // POSIX dlerror() seems to reset the
888                 // error system, so emulate that here
889                 SetLastError(ERROR_SUCCESS);
890         }
891
892         return(szLastWinError);
893 }
894
895 #endif  // COMPILER_MSVC