SHChangeNotify doesn't update URL=change my .url shortcut file
I have a simple Delphi application that creates desktop shortcuts for URLs.it.url
In the user's desktop foldercreate a file with File extensionA two-line text file:
[InternetShortcut]
URL=http://127.0.0.1/admin
This works great.When I need to update a file with a new URL, I overwrite the old one.But Windows doesn't recognize the change until I restart explorer or reboot.So ISHChangeNotify()
after overwriting filesunderstand and called it:
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH or SHCNF_FLUSH, PChar(Path), nil);
but it has no effect:
- I tried any
SHCNF_FLUSH
flag; - also
SHCNF_FLUSHNOWAIT
signs make no difference. - I also tried washing out the file first, then using
SHCNE_DELETE
event, then recreate the file.This doesn't work either, it just keeps using the old URL.
How to force explorer to reload URLs from archives without restarting?
uj5u.com enthusiastic netizens replied:
While the contents of the file can be treated like any INI file, I haven't found a straightforward way to control its operation:
- When creating an archive, its contents read as expected: system default
URL=
's protocolapplicationis activated (iehttp
it's most likely an internet browser). - Modifying files per file system has no effect-MSIE itself maintains cache or COM magic.
This can be done indirectly by:
- Clears the existing content of the file.Why? because the following steps will only
URL=
AgainAdd a valuesthe same INI section, but the first section'sURL=
value is still the one that is considered. - Access each COM profile and change its properties.Sadly, this writes more stuff in the archive-in my case the result/archive was:
However, it "works" as follows: changes (say: different URLs) are recognized.Put it all together, my following code for Delphi 7 on Windows 7 should work for you too-just call the function:
uses
ShlObj, ActiveX, ComObj;
const
SID_IUniformResourceLocatorA='{FBF23B80-E3F0-101B-8488-00AA003E56F8}';
SID_IUniformResourceLocatorW='{CABB0DA0-DA57-11CF-9974-0020AFD79762}';
SID_InternetShortcut='{FBF23B40-E3F0-101B-8488-00AA003E56F8}';
type
PUrlInvokeCommandInfoA=^TUrlInvokeCommandInfoA;
TUrlInvokeCommandInfoA=record
dwcbSize,
dwFlags: DWORD; //Bit field of IURL_INVOKECOMMAND_FLAGS
hwndParent: HWND; //Parent window.Valid only if IURL_INVOKECOMMAND_FL_ALLOW_UI is set.
pcszVerb: LPCSTR; //Verb to invoke.Ignored if IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB is set.
end;
PUrlInvokeCommandInfoW=^TUrlInvokeCommandInfoW;
TUrlInvokeCommandInfoW=record
dwcbSize,
dwFlags: DWORD;
hwndParent: HWND;
pcszVerb: LPCWSTR;
end;
IUniformResourceLocatorA=interface(IUnknown)
[SID_IUniformResourceLocatorA]
function SetURL(pcszURL: LPCSTR; dwInFlags: DWORD): HRESULT; stdcall ;
function GetURL(ppszURL: LPSTR): HRESULT; stdcall;
function InvokeCommand(purlici: PUrlInvokeCommandInfoA): HRESULT; stdcall;
end;
IUniformResourceLocatorW=interface(IUnknown)
[SID_IUniformResourceLocatorW]
function SetURL(pcszURL: LPCWSTR; dwInFlags: DWORD): HRESULT; stdcall ;
function GetURL(ppszURL: LPWSTR): HRESULT; stdcall;
function InvokeCommand(purlici: PUrlInvokeCommandInfoW): HRESULT; stdcall;
end;
function SetURL(sFile, sUrl: Widestring): Integer;
const
CLSID_InternetShortCut: TGUID=SID_InternetShortcut;
var
oUrl: IUniformResourceLocatorW;
oFile: IPersistFile;
hFile: THandle;
begin
//First, the existing file's content should be emptied
hFile:=CreateFileW(PWideChar(sFile), GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0) ;
if hFile=INVALID_HANDLE_VALUE then begin
result:=1; //File might not exist, sharing violation, etc.
exit;
end;
//Initial file pointer is at position 0
if not SetEndOfFile(hFile) then begin
result:=2; //Missing permissions, etc.
CloseHandle(hFile);
exit;
end;
//Gracefully end accessing the file
if not CloseHandle(hFile) then begin
result:=3; //File system crashed, etc.
exit;
end;
//Using COM to access properties
result:=0;
try
oUrl:=CreateComObject(CLSID_InternetShortCut) as IUniformResourceLocatorW;
except
result:=4; //CLSID unsupported, COM not available, etc.
end;
if result<> 0 then exit;
//Opening the file again
oFile:=oUrl as IPersistFile;
if oFile.Load(PWideChar(sFile), STGM_READWRITE)<> S_OK then begin
result:=5; //Sharing violations, access permissions, etc.
exit;
end;
//Set the property as per interface-only saving the file is not enough
if oUrl.SetURL(PWideChar(sUrl), 0)<> S_OK then begin
result:=6;
exit;
end;
//Storing the file's new content-setting only the property is not enough
if oFile.Save(PWideChar(sFile), TRUE)<> S_OK then begin
result:=7;
exit;
end;
//Success!
result:=0;
end;
According to my desktop firewall, the executor modifies explorer.exe
onMemoryIPersistFile.Save()
-URL archives should reflect their new content after execution, while previous ones Any attempt should still work on the contents of the old archive.
0 Comments