Subversion Repositories delphiutils

Rev

Rev 68 | Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. unit UD2_Utils;
  2.  
  3. interface
  4.  
  5. {$IF CompilerVersion >= 25.0}
  6. {$LEGACYIFEND ON}
  7. {$IFEND}
  8.  
  9. {$INCLUDE 'UserDetect2.inc'}
  10.  
  11. uses
  12.   Windows, SysUtils, Dialogs, ShellAPI;
  13.  
  14. type
  15.   TArrayOfString = array of String;
  16.  
  17.   TIconFileIdx = record
  18.     FileName: string;
  19.     IconIndex: integer;
  20.   end;
  21.  
  22. const
  23.   // Prefixes for UD2_RunCmd()
  24.   UD2_RUN_IN_OWN_DIRECTORY_PREFIX = '$RIOD$';
  25.  
  26. function SplitString(const aSeparator, aString: String; aMax: Integer = 0): TArrayOfString;
  27. function BetterInterpreteBool(str: String): boolean;
  28. function GetOwnCmdName: string;
  29. function ExpandEnvStr(const szInput: string): string;
  30. procedure UD2_RunCMD(cmdLine: string; WindowMode: integer);
  31. function SplitIconString(IconString: string): TIconFileIdx;
  32. // function GetHTML(AUrl: string): string;
  33. procedure VTS_CheckUpdates(VTSID, CurVer: string);
  34.  
  35. implementation
  36.  
  37. uses
  38.   WinInet, Forms;
  39.  
  40. function SplitString(const aSeparator, aString: String; aMax: Integer = 0): TArrayOfString;
  41. // http://stackoverflow.com/a/2626991/3544341
  42. var
  43.   i, strt, cnt: Integer;
  44.   sepLen: Integer;
  45.  
  46.   procedure AddString(aEnd: Integer = -1);
  47.   var
  48.     endPos: Integer;
  49.   begin
  50.     if (aEnd = -1) then
  51.       endPos := i
  52.     else
  53.       endPos := aEnd + 1;
  54.  
  55.     if (strt < endPos) then
  56.       result[cnt] := Copy(aString, strt, endPos - strt)
  57.     else
  58.       result[cnt] := '';
  59.  
  60.     Inc(cnt);
  61.   end;
  62.  
  63. begin
  64.   if (aString = '') or (aMax < 0) then
  65.   begin
  66.     SetLength(result, 0);
  67.     EXIT;
  68.   end;
  69.  
  70.   if (aSeparator = '') then
  71.   begin
  72.     SetLength(result, 1);
  73.     result[0] := aString;
  74.     EXIT;
  75.   end;
  76.  
  77.   sepLen := Length(aSeparator);
  78.   SetLength(result, (Length(aString) div sepLen) + 1);
  79.  
  80.   i     := 1;
  81.   strt  := i;
  82.   cnt   := 0;
  83.   while (i <= (Length(aString)- sepLen + 1)) do
  84.   begin
  85.     if (aString[i] = aSeparator[1]) then
  86.       if (Copy(aString, i, sepLen) = aSeparator) then
  87.       begin
  88.         AddString;
  89.  
  90.         if (cnt = aMax) then
  91.         begin
  92.           SetLength(result, cnt);
  93.           EXIT;
  94.         end;
  95.  
  96.         Inc(i, sepLen - 1);
  97.         strt := i + 1;
  98.       end;
  99.  
  100.     Inc(i);
  101.   end;
  102.  
  103.   AddString(Length(aString));
  104.  
  105.   SetLength(result, cnt);
  106. end;
  107.  
  108. function BetterInterpreteBool(str: String): boolean;
  109. resourcestring
  110.   LNG_CANNOT_INTERPRETE_BOOL = 'Cannot determinate the boolean value of "%s"';
  111. begin
  112.   str := LowerCase(str);
  113.   if (str = 'yes') or (str = 'true') or (str = '1') then
  114.     result := true
  115.   else if (str = 'no') or (str = 'false') or (str = '0') then
  116.     result := false
  117.   else
  118.     raise EConvertError.CreateFmt(LNG_CANNOT_INTERPRETE_BOOL, [str]);
  119. end;
  120.  
  121. function GetOwnCmdName: string;
  122. begin
  123.   result := ParamStr(0);
  124.   result := ExtractFileName(result);
  125.   result := ChangeFileExt(result, '');
  126.   result := UpperCase(result);
  127. end;
  128.  
  129. function ExpandEnvStr(const szInput: string): string;
  130. // http://stackoverflow.com/a/2833147/3544341
  131. const
  132.   MAXSIZE = 32768;
  133. begin
  134.   SetLength(Result, MAXSIZE);
  135.   SetLength(Result, ExpandEnvironmentStrings(pchar(szInput),
  136.     @Result[1],length(Result)));
  137. end;
  138.  
  139. procedure CheckLastOSCall(AThrowException: boolean);
  140. resourcestring
  141.   LNG_UNKNOWN_ERROR = 'Operating system error %d';
  142. var
  143.   LastError: Cardinal;
  144.   sError: string;
  145. begin
  146.   LastError := GetLastError;
  147.   if LastError <> 0 then
  148.   begin
  149.     if AThrowException then
  150.     begin
  151.       RaiseLastOSError;
  152.     end
  153.     else
  154.     begin
  155.       sError := SysErrorMessage(LastError);
  156.  
  157.       // Some errors have no error message, e.g. error 193 (BAD_EXE_FORMAT) in the German version of Windows 10
  158.       if sError = '' then sError := Format(LNG_UNKNOWN_ERROR, [LastError]);
  159.  
  160.       MessageDlg(sError, mtError, [mbOK], 0);
  161.     end;
  162.   end;
  163. end;
  164.  
  165. function SplitIconString(IconString: string): TIconFileIdx;
  166. var
  167.   p: integer;
  168. begin
  169.   p := Pos(',', IconString);
  170.  
  171.   if p = 0 then
  172.   begin
  173.     result.FileName := IconString;
  174.     result.IconIndex := 0;
  175.   end
  176.   else
  177.   begin
  178.     result.FileName  := ExpandEnvStr(copy(IconString, 0, p-1));
  179.     result.IconIndex := StrToInt(Copy(IconString, p+1, Length(IconString)-p));
  180.   end;
  181. end;
  182.  
  183. procedure UD2_RunCMD(cmdLine: string; WindowMode: integer);
  184. // Discussion: http://stackoverflow.com/questions/32802679/acceptable-replacement-for-winexec/32804669#32804669
  185. // Version 1: http://pastebin.com/xQjDmyVe
  186. // --> CreateProcess + ShellExecuteEx
  187. // --> Problem: Run-In-Same-Directory functionality is not possible
  188. //              (requires manual command and argument separation)
  189. // Version 2: http://pastebin.com/YpUmF5rd
  190. // --> Splits command and arguments manually, and uses ShellExecute
  191. // --> Problem: error handling wrong
  192. // --> Problem: Run-In-Same-Directory functionality is not implemented
  193. // Current version:
  194. // --> Splits command and arguments manually, and uses ShellExecute
  195. // --> Run-In-Same-Directory functionality is implemented
  196. resourcestring
  197.   LNG_INVALID_SYNTAX = 'The command line has an invalid syntax';
  198. var
  199.   cmdFile, cmdArgs, cmdDir: string;
  200.   p: integer;
  201.   sei: TShellExecuteInfo;
  202. begin
  203.   // We need a function which does following:
  204.   // 1. Replace the Environment strings, e.g. %SystemRoot%
  205.   // 2. Runs EXE files with parameters (e.g. "cmd.exe /?")
  206.   // 3. Runs EXE files without path (e.g. "calc.exe")
  207.   // 4. Runs EXE files without extension (e.g. "calc")
  208.   // 5. Runs non-EXE files (e.g. "Letter.doc")
  209.   // 6. Commands with white spaces (e.g. "C:\Program Files\xyz.exe") must be enclosed in quotes.
  210.  
  211.   cmdLine := ExpandEnvStr(cmdLine);
  212.  
  213.   // Split command line from argument list
  214.   if Copy(cmdLine, 1, 1) = '"' then
  215.   begin
  216.     cmdLine := Copy(cmdLine, 2, Length(cmdLine)-1);
  217.     p := Pos('"', cmdLine);
  218.     if p = 0 then
  219.     begin
  220.       // No matching quotes
  221.       // CreateProcess() handles the whole command line as single file name  ("abc -> "abc")
  222.       // ShellExecuteEx() does not accept the command line
  223.       MessageDlg(LNG_INVALID_SYNTAX, mtError, [mbOK], 0);
  224.       Exit;
  225.     end;
  226.     cmdFile := Copy(cmdLine, 1, p-1);
  227.     cmdArgs := Copy(cmdLine, p+2, Length(cmdLine)-p-1);
  228.   end
  229.   else
  230.   begin
  231.     p := Pos(' ', cmdLine);
  232.     if p = 0 then
  233.     begin
  234.       cmdFile := cmdLine;
  235.       cmdArgs := '';
  236.     end
  237.     else
  238.     begin
  239.       cmdFile := Copy(cmdLine, 1, p-1);
  240.       cmdArgs := Copy(cmdLine, p+1, Length(cmdLine)-p);
  241.     end;
  242.   end;
  243.  
  244.   if Copy(cmdLine, 1, Length(UD2_RUN_IN_OWN_DIRECTORY_PREFIX)) = UD2_RUN_IN_OWN_DIRECTORY_PREFIX then
  245.   begin
  246.     cmdLine := Copy(cmdLine, 1+Length(UD2_RUN_IN_OWN_DIRECTORY_PREFIX), Length(cmdLine)-Length(UD2_RUN_IN_OWN_DIRECTORY_PREFIX));
  247.  
  248.     cmdFile := ExtractFileName(cmdLine);
  249.     cmdDir  := ExtractFilePath(cmdLine);
  250.   end
  251.   else
  252.   begin
  253.     cmdFile := cmdLine;
  254.     cmdDir := '';
  255.   end;
  256.  
  257.   ZeroMemory(@sei, SizeOf(sei));
  258.   sei.cbSize       := SizeOf(sei);
  259.   sei.lpFile       := PChar(cmdFile);
  260.   {$IFNDEF PREFER_SHELLEXECUTEEX_MESSAGES}
  261.   sei.fMask        := SEE_MASK_FLAG_NO_UI;
  262.   {$ENDIF}
  263.   if cmdArgs <> '' then sei.lpParameters := PChar(cmdArgs);
  264.   if cmdDir  <> '' then sei.lpDirectory  := PChar(cmdDir);
  265.   sei.nShow        := WindowMode;
  266.   if ShellExecuteEx(@sei) then Exit;
  267.   {$IFNDEF PREFER_SHELLEXECUTEEX_MESSAGES}
  268.   CheckLastOSCall(false);
  269.   {$ENDIF}
  270. end;
  271.  
  272. function GetHTML(AUrl: string): string;
  273. // http://www.delphipraxis.net/post43515.html
  274. var
  275.   databuffer : array[0..4095] of char;
  276.   ResStr : string;
  277.   hSession, hfile: hInternet;
  278.   dwindex,dwcodelen,dwread,dwNumber: cardinal;
  279.   dwcode : array[1..20] of char;
  280.   res    : pchar;
  281.   Str    : pchar;
  282. begin
  283.   ResStr:='';
  284.   if system.pos('http://',lowercase(AUrl))=0 then
  285.      AUrl:='http://'+AUrl;
  286.  
  287.   // Hinzugefügt
  288.   Application.ProcessMessages;
  289.  
  290.   hSession:=InternetOpen('InetURL:/1.0',
  291.                          INTERNET_OPEN_TYPE_PRECONFIG,
  292.                          nil,
  293.                          nil,
  294.                          0);
  295.   if assigned(hsession) then
  296.   begin
  297.     // Hinzugefügt
  298.     application.ProcessMessages;
  299.  
  300.     hfile:=InternetOpenUrl(
  301.            hsession,
  302.            pchar(AUrl),
  303.            nil,
  304.            0,
  305.            INTERNET_FLAG_RELOAD,
  306.            0);
  307.     dwIndex  := 0;
  308.     dwCodeLen := 10;
  309.  
  310.     // Hinzugefügt
  311.     application.ProcessMessages;
  312.  
  313.     HttpQueryInfo(hfile,
  314.                   HTTP_QUERY_STATUS_CODE,
  315.                   @dwcode,
  316.                   dwcodeLen,
  317.                   dwIndex);
  318.     res := pchar(@dwcode);
  319.     dwNumber := sizeof(databuffer)-1;
  320.     if (res ='200') or (res ='302') then
  321.     begin
  322.       while (InternetReadfile(hfile,
  323.                               @databuffer,
  324.                               dwNumber,
  325.                               DwRead)) do
  326.       begin
  327.  
  328.         // Hinzugefügt
  329.         application.ProcessMessages;
  330.  
  331.         if dwRead =0 then
  332.           break;
  333.         databuffer[dwread]:=#0;
  334.         Str := pchar(@databuffer);
  335.         resStr := resStr + Str;
  336.       end;
  337.     end
  338.     else
  339.       ResStr := 'Status:'+res;
  340.     if assigned(hfile) then
  341.       InternetCloseHandle(hfile);
  342.   end;
  343.  
  344.   // Hinzugefügt
  345.   Application.ProcessMessages;
  346.  
  347.   InternetCloseHandle(hsession);
  348.   Result := resStr;
  349. end;
  350.  
  351. procedure VTS_CheckUpdates(VTSID, CurVer: string);
  352. resourcestring
  353.   (*
  354.   LNG_DOWNLOAD_ERR = 'Ein Fehler ist aufgetreten. Wahrscheinlich ist keine Internetverbindung aufgebaut, oder der der ViaThinkSoft-Server temporär offline.';
  355.   LNG_NEW_VERSION = 'Eine neue Programmversion ist vorhanden. Möchten Sie diese jetzt herunterladen?';
  356.   LNG_NO_UPDATE = 'Es ist keine neue Programmversion vorhanden.';
  357.   *)
  358.   LNG_DOWNLOAD_ERR = 'An error occurred while searching for updates. Please check your internet connection and firewall.';
  359.   LNG_NEW_VERSION = 'A new version is available. Do you want to download it now?';
  360.   LNG_NO_UPDATE = 'You already have the newest program version.';
  361. var
  362.   temp: string;
  363. begin
  364.   temp := GetHTML('http://www.viathinksoft.de/update/?id='+VTSID);
  365.   if Copy(temp, 0, 7) = 'Status:' then
  366.   begin
  367.     MessageDlg(LNG_DOWNLOAD_ERR, mtError, [mbOK], 0);
  368.   end
  369.   else
  370.   begin
  371.     if GetHTML('http://www.viathinksoft.de/update/?id='+VTSID) <> CurVer then
  372.     begin
  373.       if MessageDlg(LNG_NEW_VERSION, mtConfirmation, mbYesNoCancel, 0) = ID_YES then
  374.       begin
  375.         shellexecute(application.handle, 'open', pchar('http://www.viathinksoft.de/update/?id=@spacemission'), '', '', sw_normal);
  376.       end;
  377.     end
  378.     else
  379.     begin
  380.       MessageDlg(LNG_NO_UPDATE, mtInformation, [mbOk], 0);
  381.     end;
  382.   end;
  383. end;
  384.  
  385. end.
  386.