1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 
7 /*************************************************************************
8 *
9 * File: user_lib.cpp
10 *
11 * Module: User-mode library
12 *
13 * Description: common useful user-mode functions
14 *
15 * Author: Ivan
16 *
17 *************************************************************************/
18 
19 
20 #ifndef __USER_LIB_CPP__
21 #define __USER_LIB_CPP__
22 
23 #include "user_lib.h"
24 
25 TCHAR* MediaTypeStrings[] =
26 {
27     "CD-ROM"        ,
28     "CD-R"          ,
29     "CD-RW"         ,
30     "DVD-ROM"       ,
31     "DVD-RAM"       ,
32     "DVD-R"         ,
33     "DVD-RW"        ,
34     "DVD+R"         ,
35     "DVD+RW"        ,
36     "DD CD-ROM"     ,
37     "DD CD-R"       ,
38     "DD CD-RW"      ,
39     "BD-ROM"        ,
40     "BD-RE"         ,
41     "[BUSY]"        ,
42     "Unknown"
43 };
44 
45 void * __cdecl mymemchr (
46     const void * buf,
47     int chr,
48     size_t cnt
49     )
50 {
51     while ( cnt && (*(unsigned char *)buf != (unsigned char)chr) ) {
52         buf = (unsigned char *)buf + 1;
53         cnt--;
54     }
55 
56     return(cnt ? (void *)buf : NULL);
57 } // end mymemchr()
58 
59 char * __cdecl  mystrrchr(
60     const char * string,
61     int ch
62     )
63 {
64     char *start = (char *)string;
65 
66     while (*string++) {;}
67 
68     while (--string != start && *string != (char)ch) {;}
69 
70     if (*string == (char)ch) {
71         return( (char *)string );
72     }
73 
74     return(NULL);
75 } // end mystrrchr()
76 
77 char * __cdecl  mystrchr(
78     const char * string,
79     int ch
80     )
81 {
82     while (*string != (char)ch && *string != '\0' ) {
83         string++;
84     }
85 
86     if (*string == (char)ch) {
87         return( (char *)string );
88     }
89 
90     return(NULL);
91 } // end mystrchr()
92 
93 
94 int __cdecl Exist (
95     PCHAR path
96     )
97 {
98     DWORD attr;
99 
100     attr = GetFileAttributes((LPTSTR)path);
101     if (attr  == 0xffffffff) {
102             return 0;
103     }
104 
105     return 1;
106 
107 } // end Exist()
108 
109 ULONG
110 MyMessageBox(
111     HINSTANCE hInst,
112     HWND hWnd,
113     LPCSTR pszFormat,
114     LPCSTR pszTitle,
115     UINT fuStyle,
116     ...
117     )
118 {
119     CHAR szTitle[80];
120     CHAR szFormat[1024];
121     LPSTR pszMessage;
122     BOOL fOk;
123     int result;
124     va_list ArgList;
125 
126     if (!HIWORD(pszTitle)) {
127         LoadString(hInst, LOWORD(pszTitle), szTitle, sizeof(szTitle)/sizeof(szTitle[0]));
128         pszTitle = szTitle;
129     }
130 
131     if (!HIWORD(pszFormat)) {
132         // Allow this to be a resource ID
133         LoadString(hInst, LOWORD(pszFormat), szFormat, sizeof(szFormat)/sizeof(szFormat[0]));
134         pszFormat = szFormat;
135     }
136 
137     va_start(ArgList, fuStyle);
138     fOk = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
139                         | FORMAT_MESSAGE_FROM_STRING,
140                         pszFormat, 0, 0, (LPTSTR)&pszMessage, 0, &ArgList);
141 
142     va_end(ArgList);
143 
144     if (fOk && pszMessage) {
145         result = MessageBox(hWnd, pszMessage, pszTitle, fuStyle | MB_SETFOREGROUND);
146         LocalFree(pszMessage);
147     } else {
148         return -1;
149     }
150 
151     return result;
152 } // end MyMessageBox()
153 
154 
155 /// Return service status by service name.
156 JS_SERVICE_STATE
157 ServiceInfo(
158     LPCTSTR ServiceName
159     )
160 {
161     SC_HANDLE       schService;
162     DWORD           RC;
163     SERVICE_STATUS  ssStatus;
164     JS_SERVICE_STATE return_value;
165     SC_HANDLE       schSCManager;
166 
167     schSCManager = OpenSCManager(
168                                 NULL,                   // machine (NULL == local)
169                                 NULL,                   // database (NULL == default)
170                                 SC_MANAGER_ALL_ACCESS   // access required
171                                );
172     if (!schSCManager) {
173         schSCManager = OpenSCManager(
174                                     NULL,                   // machine (NULL == local)
175                                     NULL,                   // database (NULL == default)
176                                     SC_MANAGER_CONNECT   // access required
177                                    );
178     }
179     if (!schSCManager)
180         return JS_ERROR_STATUS;
181     schService = OpenService(schSCManager, ServiceName, SERVICE_QUERY_STATUS);
182     if (!schService) {
183         RC = GetLastError();
184         CloseServiceHandle(schSCManager);
185         if (RC == ERROR_SERVICE_DOES_NOT_EXIST) return JS_SERVICE_NOT_PRESENT;
186                                            else return JS_ERROR_STATUS;
187     }
188     QueryServiceStatus(schService, &ssStatus);
189     if(ssStatus.dwCurrentState == SERVICE_RUNNING) {
190         return_value = JS_SERVICE_RUNNING;
191     } else {
192         return_value = JS_SERVICE_NOT_RUNNING;
193     }
194     CloseServiceHandle(schService);
195     CloseServiceHandle(schSCManager);
196     return return_value;
197 } // end ServiceInfo()
198 
199 BOOL
200 CheckCdrwFilter(
201     BOOL ReInstall
202     )
203 {
204     char CdromUpperFilters[1024];
205     bool    found = false;
206 
207     if (LOBYTE(LOWORD(GetVersion())) < 5) {
208         return true;
209     }
210 
211     if (GetRegString(CDROM_CLASS_PATH,REG_UPPER_FILTER_NAME,&CdromUpperFilters[0],arraylen(CdromUpperFilters))) {
212         char *token = &CdromUpperFilters[0];
213 
214         while (*token) {
215             if (!strcmp(token,CDRW_SERVICE)) {
216                 found = true;
217                 break;
218             }
219             token += strlen(token)+1;
220         }
221         if (!found) {
222             memcpy(token,CDRW_SERVICE,sizeof(CDRW_SERVICE));
223             *(token+sizeof(CDRW_SERVICE)) = '\0';
224             *(token+sizeof(CDRW_SERVICE)+1) = '\0';
225             if(ReInstall) {
226                 RegisterString(CDROM_CLASS_PATH,REG_UPPER_FILTER_NAME,&CdromUpperFilters[0],TRUE,token-&CdromUpperFilters[0]+sizeof(CDRW_SERVICE)+1);
227                 found = true;
228             }
229         }
230     } else {
231         memcpy(CdromUpperFilters,CDRW_SERVICE,sizeof(CDRW_SERVICE));
232         CdromUpperFilters[sizeof(CDRW_SERVICE)] = '\0';
233         CdromUpperFilters[sizeof(CDRW_SERVICE)+1] = '\0';
234         if(ReInstall) {
235             RegisterString(CDROM_CLASS_PATH,REG_UPPER_FILTER_NAME,&CdromUpperFilters[0],TRUE,sizeof(CDRW_SERVICE)+1);
236             found = true;
237         }
238     }
239     return found;
240 
241 } // end CheckCdrwFilter()
242 
243 BOOL
244 RegisterString(
245     LPSTR pszKey,
246     LPSTR pszValue,
247     LPSTR pszData,
248     BOOLEAN MultiSz,
249     DWORD size
250     )
251 {
252 
253     HKEY hKey;
254     DWORD dwDisposition;
255 
256     // Create the key, if it exists it will be opened
257     if (ERROR_SUCCESS !=
258         RegCreateKeyEx(
259           HKEY_LOCAL_MACHINE,      // handle of an open key
260           pszKey,                  // address of subkey name
261           0,                       // reserved
262           NULL,                    // address of class string
263           REG_OPTION_NON_VOLATILE, // special options flag
264           KEY_ALL_ACCESS,          // desired security access
265           NULL,                    // address of key security structure
266           &hKey,                   // address of buffer for opened handle
267           &dwDisposition))         // address of disposition value buffer
268     {
269         return FALSE;
270     }
271 
272     // Write the value and it's data to the key
273     if (ERROR_SUCCESS !=
274         RegSetValueEx(
275             hKey,                                   // handle of key to set value for
276             pszValue,                               // address of value to set
277             0,                                      // reserved
278             MultiSz ? REG_MULTI_SZ : REG_SZ,        // flag for value type
279             (CONST BYTE *)pszData,                  // address of value data
280             MultiSz ? size : strlen(pszData) ))     // size of value data
281     {
282 
283         RegCloseKey(hKey);
284         return FALSE;
285     }
286 
287     // Close the key
288     RegCloseKey(hKey);
289 
290     return TRUE;
291 } // end RegisterString()
292 
293 BOOL
294 RegDelString(
295     LPSTR pszKey,
296     LPSTR pszValue
297     )
298 {
299 
300     HKEY hKey;
301     DWORD dwDisposition;
302 
303     // Create the key, if it exists it will be opened
304     if (ERROR_SUCCESS !=
305         RegCreateKeyEx(
306           HKEY_LOCAL_MACHINE,      // handle of an open key
307           pszKey,                  // address of subkey name
308           0,                       // reserved
309           NULL,                    // address of class string
310           REG_OPTION_NON_VOLATILE, // special options flag
311           KEY_ALL_ACCESS,          // desired security access
312           NULL,                    // address of key security structure
313           &hKey,                   // address of buffer for opened handle
314           &dwDisposition))         // address of disposition value buffer
315     {
316         return FALSE;
317     }
318 
319     // Write the value and it's data to the key
320     if (ERROR_SUCCESS !=
321         RegDeleteValue(
322             hKey,                 // handle of key to set value for
323             pszValue))
324     {
325 
326         RegCloseKey(hKey);
327         return FALSE;
328     }
329 
330     // Close the key
331     RegCloseKey(hKey);
332 
333     return TRUE;
334 } // end RegDelString()
335 
336 /// Get string from registry by Key path and Value name
337 BOOL
338 GetRegString(
339     LPSTR pszKey,
340     LPSTR pszValue,
341     LPSTR pszData,
342     DWORD dwBufSize
343     )
344 {
345 
346     HKEY hKey;
347     DWORD dwDataSize = dwBufSize;
348     DWORD dwValueType = REG_SZ;
349 
350     if(!dwBufSize)
351         return FALSE;
352 
353     RegOpenKeyEx(
354        HKEY_LOCAL_MACHINE,    // handle of open key
355        pszKey,                // address of name of subkey to open
356        0,                     // reserved
357        KEY_QUERY_VALUE,       // security access mask
358        &hKey                  // address of handle of open key
359        );
360 
361     if (ERROR_SUCCESS != RegQueryValueEx(
362         hKey,               // handle of key to query
363         pszValue,           // address of name of value to query
364         0,                  // reserved
365         &dwValueType,       // address of buffer for value type
366         (BYTE *)pszData,    // address of data buffer
367         &dwDataSize         // address of data buffer size
368         )) return FALSE;
369 
370     if (pszData[dwDataSize-1] != '\0')
371          pszData[dwDataSize-1] = '\0';
372 
373     return TRUE;
374 } // end GetRegString()
375 
376 BOOL
377 RegisterDword(
378    LPSTR pszKey,
379    LPSTR pszValue,
380    DWORD dwData
381    )
382 {
383 
384     HKEY hKey;
385     DWORD dwDisposition;
386 
387     // Create the key, if it exists it will be opened
388     if (ERROR_SUCCESS !=
389         RegCreateKeyEx(
390           HKEY_LOCAL_MACHINE,      // handle of an open key
391           pszKey,                  // address of subkey name
392           0,                       // reserved
393           NULL,                    // address of class string
394           REG_OPTION_NON_VOLATILE, // special options flag
395           KEY_ALL_ACCESS,          // desired security access
396           NULL,                    // address of key security structure
397           &hKey,                   // address of buffer for opened handle
398           &dwDisposition))         // address of disposition value buffer
399     {
400         return FALSE;
401     }
402 
403     // Write the value and it's data to the key
404     if (ERROR_SUCCESS !=
405         RegSetValueEx(
406             hKey,                   // handle of key to set value for
407             pszValue,               // address of value to set
408             0,                      // reserved
409             REG_DWORD,              // flag for value type
410             (CONST BYTE *)&dwData,  // address of value data
411             4 ))                    // size of value data
412     {
413 
414         RegCloseKey(hKey);
415         return FALSE;
416     }
417 
418     // Close the key
419     RegCloseKey(hKey);
420 
421     return TRUE;
422 } // end RegisterDword()
423 
424 BOOL
425 GetRegUlong(
426     LPSTR pszKey,
427     LPSTR pszValue,
428     PULONG pszData
429     )
430 {
431 
432     HKEY hKey;
433     DWORD dwDataSize = 4;
434     DWORD dwValueType = REG_DWORD;
435     ULONG origValue = *pszData;
436 
437     if(RegOpenKeyEx(
438        HKEY_LOCAL_MACHINE,    // handle of open key
439        pszKey,                // address of name of subkey to open
440        0,                    // reserved
441        KEY_QUERY_VALUE,        // security access mask
442        &hKey                 // address of handle of open key
443         ) != ERROR_SUCCESS) {
444         (*pszData) = origValue;
445         return FALSE;
446     }
447 
448     if(RegQueryValueEx(
449         hKey,         // handle of key to query
450         pszValue,     // address of name of value to query
451         0,             // reserved
452         &dwValueType,// address of buffer for value type
453         (BYTE *)pszData,     // address of data buffer
454         &dwDataSize  // address of data buffer size
455         ) != ERROR_SUCCESS) {
456         (*pszData) = origValue;
457     }
458 
459     RegCloseKey(hKey);
460 
461     return TRUE;
462 } // end GetRegUlong()
463 
464 BOOL
465 SetRegUlong(
466   LPSTR pszKey,
467   LPSTR pszValue,
468   PULONG pszData
469   )
470 {
471 
472     HKEY    hKey;
473     DWORD   dwDataSize = 4;
474     DWORD   dwValueType = REG_DWORD;
475     LPVOID  lpMsgBuf;
476     LONG    RC;
477 
478     if (!(ERROR_SUCCESS == (RC = RegOpenKeyEx(
479        HKEY_LOCAL_MACHINE,    // handle of open key
480        pszKey,                // address of name of subkey to open
481        0,                    // reserved
482        KEY_ALL_ACCESS ,        // security access mask
483        &hKey                 // address of handle of open key
484        )))) {
485         FormatMessage(
486             FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
487             NULL,
488             RC,
489             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
490             (LPTSTR) &lpMsgBuf,
491             0,
492             NULL);
493 
494         // Display the string.
495         MessageBox( NULL, (CCHAR*)lpMsgBuf, "Error", MB_OK|MB_ICONHAND );
496 
497         // Free the buffer.
498         LocalFree( lpMsgBuf );
499         return FALSE;
500     }
501 
502     if (!(ERROR_SUCCESS == (RC = RegSetValueEx(
503         hKey,         // handle of key to query
504         pszValue,     // address of name of value to query
505         0,             // reserved
506         REG_DWORD,// address of buffer for value type
507         (BYTE *)pszData,     // address of data buffer
508         sizeof(ULONG)  // data buffer size
509         )))) {
510         FormatMessage(
511             FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
512             NULL,
513             RC,
514             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
515             (LPTSTR) &lpMsgBuf,
516             0,
517             NULL);
518 
519         // Display the string.
520         MessageBox( NULL, (CCHAR*)lpMsgBuf, "Error", MB_OK|MB_ICONHAND );
521 
522         // Free the buffer.
523         LocalFree( lpMsgBuf );
524 
525     }
526     RegCloseKey(hKey);
527     return TRUE;
528 } // end SetRegUlong()
529 
530 BOOL
531 Privilege(
532     LPTSTR pszPrivilege,
533     BOOL bEnable
534     )
535 {
536 
537     HANDLE           hToken;
538     TOKEN_PRIVILEGES tp;
539 
540     //
541     // obtain the token, first check the thread and then the process
542     //
543     if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, TRUE, &hToken)){
544         if (GetLastError() == ERROR_NO_TOKEN) {
545             if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
546                 return FALSE;
547         }
548         else return FALSE;
549     }
550 
551     //
552     // get the luid for the privilege
553     //
554     if (!LookupPrivilegeValue(NULL, pszPrivilege, &tp.Privileges[0].Luid))
555          return FALSE;
556 
557     tp.PrivilegeCount = 1;
558 
559     if (bEnable)
560         tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
561     else
562         tp.Privileges[0].Attributes = 0;
563 
564     //
565     // enable or disable the privilege
566     //
567     if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0))
568         return FALSE;
569 
570     if (!CloseHandle(hToken))
571         return FALSE;
572 
573     return TRUE;
574 } // end Privilege()
575 
576 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
577 
578 
579 BOOL IsWow64(VOID)
580 {
581     BOOL bIsWow64 = FALSE;
582     LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"),"IsWow64Process");
583 
584     if (NULL != fnIsWow64Process)
585     {
586         if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
587         {
588             return FALSE;
589         }
590     }
591     return bIsWow64;
592 } // end IsWow64()
593 
594 
595 HANDLE
596 CreatePublicEvent(
597     PWCHAR EventName
598     )
599 {
600     SECURITY_DESCRIPTOR sdPublic;
601     SECURITY_ATTRIBUTES saPublic;
602 
603     InitializeSecurityDescriptor(
604         &sdPublic,
605         SECURITY_DESCRIPTOR_REVISION
606         );
607 
608     SetSecurityDescriptorDacl(
609         &sdPublic,
610         TRUE,
611         NULL,
612         FALSE
613         );
614 
615     saPublic.nLength = sizeof(saPublic);
616     saPublic.lpSecurityDescriptor = &sdPublic;
617 
618     return CreateEventW(
619         &saPublic,
620         TRUE,
621         FALSE,
622         EventName);
623 
624 } // end CreatePublicEvent()
625 
626 /// Send Device IO Controls to undelaying level via handle
627 ULONG
628 UDFPhSendIOCTL(
629     IN ULONG IoControlCode,
630     IN HANDLE DeviceObject,
631     IN PVOID InputBuffer ,
632     IN ULONG InputBufferLength,
633     OUT PVOID OutputBuffer ,
634     IN ULONG OutputBufferLength,
635     IN BOOLEAN OverrideVerify,
636     IN PVOID Dummy
637     )
638 {
639     ULONG real_read;
640     ULONG ret;
641     LONG offh=0;
642     ULONG RC = DeviceIoControl(DeviceObject,IoControlCode,
643                                 InputBuffer,InputBufferLength,
644                                 OutputBuffer,OutputBufferLength,
645                                 &real_read,NULL);
646 
647     if (!RC) {
648         ret = GetLastError();
649     }
650     return RC ? 1 : -1;
651 } // end UDFPhSendIOCTL()
652 
653 CHAR    RealDeviceName[MAX_PATH+1];
654 
655 PCHAR
656 UDFGetDeviceName(
657     PCHAR szDeviceName
658     )
659 {
660     HANDLE      hDevice;
661     WCHAR       DeviceName[MAX_PATH+1];
662     ULONG       RC;
663 
664     ODS("  UDFGetDeviceName\r\n");
665     hDevice = CreateFile(szDeviceName, GENERIC_READ ,
666                          FILE_SHARE_READ,
667                          NULL,
668                          OPEN_EXISTING,
669                          FILE_ATTRIBUTE_NORMAL,  NULL);
670 
671     if (hDevice == ((HANDLE)-1)) {
672         strcpy(RealDeviceName,"");
673         return (PCHAR)&RealDeviceName;
674     }
675 
676     RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_DEVICE_NAME,hDevice,
677                         &DeviceName,(MAX_PATH+1)*sizeof(WCHAR),
678                         &DeviceName,(MAX_PATH+1)*sizeof(WCHAR), FALSE,NULL);
679 
680     if(RC == 1) {
681         wcstombs((PCHAR)&RealDeviceName,&DeviceName[1],(USHORT)DeviceName[0]);
682         RealDeviceName[(USHORT)DeviceName[0]/sizeof(USHORT)] = '\0';
683     } else {
684         strcpy(RealDeviceName, szDeviceName+4);
685     }
686 
687     CloseHandle(hDevice);
688 
689     return (PCHAR)(strrchr(RealDeviceName, '\\')+1);
690 } // end UDFGetDeviceName()
691 
692 BOOL
693 GetOptUlong(
694     PCHAR Path,
695     PCHAR OptName,
696     PULONG OptVal
697     )
698 {
699     if(!Path) {
700         return FALSE;
701     }
702     if(Path[0] && Path[1] == ':') {
703         CHAR SettingFile[MAX_PATH];
704         CHAR Setting[16];
705 
706         sprintf(SettingFile, "%s\\%s", Path, UDF_CONFIG_STREAM_NAME);
707         GetPrivateProfileString("DiskSettings", OptName, "d", &Setting[0], 10, SettingFile);
708         Setting[15]=0;
709         if (Setting[0] != 'd') {
710             if(Setting[0] == '0' && Setting[1] == 'x') {
711                 sscanf(Setting+2, "%x", OptVal);
712             } else {
713                 sscanf(Setting, "%d", OptVal);
714             }
715             return TRUE;
716         }
717         return FALSE;
718     }
719     return GetRegUlong(Path, OptName, OptVal);
720 } // end GetOptUlong()
721 
722 BOOL
723 SetOptUlong(
724     PCHAR Path,
725     PCHAR OptName,
726     PULONG OptVal
727     )
728 {
729     if(!Path) {
730         return FALSE;
731     }
732     if(Path[0] && Path[1] == ':') {
733         CHAR SettingFile[MAX_PATH];
734         CHAR Setting[16];
735         if(Path[2] != '\\') {
736             sprintf(SettingFile, "%s\\%s", Path, UDF_CONFIG_STREAM_NAME);
737         } else {
738             sprintf(SettingFile, "%s%s", Path, UDF_CONFIG_STREAM_NAME);
739         }
740         sprintf(Setting, "%d\n", (*OptVal));
741         return WritePrivateProfileString("DiskSettings", OptName, Setting, SettingFile);
742     }
743     return SetRegUlong(Path, OptName, OptVal);
744 } // end SetOptUlong()
745 
746 ULONG
747 UDFGetOptUlongInherited(
748     PCHAR Drive,
749     PCHAR OptName,
750     PULONG OptVal,
751     ULONG CheckDepth
752     )
753 {
754     CHAR    LocalPath[1024];
755     ULONG   retval = 0;
756 
757     ODS("  UDFGetOptUlongInherited\r\n");
758 
759     if(GetOptUlong(UDF_SERVICE_PARAM_PATH, OptName, OptVal)) {
760         retval = UDF_OPTION_GLOBAL;
761     }
762     if(CheckDepth <= UDF_OPTION_GLOBAL) {
763         return retval;
764     }
765     strcpy(LocalPath,UDF_SERVICE_PARAM_PATH);
766     strcat(LocalPath,"\\");
767     strcat(LocalPath,UDFGetDeviceName(Drive));
768     if(GetOptUlong(LocalPath, OptName, OptVal)) {
769         retval = UDF_OPTION_DEVSPEC;
770     }
771     if(CheckDepth <= UDF_OPTION_DEVSPEC) {
772         return retval;
773     }
774     if(GetOptUlong(Drive, OptName, OptVal))
775         retval = UDF_OPTION_DISKSPEC;
776     return retval;
777 } // end UDFGetOptUlongInherited()
778 
779 HANDLE
780 OpenOurVolume(
781     PCHAR szDeviceName
782     )
783 {
784     HANDLE hDevice;
785 
786     // Open device volume
787     hDevice = CreateFile(szDeviceName, GENERIC_READ ,
788                              FILE_SHARE_READ,
789                              NULL,
790                              OPEN_EXISTING,
791                              FILE_ATTRIBUTE_NORMAL,  NULL);
792 
793     if (hDevice == ((HANDLE)-1)) {
794         hDevice = CreateFile(szDeviceName, GENERIC_READ ,
795                                  FILE_SHARE_READ | FILE_SHARE_WRITE,
796                                  NULL,
797                                  OPEN_EXISTING,
798                                  FILE_ATTRIBUTE_NORMAL,  NULL);
799 
800     }
801     return hDevice;
802 } // end OpenOurVolume()
803 
804 ULONG
805 drv_letter_to_index(
806     WCHAR a
807     )
808 {
809     if(a >= 'a' && a <= 'z') {
810         return a - 'a';
811     }
812     if(a >= 'A' && a <= 'Z') {
813         return a - 'A';
814     }
815     return -1;
816 } // end drv_letter_to_index()
817 
818 /// Start app with desired parameters
819 DWORD
820 WINAPI
821 LauncherRoutine2(
822     LPVOID lpParameter
823     )
824 {
825     PCHAR ParamStr = (PCHAR)lpParameter;
826     STARTUPINFO proc_startup_info;
827     PROCESS_INFORMATION proc_info;
828     CHAR szLaunchPath[MAX_PATH],ErrMes[50];
829     INT  index;
830     ULONG MkUdfRetCode;
831     CHAR szTemp[256];
832 
833     GetRegString(UDF_KEY,"ToolsPath",szLaunchPath, sizeof(szLaunchPath));
834     SetCurrentDirectory(szLaunchPath);
835 
836     strcat(szLaunchPath,"\\");
837     //strcat(szLaunchPath,UDFFMT);
838     strcat(szLaunchPath,ParamStr);
839 
840     //strcpy(MkUdfStatus,"");
841 
842 #ifndef TESTMODE
843     proc_startup_info.cb = sizeof(proc_startup_info);
844     proc_startup_info.lpReserved = 0;
845     proc_startup_info.lpReserved2 = 0;
846     proc_startup_info.cbReserved2 = 0;
847     proc_startup_info.lpDesktop = 0;
848     proc_startup_info.lpTitle = 0;
849     proc_startup_info.dwFlags = 0;
850 
851     proc_startup_info.hStdInput = NULL;
852     proc_startup_info.hStdOutput = NULL;
853     proc_startup_info.hStdError = NULL;
854 
855     if(CreateProcess(NULL, szLaunchPath, 0,0, TRUE, CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS,
856                   0,0, &proc_startup_info, &proc_info)) {
857 
858         //hFmtProc[i] = proc_info.hProcess;
859         WaitForSingleObject(proc_info.hProcess, -1);
860         GetExitCodeProcess(proc_info.hProcess, &MkUdfRetCode);
861         index=0;
862 /*
863         while (mkudf_err_msg[index].err_code != 0xffffffff){
864           if (mkudf_err_msg[index].err_code == MkUdfRetCode) break;
865           index++;
866         }
867 */
868         //strcpy(MkUdfStatus,mkudf_err_msg[index].err_msg);
869 
870         CloseHandle(proc_info.hThread);
871         CloseHandle(proc_info.hProcess);
872     } else {
873         strcpy(ErrMes,"Stop: Cannot launch ");
874         strcat(ErrMes,szLaunchPath);
875         sprintf(szTemp," error %d",GetLastError());
876         strcat(ErrMes,szTemp);
877         MessageBox(NULL,ErrMes,"UDFFormat",MB_OK | MB_ICONHAND);
878 
879     }
880 #else
881         MessageBox(NULL,szLaunchPath,"Message",MB_OK);
882         Sleep(500);
883         MkUdfRetCode = MKUDF_OK;
884 //        MkUdfRetCode = MKUDF_FORMAT_REQUIRED;
885 //        MkUdfRetCode = MKUDF_CANT_BLANK;
886 
887         index = 0;
888         while (mkudf_err_msg[index].err_code != 0xffffffff){
889           if (mkudf_err_msg[index].err_code == MkUdfRetCode) break;
890           index++;
891         }
892         //strcpy(MkUdfStatus,mkudf_err_msg[index].err_msg);
893 
894 #endif
895     return MkUdfRetCode;
896 } // end LauncherRoutine2()
897 
898 
899 #endif // __USER_LIB_CPP__
900