• notice
  • Congratulations on the launch of the Sought Tech site

SHChangeNotify doesn't update URL=change my .url shortcut file

I have a simple Delphi application that creates desktop shortcuts for URLs.it.urlIn 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;
  • alsoSHCNF_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 (ie httpit'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:

  1. 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's URL= value is still the one that is considered.
  2. 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.exeonMemoryIPersistFile.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.

Tags

Technical otaku

Sought technology together

Related Topic

0 Comments

Leave a Reply

+