Trochu nedobrovolně jsem byl dnes donucen šťourat se podrobněji v ClickOnce útrobách, přestože to není moje oblast zájmu.
Symptomy problému byly zajímavé – aplikace instalovaná pomocí ClickOnce, která v sobě měla volbu „Automaticky spouštět při startu Windows“, se chovala divně. Zprvu se zdálo, že nastavení provedená v aplikaci (.NET Settings mechanizmus), se restartem počítače ztratí. Nakonec jsem diagnostikoval, že ve skutečnosti aplikace používá dvoje nastavení – jedna nastavení používaná po instalaci a při spuštění aplikace automaticky vytvořenou položkou z menu Start, druhá nastavení používaná při automatickém spuštění po startu Windows. Zároveň jsem v C:\Users\… našel v profilu uživatele dva různé user.config soubory, které se používaly pro tyto dva scénáře spuštění aplikace.
Chyba byla ve skutečnosti v nekoretním spouštění aplikace po startu Windows. ClickOnce totiž sám automatické spouštění po startu Windows nepodporuje a při vlastní implementaci nebyl na rozdíl od zástupce v menu Start totiž použit link typu .asppref-ms (link soubor pro spouštění ClickOnce apliace, který zajišťuje i aktualizace a další ClickOnce věci), ale nekorektně aplikace pro spuštění po startu Windows používala přímo odkaz na svůj .exe soubor. To způsobilo nejen použití jiného user.config souboru, ale i nefunkčnost automatických aktualizací a dalších vlastností ClickOnce.
Poučení tedy zní: Pokud chcete korektně spouštět ClickOnce aplikaci, je potřeba volat vytvořený soubor .appref-ms (vytvořený ClickOnce instalátorem do menu Start) a nikoliv se odkazovat na .exe soubor aplikace.
Chybný kód tak může vypadat:
Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true) .SetValue("InformTrayReader", Application.ExecutablePath);
Zatímco „správně“ (při dalších omezeních) by to mohlo vypadat nějak takto:
Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true) .SetValue("InformTrayReader", GetApplicationStartupLink()); private object GetApplicationStartupLink() { const string productName = "název dle ClickOnce Publish nastavení"; const string publisherName = "nastavení dle ClickOnce Publish nastavení"; string allProgramsPath = Environment.GetFolderPath(Environment.SpecialFolder.Programs); string shortcutPath = Path.Combine(allProgramsPath, publisherName); return Path.Combine(shortcutPath, productName) + ".appref-ms"; }
Viz též související info:
UPDATE pro Windows Vista
Pokud nedejbože potřebujete, aby to fungovalo pro nějakého nebožáka používajícího alfa-verzi od Windows7 zvanou Windows Vista (dodnes nechápu, jak mohl Microsoft něco takového vydat), potom je nutný ještě jeden workaround.
Visty totiž nepustí .appref-ms přímo, a to ani z registrů, ani kdybyste odkaz dopravili do Start/Startup. Funguje v nich ale spouštění .exe a kupodivu lze .appref-ms zavolat z našeho exe a spustí se. Stačí tedy našemu programu přidat přepínač příkazové řádky -LaunchClickOnce a při jeho zjištění v Main() místo aplikace samotné odstartovat jen .appref-ms a sám se ukončit.
Podrobnější popis s ukázkou konkrétního kódu najdete na stránce http://www.brokenwire.net/bw/Programming/116/run-clickonce-app-on-startup.