2
0

CompFileAssoc.pas 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. unit CompFileAssoc;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2020 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. Compiler IDE's functions for registering/unregistering the .iss file association
  8. }
  9. interface
  10. function RegisterISSFileAssociation(const AllowInteractive: Boolean; var AllUsers: Boolean): Boolean;
  11. procedure UnregisterISSFileAssociation;
  12. implementation
  13. uses
  14. Windows, SysUtils, PathFunc, ShlObj, CmnFunc, CmnFunc2;
  15. function GetRootkey: HKEY;
  16. begin
  17. if IsAdminLoggedOn then
  18. Result := HKEY_LOCAL_MACHINE
  19. else
  20. Result := HKEY_CURRENT_USER;
  21. end;
  22. procedure UnregisterISSFileAssociationDo(const Rootkey: HKEY; const ChangeNotify: Boolean); forward;
  23. function RegisterISSFileAssociation(const AllowInteractive: Boolean; var AllUsers: Boolean): Boolean;
  24. procedure SetKeyValue(const Rootkey: HKEY; const Subkey, ValueName: PChar; const Data: String);
  25. procedure Check(const Res: Longint);
  26. begin
  27. if Res <> ERROR_SUCCESS then
  28. raise Exception.CreateFmt('Error creating file association:'#13#10'%d - %s',
  29. [Res, Win32ErrorString(Res)]);
  30. end;
  31. var
  32. K: HKEY;
  33. Disp: DWORD;
  34. begin
  35. Check(RegCreateKeyExView(rvDefault, Rootkey, Subkey, 0, nil, 0, KEY_SET_VALUE,
  36. nil, K, @Disp));
  37. try
  38. Check(RegSetValueEx(K, ValueName, 0, REG_SZ, PChar(Data), (Length(Data)+1)*SizeOf(Data[1])));
  39. finally
  40. RegCloseKey(K);
  41. end;
  42. end;
  43. var
  44. SelfName: String;
  45. Rootkey: HKEY;
  46. begin
  47. Rootkey := GetRootkey;
  48. AllUsers := Rootkey = HKEY_LOCAL_MACHINE;
  49. Result := AllUsers or not AllowInteractive or
  50. (MsgBox('Unable to associate for all users without administrative privileges. Do you want to associate only for yourself instead?',
  51. 'Associate', mbConfirmation, MB_YESNO) = IDYES);
  52. if not Result then
  53. Exit;
  54. SelfName := NewParamStr(0);
  55. SetKeyValue(Rootkey, 'Software\Classes\.iss', nil, 'InnoSetupScriptFile');
  56. SetKeyValue(Rootkey, 'Software\Classes\.iss', 'Content Type', 'text/plain');
  57. SetKeyValue(Rootkey, 'Software\Classes\InnoSetupScriptFile', nil, 'Inno Setup Script');
  58. SetKeyValue(Rootkey, 'Software\Classes\InnoSetupScriptFile\DefaultIcon', nil, SelfName + ',1');
  59. SetKeyValue(Rootkey, 'Software\Classes\InnoSetupScriptFile\shell\open\command', nil,
  60. '"' + SelfName + '" "%1"');
  61. SetKeyValue(Rootkey, 'Software\Classes\InnoSetupScriptFile\shell\OpenWithInnoSetup', nil,
  62. 'Open with &Inno Setup');
  63. SetKeyValue(Rootkey, 'Software\Classes\InnoSetupScriptFile\shell\OpenWithInnoSetup\command', nil,
  64. '"' + SelfName + '" "%1"');
  65. SetKeyValue(Rootkey, 'Software\Classes\InnoSetupScriptFile\shell\Compile', nil, 'Compi&le');
  66. SetKeyValue(Rootkey, 'Software\Classes\InnoSetupScriptFile\shell\Compile\command', nil,
  67. '"' + SelfName + '" /cc "%1"');
  68. SetKeyValue(Rootkey, PChar('Software\Classes\Applications\' + PathExtractName(SelfName) + '\SupportedTypes'), '.iss', '');
  69. { If we just associated for all users, remove our existing association for the current user if it exists. }
  70. if AllUsers then
  71. UnregisterISSFileAssociationDo(HKEY_CURRENT_USER, False);
  72. SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil);
  73. end;
  74. procedure UnregisterISSFileAssociationDo(const Rootkey: HKEY; const ChangeNotify: Boolean);
  75. function KeyValueEquals(const Rootkey: HKEY; const Subkey: PChar; const Data: String): Boolean;
  76. var
  77. K: HKEY;
  78. S: String;
  79. begin
  80. Result := False;
  81. if RegOpenKeyExView(rvDefault, Rootkey, Subkey, 0, KEY_QUERY_VALUE, K) = ERROR_SUCCESS then begin
  82. if RegQueryStringValue(K, nil, S) and (PathCompare(Data, S) = 0) then
  83. Result := True;
  84. RegCloseKey(K);
  85. end;
  86. end;
  87. function KeyExists(const Rootkey: HKEY; const Subkey: PChar): Boolean;
  88. var
  89. K: HKEY;
  90. begin
  91. Result := (RegOpenKeyExView(rvDefault, Rootkey, Subkey, 0, KEY_QUERY_VALUE,
  92. K) = ERROR_SUCCESS);
  93. if Result then
  94. RegCloseKey(K);
  95. end;
  96. function GetKeyNumSubkeysValues(const Rootkey: HKEY; const Subkey: PChar;
  97. var NumSubkeys, NumValues: DWORD): Boolean;
  98. var
  99. K: HKEY;
  100. begin
  101. Result := False;
  102. if RegOpenKeyExView(rvDefault, Rootkey, Subkey, 0, KEY_QUERY_VALUE, K) = ERROR_SUCCESS then begin
  103. Result := RegQueryInfoKey(K, nil, nil, nil, @NumSubkeys, nil, nil,
  104. @NumValues, nil, nil, nil, nil) = ERROR_SUCCESS;
  105. RegCloseKey(K);
  106. end;
  107. end;
  108. procedure DeleteValue(const Rootkey: HKEY; const Subkey, ValueName: PChar);
  109. var
  110. K: HKEY;
  111. begin
  112. if RegOpenKeyExView(rvDefault, Rootkey, Subkey, 0, KEY_SET_VALUE, K) = ERROR_SUCCESS then begin
  113. RegDeleteValue(K, ValueName);
  114. RegCloseKey(K);
  115. end;
  116. end;
  117. var
  118. SelfName: String;
  119. NumSubkeys, NumValues: DWORD;
  120. begin
  121. if not KeyExists(Rootkey, 'Software\Classes\InnoSetupScriptFile') and not KeyExists(Rootkey, 'Software\Classes\.iss') then
  122. Exit;
  123. SelfName := NewParamStr(0);
  124. { NOTE: We can't just blindly delete the entire .iss & InnoSetupScriptFile
  125. keys, otherwise we'd remove the association even if we weren't the one who
  126. registered it in the first place. }
  127. { Clean up 'InnoSetupScriptFile' }
  128. if KeyValueEquals(Rootkey, 'Software\Classes\InnoSetupScriptFile\DefaultIcon', SelfName + ',1') then
  129. RegDeleteKeyIncludingSubkeys(rvDefault, Rootkey, 'Software\Classes\InnoSetupScriptFile\DefaultIcon');
  130. if KeyValueEquals(Rootkey, 'Software\Classes\InnoSetupScriptFile\shell\open\command', '"' + SelfName + '" "%1"') then
  131. RegDeleteKeyIncludingSubkeys(rvDefault, Rootkey, 'Software\Classes\InnoSetupScriptFile\shell\open');
  132. if KeyValueEquals(Rootkey, 'Software\Classes\InnoSetupScriptFile\shell\OpenWithInnoSetup\command', '"' + SelfName + '" "%1"') then
  133. RegDeleteKeyIncludingSubkeys(rvDefault, Rootkey, 'Software\Classes\InnoSetupScriptFile\shell\OpenWithInnoSetup');
  134. if KeyValueEquals(Rootkey, 'Software\Classes\InnoSetupScriptFile\shell\Compile\command', '"' + SelfName + '" /cc "%1"') then
  135. RegDeleteKeyIncludingSubkeys(rvDefault, Rootkey, 'Software\Classes\InnoSetupScriptFile\shell\Compile');
  136. RegDeleteKeyIfEmpty(rvDefault, Rootkey, 'Software\Classes\InnoSetupScriptFile\shell');
  137. if KeyValueEquals(Rootkey, 'Software\Classes\InnoSetupScriptFile', 'Inno Setup Script') and
  138. GetKeyNumSubkeysValues(Rootkey, 'Software\Classes\InnoSetupScriptFile', NumSubkeys, NumValues) and
  139. (NumSubkeys = 0) and (NumValues <= 1) then
  140. RegDeleteKey(Rootkey, 'Software\Classes\InnoSetupScriptFile');
  141. { Clean up '.iss' }
  142. if not KeyExists(Rootkey, 'Software\Classes\InnoSetupScriptFile') and
  143. KeyValueEquals(Rootkey, 'Software\Classes\.iss', 'InnoSetupScriptFile') then begin
  144. DeleteValue(Rootkey, 'Software\Classes\.iss', nil);
  145. DeleteValue(Rootkey, 'Software\Classes\.iss', 'Content Type');
  146. end;
  147. RegDeleteKeyIfEmpty(rvDefault, RootKey, 'Software\Classes\.iss');
  148. if ChangeNotify then
  149. SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil);
  150. end;
  151. procedure UnregisterISSFileAssociation;
  152. begin
  153. UnregisterISSFileAssociationDo(GetRootkey, True);
  154. end;
  155. end.