📄 cmnfunc2.pas
字号:
function SkipPastConst(const S: String; const Start: Integer): Integer;
{ Returns the character index following the Inno Setup constant embedded
into the string S at index Start.
If the constant is not closed (missing a closing brace), it returns zero. }
var
L, BraceLevel, LastOpenBrace: Integer;
begin
Result := Start;
L := Length(S);
if Result < L then begin
Inc(Result);
if S[Result] = '{' then begin
Inc(Result);
Exit;
end
else begin
BraceLevel := 1;
LastOpenBrace := -1;
while Result <= L do begin
case S[Result] of
'{': begin
if LastOpenBrace <> Result-1 then begin
Inc(BraceLevel);
LastOpenBrace := Result;
end
else
{ Skip over '{{' when in an embedded constant }
Dec(BraceLevel);
end;
'}': begin
Dec(BraceLevel);
if BraceLevel = 0 then begin
Inc(Result);
Exit;
end;
end;
else
if S[Result] in ConstLeadBytes^ then
Inc(Result);
end;
Inc(Result);
end;
end;
end;
Result := 0;
end;
function ConvertConstPercentStr(var S: String): Boolean;
{ Same as ConvertPercentStr, but is designed to ignore embedded Inno Setup
constants. Any '%' characters between braces are not translated. Two
consecutive braces are ignored. }
var
I, C, E: Integer;
N: String;
begin
Result := True;
I := 1;
while I <= Length(S) do begin
case S[I] of
'{': begin
I := SkipPastConst(S, I);
if I = 0 then begin
Result := False;
Break;
end;
Dec(I); { ...since there's an Inc below }
end;
'%': begin
N := Copy(S, I, 3);
if Length(N) <> 3 then begin
Result := False;
Break;
end;
N[1] := '$';
Val(N, C, E);
if E <> 0 then begin
Result := False;
Break;
end;
{ delete the two numbers following '%', and replace '%' with the character }
Delete(S, I+1, 2);
S[I] := Chr(C);
end;
else
if S[I] in ConstLeadBytes^ then
Inc(I);
end;
Inc(I);
end;
end;
function ConstPos(const Ch: Char; const S: String): Integer;
{ Like the standard Pos function, but skips over any Inno Setup constants
embedded in S }
var
I, L: Integer;
begin
Result := 0;
I := 1;
L := Length(S);
while I <= L do begin
if S[I] = Ch then begin
Result := I;
Break;
end
else if S[I] = '{' then begin
I := SkipPastConst(S, I);
if I = 0 then
Break;
end
else begin
if S[I] in ConstLeadBytes^ then
Inc(I);
Inc(I);
end;
end;
end;
function GetShortName(const LongName: String): String;
{ Gets the short version of the specified long filename. If the file does not
exist, or some other error occurs, it returns LongName. }
var
Res: DWORD;
begin
SetLength(Result, MAX_PATH);
repeat
Res := GetShortPathName(PChar(LongName), PChar(Result), Length(Result));
if Res = 0 then begin
Result := LongName;
Break;
end;
until AdjustLength(Result, Res);
end;
function GetWinDir: String;
{ Returns fully qualified path of the Windows directory. Only includes a
trailing backslash if the Windows directory is the root directory. }
var
Buf: array[0..MAX_PATH-1] of Char;
begin
GetWindowsDirectory(Buf, SizeOf(Buf));
Result := StrPas(Buf);
end;
function GetSystemDir: String;
{ Returns fully qualified path of the Windows System directory. Only includes a
trailing backslash if the Windows System directory is the root directory. }
var
Buf: array[0..MAX_PATH-1] of Char;
begin
GetSystemDirectory(Buf, SizeOf(Buf));
Result := StrPas(Buf);
end;
function GetTempDir: String;
{ Returns fully qualified path of the temporary directory, with trailing
backslash. This does not use the Win32 function GetTempPath, due to platform
differences. }
label 1;
begin
Result := GetEnv('TMP');
if (Result <> '') and DirExists(Result) then
goto 1;
Result := GetEnv('TEMP');
if (Result <> '') and DirExists(Result) then
goto 1;
if Win32Platform = VER_PLATFORM_WIN32_NT then begin
{ Like Windows 2000's GetTempPath, return USERPROFILE when TMP and TEMP
are not set }
Result := GetEnv('USERPROFILE');
if (Result <> '') and DirExists(Result) then
goto 1;
end;
Result := GetWinDir;
1:Result := AddBackslash(PathExpand(Result));
end;
procedure StringChange(var S: String; const FromStr, ToStr: String);
{ Change all occurrences in S of FromStr to ToStr }
var
StartPos, I: Integer;
label 1;
begin
if FromStr = '' then Exit;
StartPos := 1;
1:for I := StartPos to Length(S)-Length(FromStr)+1 do begin
if Copy(S, I, Length(FromStr)) = FromStr then begin
Delete(S, I, Length(FromStr));
Insert(ToStr, S, I);
StartPos := I + Length(ToStr);
goto 1;
end;
end;
end;
function AdjustLength(var S: String; const Res: Cardinal): Boolean;
{ Returns True if successful. Returns False if buffer wasn't large enough,
and called AdjustLength to resize it. }
begin
Result := Integer(Res) < Length(S);
SetLength(S, Res);
end;
function UsingWinNT: Boolean;
{ Returns True if system is running any version of Windows NT. Never returns
True on Windows 95 or 3.1. }
begin
Result := Win32Platform = VER_PLATFORM_WIN32_NT;
end;
function InternalRegQueryStringValue(H: HKEY; Name: PChar; var ResultStr: String;
Type1, Type2: DWORD): Boolean;
var
Typ, Size: DWORD;
S: String;
ErrorCode: Longint;
label 1;
begin
Result := False;
1:Size := 0;
if (RegQueryValueEx(H, Name, nil, @Typ, nil, @Size) = ERROR_SUCCESS) and
((Typ = Type1) or (Typ = Type2)) then begin
if Size = 0 then begin
{ It's an empty string with no null terminator.
(Must handle those here since we can't pass a nil lpData pointer on
the second RegQueryValueEx call.) }
ResultStr := '';
Result := True;
end
else begin
SetString(S, nil, Size);
ErrorCode := RegQueryValueEx(H, Name, nil, @Typ, @S[1], @Size);
if ErrorCode = ERROR_MORE_DATA then begin
{ The data must've increased in size since the first RegQueryValueEx
call. Start over. }
goto 1;
end;
if (ErrorCode = ERROR_SUCCESS) and
((Typ = Type1) or (Typ = Type2)) then begin
{ Remove any null terminators from the end and trim the string to the
returned Size.
Note: We *should* find 1 null terminator, but it's possible for
there to be more or none if the value was written that way. }
while (Size <> 0) and (S[Size] = #0) do
Dec(Size);
{ In a REG_MULTI_SZ value, each individual string is null-terminated,
so add 1 null (back) to the end, unless there are no strings (Size=0) }
if (Typ = REG_MULTI_SZ) and (Size <> 0) then
Inc(Size);
SetLength(S, Size);
if (Typ = REG_MULTI_SZ) and (Size <> 0) then
S[Size] := #0;
ResultStr := S;
Result := True;
end;
end;
end;
end;
function RegQueryStringValue(H: HKEY; Name: PChar; var ResultStr: String): Boolean;
{ Queries the specified REG_SZ or REG_EXPAND_SZ registry key/value, and returns
the value in ResultStr. Returns True if successful. When False is returned,
ResultStr is unmodified. }
begin
Result := InternalRegQueryStringValue(H, Name, ResultStr, REG_SZ,
REG_EXPAND_SZ);
end;
function RegQueryMultiStringValue(H: HKEY; Name: PChar; var ResultStr: String): Boolean;
{ Queries the specified REG_MULTI_SZ registry key/value, and returns the value
in ResultStr. Returns True if successful. When False is returned, ResultStr
is unmodified. }
begin
Result := InternalRegQueryStringValue(H, Name, ResultStr, REG_MULTI_SZ,
REG_MULTI_SZ);
end;
function RegValueExists(H: HKEY; Name: PChar): Boolean;
{ Returns True if the specified value exists. Requires KEY_QUERY_VALUE access
to the key. }
var
I: Integer;
EnumName: array[0..1] of Char;
Count: DWORD;
ErrorCode: Longint;
begin
Result := RegQueryValueEx(H, Name, nil, nil, nil, nil) = ERROR_SUCCESS;
if Result and ((Name = nil) or (Name^ = #0)) and
(Win32Platform <> VER_PLATFORM_WIN32_NT) then begin
{ On Win9x/Me a default value always exists according to RegQueryValueEx,
so it must use RegEnumValue instead to check if a default value
really exists }
Result := False;
I := 0;
while True do begin
Count := SizeOf(EnumName);
ErrorCode := RegEnumValue(H, I, EnumName, Count, nil, nil, nil, nil);
if (ErrorCode <> ERROR_SUCCESS) and (ErrorCode <> ERROR_MORE_DATA) then
Break;
{ is it the default value? }
if (ErrorCode = ERROR_SUCCESS) and (EnumName[0] = #0) then begin
Result := True;
Break;
end;
Inc(I);
end;
end;
end;
function RegDeleteKeyIncludingSubkeys(const Key: HKEY; const Name: PChar): Longint;
{ Deletes the specified key and all subkeys.
Returns ERROR_SUCCESS if the key was successful deleted. }
var
H: HKEY;
KeyName: String;
KeyNameCount, MaxCount: DWORD;
FT: TFileTime;
I: Integer;
begin
if Win32Platform = VER_PLATFORM_WIN32_NT then begin
if RegOpenKeyEx(Key, Name, 0, KEY_ENUMERATE_SUB_KEYS or KEY_QUERY_VALUE, H) = ERROR_SUCCESS then begin
if RegQueryInfoKey(H, nil, nil, nil, nil, @MaxCount, nil, nil, nil, nil,
nil, nil) = ERROR_SUCCESS then begin
if MaxCount < 1 then MaxCount := 1;
SetLength(KeyName, MaxCount);
I := 0;
while True do begin
KeyNameCount := MaxCount+1;
if RegEnumKeyEx(H, I, PChar(KeyName), KeyNameCount, nil, nil, nil, @FT) <> ERROR_SUCCESS then
Break;
if RegDeleteKeyIncludingSubkeys(H, PChar(KeyName)) <> ERROR_SUCCESS then
Inc(I);
end;
end;
RegCloseKey(H);
end;
end;
Result := RegDeleteKey(Key, Name);
end;
function RegDeleteKeyIfEmpty(const RootKey: HKEY; const SubkeyName: PChar): Longint;
{ Deletes the specified subkey if it has no subkeys or values.
Returns ERROR_SUCCESS if the key was successful deleted, ERROR_DIR_NOT_EMPTY
if it was not deleted because it contained subkeys or values, or possibly
some other Win32 error code. }
var
K: HKEY;
NumSubkeys, NumValues: DWORD;
begin
Result := RegOpenKeyEx(RootKey, SubkeyName, 0, KEY_QUERY_VALUE, K);
if Result <> ERROR_SUCCESS then
Exit;
Result := RegQueryInfoKey(K, nil, nil, nil, @NumSubkeys, nil, nil,
@NumValues, nil, nil, nil, nil);
RegCloseKey(K);
if Result <> ERROR_SUCCESS then
Exit;
if (NumSubkeys = 0) and (NumValues = 0) then
Result := RegDeleteKey(RootKey, SubkeyName)
else
Result := ERROR_DIR_NOT_EMPTY;
end;
function GetShellFolderPath(const FolderID: Integer): String;
var
pidl: PItemIDList;
Buffer: array[0..MAX_PATH-1] of Char;
Malloc: IMalloc;
begin
Result := '';
if FAILED(SHGetMalloc(Malloc)) then
Malloc := nil;
if SUCCEEDED(SHGetSpecialFolderLocation(0, FolderID, pidl)) then begin
if SHGetPathFromIDList(pidl, Buffer) then
Result := Buffer;
if Assigned(Malloc) then
Malloc.Free(pidl);
end;
end;
function GetPathFromRegistry(const Name: PChar): String;
var
H: HKEY;
begin
if RegOpenKeyEx(HKEY_LOCAL_MACHINE, NEWREGSTR_PATH_SETUP, 0,
KEY_QUERY_VALUE, H) = ERROR_SUCCESS then begin
if not RegQueryStringValue(H, Name, Result) then
Result := '';
RegCloseKey(H);
end
else
Result := '';
end;
function GetProgramFilesPath: String;
{ Gets path of Program Files.
Returns blank string if not found in registry. }
begin
Result := GetPathFromRegistry('ProgramFilesDir');
end;
function GetCommonFilesPath: String;
{ Gets path of Common Files.
Returns blank string if not found in registry. }
begin
Result := GetPathFromRegistry('CommonFilesDir');
end;
function IsMemberOfGroup(const DomainAliasRid: DWORD): Boolean;
{ Returns True if the logged-on user is a member of the specified local
group. Always returns True on Windows 9x/Me. }
const
SECURITY_NT_AUTHORITY: TSIDIdentifierAuthority =
(Value: (0, 0, 0, 0, 0, 5));
SECURITY_BUILTIN_DOMAIN_RID = $00000020;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -