home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 March / CMCD0304.ISO / Software / Freeware / Programare / nullsoft / nsis20.exe / Source / exehead / util.c < prev    next >
C/C++ Source or Header  |  2004-02-07  |  17KB  |  688 lines

  1. #include "../Platform.h"
  2. #include <shellapi.h>
  3. #include "util.h"
  4. #include "state.h"
  5. #include "config.h"
  6. #include "lang.h"
  7. #include "exec.h"
  8.  
  9. #include "fileform.h"
  10. #include "ui.h"
  11.  
  12. #ifdef NSIS_CONFIG_LOG
  13. #ifndef NSIS_CONFIG_LOG_ODS
  14. char g_log_file[1024];
  15. #endif
  16. #endif
  17.  
  18. // *** DO NOT DECLARE MORE VARIABLES INSIDE THIS PRAGMAS ***
  19. // This will produce a special section called ".ndata" (stands for nsis data)
  20. // this way makensis during build time, can search for this section by name
  21. // and change the virtual size of this section
  22. // which result in extra memory for extra variables without code to do allocation :)
  23. // nsis then removes the "DISCARDABLE" style from section (for safe)
  24. #pragma bss_seg( VARS_SECTION_NAME )
  25. NSIS_STRING g_usrvars[1];
  26. #pragma bss_seg()
  27. #define SECTION_VARS_RWD "/section:" ## VARS_SECTION_NAME ## ",rwd"
  28. #pragma comment(linker, SECTION_VARS_RWD)
  29.  
  30. void NSISCALL FreePIDL(LPITEMIDLIST idl)
  31. {
  32.   IMalloc *m;
  33.   SHGetMalloc(&m);
  34.   if (m)
  35.   {
  36.     m->lpVtbl->Free(m, idl);
  37.     m->lpVtbl->Release(m);
  38.   }
  39. }
  40.  
  41. HANDLE NSISCALL myCreateProcess(char *cmd, char *dir)
  42. {
  43.   DWORD d;
  44.   PROCESS_INFORMATION ProcInfo;
  45.   static STARTUPINFO StartUp;
  46.   StartUp.cb=sizeof(StartUp);
  47.   d=GetFileAttributes(dir);
  48.   if (d == INVALID_FILE_ATTRIBUTES || !(d&FILE_ATTRIBUTE_DIRECTORY))
  49.     dir=0;
  50.   if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, dir, &StartUp, &ProcInfo))
  51.     return NULL;
  52.   CloseHandle(ProcInfo.hThread);
  53.   return ProcInfo.hProcess;
  54. }
  55.  
  56. /*BOOL NSISCALL my_SetWindowText(HWND hWnd, const char *val)
  57. {
  58.   return SendMessage(hWnd,WM_SETTEXT,0,(LPARAM)val);
  59. }*/
  60.  
  61. BOOL NSISCALL my_SetDialogItemText(HWND dlg, UINT idx, const char *val)
  62. {
  63.   return SetDlgItemText(dlg,idx,val);
  64.   //return my_SetWindowText(GetDlgItem(dlg,idx),val);
  65. }
  66.  
  67. int NSISCALL my_GetDialogItemText(UINT idx, char *val)
  68. {
  69.   extern HWND m_curwnd;
  70.   return GetDlgItemText(m_curwnd, idx, val, NSIS_MAX_STRLEN);
  71. }
  72.  
  73. int NSISCALL my_MessageBox(const char *text, UINT type) {
  74.   int _type = type & 0x000FFFFF;
  75. #ifdef NSIS_CONFIG_SILENT_SUPPORT
  76.   // default for silent installers
  77.   if (g_exec_flags.silent && type >> 20)
  78.     return type >> 20;
  79. #endif
  80.   // no silent or no default, just show
  81.   if (g_exec_flags.rtl)
  82.     _type ^= MB_RIGHT | MB_RTLREADING;
  83.   return MessageBox(g_hwnd, text, g_caption, _type);
  84. }
  85.  
  86. void * NSISCALL my_GlobalAlloc(DWORD dwBytes) {
  87.   return (void *)GlobalAlloc(GPTR, dwBytes);
  88. }
  89.  
  90. #ifdef NSIS_SUPPORT_RMDIR
  91. void NSISCALL doRMDir(char *buf, int flags) // 1 - recurse, 2 - rebootok
  92. {
  93.   if (is_valid_instpath(buf))
  94.   {
  95.     if (flags&1) {
  96.       SHFILEOPSTRUCT op;
  97.  
  98.       op.hwnd=g_hwnd;
  99.       op.wFunc=FO_DELETE;
  100.       buf[mystrlen(buf)+1]=0;
  101.       op.pFrom=buf;
  102.       op.pTo=0;
  103.  
  104.       op.fFlags=FOF_NOERRORUI|FOF_SILENT|FOF_NOCONFIRMATION;
  105.  
  106.       SHFileOperation(&op);
  107.     }
  108. #ifdef NSIS_SUPPORT_MOVEONREBOOT
  109.     else if (!RemoveDirectory(buf) && flags&2) {
  110.       log_printf2("Remove folder on reboot: %s",buf);
  111.       MoveFileOnReboot(buf,0);
  112.     }
  113. #else
  114.     else RemoveDirectory(buf);
  115. #endif
  116.   }
  117.   log_printf2("RMDir: RemoveDirectory(\"%s\")",buf);
  118. }
  119. #endif//NSIS_SUPPORT_RMDIR
  120.  
  121. char *NSISCALL addtrailingslash(char *str)
  122. {
  123.   if (lastchar(str)!='\\') lstrcat(str,"\\");
  124.   return str;
  125. }
  126.  
  127. /*char NSISCALL lastchar(const char *str)
  128. {
  129.   return *CharPrev(str,str+mystrlen(str));
  130. }*/
  131.  
  132. char * NSISCALL findchar(char *str, char c)
  133. {
  134.   while (*str && *str != c)
  135.   {
  136.     str = CharNext(str);
  137.   }
  138.   return str;
  139. }
  140.  
  141. void NSISCALL trimslashtoend(char *buf)
  142. {
  143.   char *p = buf + mystrlen(buf);
  144.   do
  145.   {
  146.     if (*p == '\\')
  147.       break;
  148.     p = CharPrev(buf, p);
  149.   } while (p > buf);
  150.  
  151.   *p = 0;
  152. }
  153.  
  154. int NSISCALL validpathspec(char *ubuf)
  155. {
  156.   char dl = ubuf[0] | 0x20; // convert alleged drive letter to lower case
  157.   return ((*(WORD*)ubuf==CHAR2_TO_WORD('\\','\\')) || (dl >= 'a' && dl <= 'z' && *CharNext(ubuf)==':'));
  158. }
  159.  
  160. char * NSISCALL skip_root(char *path)
  161. {
  162.   char *p = CharNext(path);
  163.   char *p2 = CharNext(p);
  164.  
  165.   if (*path && *(WORD*)p == CHAR2_TO_WORD(':', '\\'))
  166.   {
  167.     return CharNext(p2);
  168.   }
  169.   else if (*(WORD*)path == CHAR2_TO_WORD('\\','\\'))
  170.   {
  171.     // skip host and share name
  172.     int x = 2;
  173.     while (x--)
  174.     {
  175.       p2 = findchar(p2, '\\');
  176.       if (!*p2)
  177.         return NULL;
  178.       p2 = CharNext(p2);
  179.     }
  180.  
  181.     return p2;
  182.   }
  183.   else
  184.     return NULL;
  185. }
  186.  
  187. int NSISCALL is_valid_instpath(char *s)
  188. {
  189.   static char tmp[NSIS_MAX_STRLEN];
  190.   char *root;
  191.   
  192.   mystrcpy(tmp, s);
  193.  
  194.   root = skip_root(tmp);
  195.  
  196.   if (!root)
  197.     return 0;
  198.  
  199.   if ((g_flags & CH_FLAGS_NO_ROOT_DIR) && (!*root || *root == '\\'))
  200.     return 0;
  201.  
  202.   while (mystrlen(tmp) > root - tmp)
  203.   {
  204.     WIN32_FIND_DATA *fd = file_exists(tmp);
  205.     // if the directory bit not set then it's a file, which is not a valid inst dir...
  206.     // GetFileAttributes is not used because it doesn't work with certain files (error 32)
  207.     // as for concers of the user using * or ?, that's invalid anyway...
  208.     if (fd && !(fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  209.       return 0;
  210.     trimslashtoend(tmp);
  211.   }
  212.  
  213.   // if the root drive exists
  214.   if (GetFileAttributes(tmp) == INVALID_FILE_ATTRIBUTES)
  215.     return 0;
  216.  
  217.   return 1;
  218. }
  219.  
  220. char * NSISCALL mystrstri(char *a, char *b)
  221. {
  222.   int l = mystrlen(b);
  223.   while (mystrlen(a) >= l)
  224.   {
  225.     char c = a[l];
  226.     a[l] = 0;
  227.     if (!lstrcmpi(a, b))
  228.     {
  229.       a[l] = c;
  230.       return a;
  231.     }
  232.     a[l] = c;
  233.     a = CharNext(a);
  234.   }
  235.   return NULL;
  236. }
  237.  
  238. void * NSISCALL mini_memcpy(void *out, const void *in, int len)
  239. {
  240.   char *c_out=(char*)out;
  241.   char *c_in=(char *)in;
  242.   while (len-- > 0)
  243.   {
  244.     *c_out++=*c_in++;
  245.   }
  246.   return out;
  247. }
  248.  
  249.  
  250. HANDLE NSISCALL myOpenFile(const char *fn, DWORD da, DWORD cd)
  251. {
  252.   int attr = GetFileAttributes(fn);
  253.   return CreateFile(
  254.     fn,
  255.     da,
  256.     FILE_SHARE_READ,
  257.     NULL,
  258.     cd,
  259.     attr == INVALID_FILE_ATTRIBUTES ? 0 : attr,
  260.     NULL
  261.   );
  262. }
  263.  
  264. char * NSISCALL my_GetTempFileName(char *buf, const char *dir)
  265. {
  266.   int n = 100;
  267.   while (n--)
  268.   {
  269.     char prefix[4];
  270.     *(LPDWORD)prefix = CHAR4_TO_DWORD('n', 's', 'a', 0);
  271.     prefix[2] += (char)(GetTickCount() % 26);
  272.     if (GetTempFileName(dir, prefix, 0, buf))
  273.       return buf;
  274.   }
  275.   *buf = 0;
  276.   return 0;
  277. }
  278.  
  279. #ifdef NSIS_SUPPORT_MOVEONREBOOT
  280. void NSISCALL MoveFileOnReboot(LPCTSTR pszExisting, LPCTSTR pszNew)
  281. {
  282.   BOOL fOk = 0;
  283.   HMODULE hLib=GetModuleHandle("kernel32.dll");
  284.   if (hLib)
  285.   {
  286.     typedef BOOL (WINAPI *mfea_t)(LPCSTR lpExistingFileName,LPCSTR lpNewFileName,DWORD dwFlags);
  287.     mfea_t mfea;
  288.     mfea=(mfea_t) GetProcAddress(hLib,"MoveFileExA");
  289.     if (mfea)
  290.     {
  291.       fOk=mfea(pszExisting, pszNew, MOVEFILE_DELAY_UNTIL_REBOOT|MOVEFILE_REPLACE_EXISTING);
  292.     }
  293.   }
  294.  
  295.   if (!fOk)
  296.   {
  297.     static char szRenameLine[1024];
  298.     static char wininit[1024];
  299.     static char tmpbuf[1024];
  300.     int cchRenameLine;
  301.     char *szRenameSec = "[Rename]\r\n";
  302.     HANDLE hfile, hfilemap;
  303.     DWORD dwFileSize, dwRenameLinePos;
  304.  
  305.     int spn;
  306.  
  307.     *((int *)tmpbuf) = *((int *)"NUL");
  308.  
  309.     if (pszNew) {
  310.       // create the file if it's not already there to prevent GetShortPathName from failing
  311.       CloseHandle(myOpenFile(pszNew,0,CREATE_NEW));
  312.       spn = GetShortPathName(pszNew,tmpbuf,1024);
  313.       if (!spn || spn > 1024)
  314.         return;
  315.     }
  316.     // wininit is used as a temporary here
  317.     spn = GetShortPathName(pszExisting,wininit,1024);
  318.     if (!spn || spn > 1024)
  319.       return;
  320.     cchRenameLine = wsprintf(szRenameLine,"%s=%s\r\n",tmpbuf,wininit);
  321.  
  322.     GetWindowsDirectory(wininit, 1024-16);
  323.     lstrcat(wininit, "\\wininit.ini");
  324.     hfile = CreateFile(wininit,
  325.         GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
  326.         FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  327.  
  328.     if (hfile != INVALID_HANDLE_VALUE)
  329.     {
  330.       dwFileSize = GetFileSize(hfile, NULL);
  331.       hfilemap = CreateFileMapping(hfile, NULL, PAGE_READWRITE, 0, dwFileSize + cchRenameLine + 10, NULL);
  332.  
  333.       if (hfilemap != NULL)
  334.       {
  335.         LPSTR pszWinInit = (LPSTR) MapViewOfFile(hfilemap, FILE_MAP_WRITE, 0, 0, 0);
  336.  
  337.         if (pszWinInit != NULL)
  338.         {
  339.           LPSTR pszRenameSecInFile = mystrstri(pszWinInit, szRenameSec);
  340.           if (pszRenameSecInFile == NULL)
  341.           {
  342.             mystrcpy(pszWinInit+dwFileSize, szRenameSec);
  343.             dwFileSize += 10;
  344.             dwRenameLinePos = dwFileSize;
  345.           }
  346.           else
  347.           {
  348.             char *pszFirstRenameLine = pszRenameSecInFile+10;
  349.             char *pszNextSec = mystrstri(pszFirstRenameLine,"\n[");
  350.             if (pszNextSec)
  351.             {
  352.               char *p = ++pszNextSec;
  353.               while (p < pszWinInit + dwFileSize) {
  354.                 p[cchRenameLine] = *p;
  355.                 p++;
  356.               }
  357.  
  358.               dwRenameLinePos = pszNextSec - pszWinInit;
  359.             }
  360.             // rename section is last, stick item at end of file
  361.             else dwRenameLinePos = dwFileSize;
  362.           }
  363.  
  364.           mini_memcpy(&pszWinInit[dwRenameLinePos], szRenameLine, cchRenameLine);
  365.           dwFileSize += cchRenameLine;
  366.  
  367.           UnmapViewOfFile(pszWinInit);
  368.  
  369.           //fOk++;
  370.         }
  371.         CloseHandle(hfilemap);
  372.       }
  373.       SetFilePointer(hfile, dwFileSize, NULL, FILE_BEGIN);
  374.       SetEndOfFile(hfile);
  375.       CloseHandle(hfile);
  376.     }
  377.   }
  378.   //return fOk;
  379.  
  380. #ifdef NSIS_SUPPORT_REBOOT
  381.   g_exec_flags.exec_reboot++;
  382. #endif
  383. }
  384. #endif
  385.  
  386. void NSISCALL myRegGetStr(HKEY root, const char *sub, const char *name, char *out)
  387. {
  388.   HKEY hKey;
  389.   *out=0;
  390.   if (RegOpenKeyEx(root,sub,0,KEY_READ,&hKey) == ERROR_SUCCESS)
  391.   {
  392.     DWORD l = NSIS_MAX_STRLEN;
  393.     DWORD t;
  394.     if (RegQueryValueEx(hKey,name,NULL,&t,out,&l ) != ERROR_SUCCESS || (t != REG_SZ && t != REG_EXPAND_SZ)) *out=0;
  395.     out[NSIS_MAX_STRLEN-1]=0;
  396.     RegCloseKey(hKey);
  397.   }
  398. }
  399.  
  400. void NSISCALL myitoa(char *s, int d)
  401. {
  402.   wsprintf(s,"%d",d);
  403. }
  404.  
  405. int NSISCALL myatoi(char *s)
  406. {
  407.   unsigned int v=0;
  408.   int sign=1; // sign of positive
  409.   char m=10; // base of 0
  410.   char t='9'; // cap top of numbers at 9
  411.  
  412.   if (*s == '-')
  413.   {
  414.     s++;  //skip over -
  415.     sign=-1; // sign flip
  416.   }
  417.  
  418.   if (*s == '0')
  419.   {
  420.     s++; // skip over 0
  421.     if (s[0] >= '0' && s[0] <= '7')
  422.     {
  423.       m=8; // base of 8
  424.       t='7'; // cap top at 7
  425.     }
  426.     if ((s[0] & ~0x20) == 'X')
  427.     {
  428.       m=16; // base of 16
  429.       s++; // advance over 'x'
  430.     }
  431.   }
  432.  
  433.   for (;;)
  434.   {
  435.     int c=*s++;
  436.     if (c >= '0' && c <= t) c-='0';
  437.     else if (m==16 && (c & ~0x20) >= 'A' && (c & ~0x20) <= 'F') c = (c & 7) + 9;
  438.     else break;
  439.     v*=m;
  440.     v+=c;
  441.   }
  442.   return ((int)v)*sign;
  443. }
  444.  
  445. // Straight copies of selected shell functions.  Calling local functions
  446. // requires less code than DLL functions.  For the savings to outweigh the cost
  447. // of a new function there should be about a couple of dozen or so calls.
  448. char * NSISCALL mystrcpy(char *out, const char *in)
  449. {
  450.   return lstrcpy(out, in);
  451. }
  452.  
  453. int NSISCALL mystrlen(const char *in)
  454. {
  455.   return lstrlen(in);
  456. }
  457.  
  458. char ps_tmpbuf[NSIS_MAX_STRLEN*2];
  459.  
  460. #define SYSREGKEY "Software\\Microsoft\\Windows\\CurrentVersion"
  461.  
  462. // Based on Dave Laundon's simplified process_string
  463. char * NSISCALL GetNSISString(char *outbuf, int strtab)
  464. {
  465.   char *in = (char*)GetNSISStringNP(GetNSISTab(strtab));
  466.   char *out = ps_tmpbuf;
  467.   if ((unsigned int) (outbuf - ps_tmpbuf) < sizeof(ps_tmpbuf))
  468.   {
  469.     out = outbuf;
  470.     outbuf = 0;
  471.   }
  472.   while (*in && out - ps_tmpbuf < NSIS_MAX_STRLEN)
  473.   {
  474.     unsigned char nVarIdx = (unsigned char)*in++;
  475.     int nData;
  476.     int fldrs[4];
  477.     if (nVarIdx > NS_SKIP_CODE)
  478.     {
  479.       nData = ((in[1] & 0x7F) << 7) | (in[0] & 0x7F);
  480.       fldrs[0] = in[0]; // current user
  481.       fldrs[1] = in[0] | CSIDL_FLAG_CREATE;
  482.       fldrs[2] = in[1]; // all users
  483.       fldrs[3] = in[1] | CSIDL_FLAG_CREATE;
  484.       in += 2;
  485.     }
  486.     if (nVarIdx == NS_SKIP_CODE)
  487.     {
  488.       *out++ = *in++;
  489.     }
  490.     else if (nVarIdx == NS_SHELL_CODE)
  491.     {
  492.       // NOTE 1: the code CSIDL_PRINTERS, is used for QUICKLAUNCH
  493.       // NOTE 2: the code CSIDL_BITBUCKET is used for COMMONFILES
  494.       // NOTE 3: the code CSIDL_CONTROLS is used for PROGRAMFILES
  495.       LPITEMIDLIST idl;
  496.       char *append = 0;
  497.  
  498.       int x = 0;
  499.  
  500.       *out = 0;
  501.  
  502.       if (fldrs[2] == CSIDL_PRINTERS) // QUICKLAUNCH
  503.       {
  504.         append = "\\Microsoft\\Internet Explorer\\Quick Launch";
  505.         x = 2;
  506.       }
  507.       if (fldrs[0] == CSIDL_PROGRAM_FILES_COMMON)
  508.       {
  509.         myRegGetStr(HKEY_LOCAL_MACHINE, SYSREGKEY, "CommonFilesDir", out);
  510.       }
  511.       if (fldrs[0] == CSIDL_PROGRAM_FILES)
  512.       {
  513.         myRegGetStr(HKEY_LOCAL_MACHINE, SYSREGKEY, "ProgramFilesDir", out);
  514.         if (!*out)
  515.           mystrcpy(out, "C:\\Program Files");
  516.       }
  517.       if (fldrs[0] == CSIDL_SYSTEM)
  518.       {
  519.         GetSystemDirectory(out, NSIS_MAX_STRLEN);
  520.       }
  521.       if (fldrs[0] == CSIDL_WINDOWS)
  522.       {
  523.         GetWindowsDirectory(out, NSIS_MAX_STRLEN);
  524.       }
  525.  
  526.       if (!*out)
  527.       {
  528.         x = 4;
  529.         if (!g_exec_flags.all_user_var)
  530.           x = 2;
  531.       }
  532.  
  533.       while (x--)
  534.       {
  535.         if (!SHGetSpecialFolderLocation(g_hwnd, fldrs[x], &idl))
  536.         {
  537.           BOOL res = SHGetPathFromIDList(idl, out);
  538.           FreePIDL(idl);
  539.           if (res)
  540.           {
  541.             break;
  542.           }
  543.         }
  544.         else
  545.           *out=0;
  546.       }
  547.  
  548.       if (*out && append)
  549.       {
  550.         lstrcat(out, append);
  551.       }
  552.  
  553.       validate_filename(out);
  554.       out += mystrlen(out);
  555.     }
  556.     else if (nVarIdx == NS_VAR_CODE)
  557.     {
  558.       if (nData == 27) // HWNDPARENT
  559.         myitoa(out, (unsigned int) g_hwnd);
  560.       else
  561.         mystrcpy(out, g_usrvars[nData]);
  562.       // validate the directory name
  563.       if ((unsigned int)(nData - 21) < 6) {
  564.         // validate paths for $INSTDIR, $OUTDIR, $EXEDIR, $LANGUAGE, $TEMP and $PLUGINSDIR
  565.         // $LANGUAGE is just a number anyway...
  566.         validate_filename(out);
  567.       }
  568.       out += mystrlen(out);
  569.     } // == VAR_CODES_START
  570.     else if (nVarIdx == NS_LANG_CODE)
  571.     {
  572.       GetNSISString(out, -nData-1);
  573.       out += mystrlen(out);
  574.     }
  575.     else // Normal char
  576.     {
  577.       *out++ = nVarIdx;
  578.     }
  579.   } // while
  580.   *out = 0;
  581.   if (outbuf)
  582.     return lstrcpyn(outbuf, ps_tmpbuf, NSIS_MAX_STRLEN);
  583.   return ps_tmpbuf;
  584. }
  585.  
  586. char * NSISCALL validate_filename(char *in) {
  587.   char *nono = "*?|<>/\":";
  588.   char *out;
  589.   char *out_save;
  590.   while (*in == ' ') in = CharNext(in);
  591.   if (in[0] == '\\' && in[1] == '\\' && in[2] == '?' && in[3] == '\\')
  592.   {
  593.     // at least four bytes
  594.     in += 4;
  595.   }
  596.   if (*in)
  597.   {
  598.     // at least two bytes
  599.     if (validpathspec(in)) in += 2;
  600.   }
  601.   out = out_save = in;
  602.   while (*in)
  603.   {
  604.     if ((unsigned char)*in > 31 && !*findchar(nono, *in))
  605.     {
  606.       mini_memcpy(out, in, CharNext(in) - in);
  607.       out = CharNext(out);
  608.     }
  609.     in = CharNext(in);
  610.   }
  611.   *out = 0;
  612.   do
  613.   {
  614.     out = CharPrev(out_save, out);
  615.     if (*out == ' ' || *out == '\\')
  616.       *out = 0;
  617.     else
  618.       break;
  619.   } while (out_save < out);
  620.   return out_save;
  621. }
  622.  
  623. #ifdef NSIS_CONFIG_LOG
  624. int log_dolog;
  625. char log_text[NSIS_MAX_STRLEN*4];
  626.  
  627. #ifndef NSIS_CONFIG_LOG_ODS
  628. void NSISCALL log_write(int close)
  629. {
  630.   static HANDLE fp=INVALID_HANDLE_VALUE;
  631.   if (close)
  632.   {
  633.     if (fp!=INVALID_HANDLE_VALUE)
  634.     {
  635.       CloseHandle(fp);
  636.     }
  637.     fp=INVALID_HANDLE_VALUE;
  638.     return;
  639.   }
  640.   if (log_dolog)
  641.   {
  642.     if (g_log_file[0] && fp==INVALID_HANDLE_VALUE)
  643.     {
  644.       fp = myOpenFile(g_log_file,GENERIC_WRITE,OPEN_ALWAYS);
  645.       if (fp!=INVALID_HANDLE_VALUE)
  646.         SetFilePointer(fp,0,NULL,FILE_END);
  647.     }
  648.     if (fp!=INVALID_HANDLE_VALUE)
  649.     {
  650.       DWORD d;
  651.       lstrcat(log_text,"\r\n");
  652.       WriteFile(fp,log_text,mystrlen(log_text),&d,NULL);
  653.     }
  654.   }
  655. }
  656. #endif//!NSIS_CONFIG_LOG_ODS
  657.  
  658. void log_printf(char *format, ...)
  659. {
  660.   va_list val;
  661.   va_start(val,format);
  662.   wvsprintf(log_text,format,val);
  663.   va_end(val);
  664. #ifdef NSIS_CONFIG_LOG_ODS
  665.   if (log_dolog)
  666.     OutputDebugString(log_text);
  667. #else
  668.   log_write(0);
  669. #endif
  670. }
  671. #endif//NSIS_CONFIG_LOG
  672.  
  673. WIN32_FIND_DATA * NSISCALL file_exists(char *buf)
  674. {
  675.   HANDLE h;
  676.   static WIN32_FIND_DATA fd;
  677.   // Avoid a "There is no disk in the drive" error box on empty removable drives
  678.   SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  679.   h = FindFirstFile(buf,&fd);
  680.   SetErrorMode(0);
  681.   if (h != INVALID_HANDLE_VALUE)
  682.   {
  683.     FindClose(h);
  684.     return &fd;
  685.   }
  686.   return NULL;
  687. }
  688.