2

I have a WPF application deployed using ClickOnce. It has one custom file association set with it that can open and be opened in the application if that file type is opened. This has been working great, then all of a sudden during an update users started receiving an "Application Could Not Be Started" errors.

Looking into the error details I can see this:

ERROR DETAILS
    Following errors were detected during this operation.
    * [12/8/2020 3:34:54 PM] System.UnauthorizedAccessException
        - Attempted to perform an unauthorized operation.
        - Source: mscorlib
        - Stack trace:
            at Microsoft.Win32.RegistryKey.Win32Error(Int32 errorCode, String str)
            at Microsoft.Win32.RegistryKey.SetValue(String name, Object value, RegistryValueKind valueKind)
            at System.Deployment.Application.ShellExposure.AddFileAssociation(FileAssociation fileAssociation, DefinitionIdentity subId, Uri deploymentProviderUri)
            at System.Deployment.Application.ShellExposure.AddShellExtensions(DefinitionIdentity subId, Uri deploymentProviderUri, AssemblyManifest appManifest)
            at System.Deployment.Application.ShellExposure.UpdateShellExtensions(SubscriptionState subState, ShellExposureInformation& shellExposureInformation)
            at System.Deployment.Application.ShellExposure.UpdateSubscriptionShellExposure(SubscriptionState subState)
            at System.Deployment.Application.SubscriptionStore.CommitApplication(SubscriptionState& subState, CommitApplicationParams commitParams)
            at System.Deployment.Application.ApplicationActivator.InstallApplication(SubscriptionState& subState, ActivationDescription actDesc)
            at System.Deployment.Application.ApplicationActivator.PerformDeploymentActivation(Uri activationUri, Boolean isShortcut, String textualSubId, String deploymentProviderUrlFromExtension, BrowserSettings browserSettings, String& errorPageUrl, Uri& deploymentUri)
            at System.Deployment.Application.ApplicationActivator.PerformDeploymentActivationWithRetry(Uri activationUri, Boolean isShortcut, String textualSubId, String deploymentProviderUrlFromExtension, BrowserSettings browserSettings, String& errorPageUrl)
--- End of stack trace from previous location where exception was thrown ---
            at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
            at System.Deployment.Application.ApplicationActivator.PerformDeploymentActivationWithRetry(Uri activationUri, Boolean isShortcut, String textualSubId, String deploymentProviderUrlFromExtension, BrowserSettings browserSettings, String& errorPageUrl)
            at System.Deployment.Application.ApplicationActivator.ActivateDeploymentWorker(Object state)

I determined it was the file association as that is the only thing touching the registry by ClickOnce AFIK. After removing it, the issue went away, but now the program has no file extensions. I've tried installing with elevated permissions, but that hasn't fixed the issue either. Adding the extension back caused the issue to return. We didn't touch any of the underlying file association or startup logic on this update so what the heck would be causing this issue?

Has anyone experienced this working with ClickOnce and file associations?

Edit: Using VS2017's Publish->Options to create the associations (which drops the info into the .csproj file).

<ItemGroup>
    <FileAssociation Include=".simsp">
      <Visible>False</Visible>
      <Description>My Description</Description>
      <Progid>MyProgram.Proposal</Progid>
      <DefaultIcon>Proposal.ico</DefaultIcon>
    </FileAssociation>
</ItemGroup>

Also, after uninstalling and removing AppData files related to the app, the app installed on one machine fine, but not the other under the same user account (we use file sync to replicate desktops). This is confusing as I am not sure why the install would fail during Registry entry if it's an issue in the AppData files located in the Users path.

EDIT 3: The issue seems to occur randomly, but we noticed it occurs when a file is opened, causing the ClickOnce app to open and update. Thus far, the issue seems isolated to user using file sync, replicated desktops who have mutliple workstations.

Best practices to work around this? It may just be a ClickOnce limitation.

Tronald
  • 1,520
  • 1
  • 13
  • 31
  • How does your clickonce manifest look like? Are you using [`fileAssociation`](https://learn.microsoft.com/en-us/visualstudio/deployment/fileassociation-element-clickonce-application?view=vs-2019)? – Pavel Anikhouski Dec 09 '20 at 10:28
  • @PavelAnikhouski I'm using VS2017's built in publishing settings that go into the .csproj file. I assume it generates in the manifest upon publishing. I can create the association again and see what the manifest says tonight. – Tronald Dec 09 '20 at 21:00
  • @PavelAnikhouski I updated the question. I guess the association doesn't add itself to the manifest as it is not in there. This is what's generated in the .csproj file though. Thoughts? – Tronald Dec 10 '20 at 00:24

2 Answers2

3
    - Attempted to perform an unauthorized operation.

This error says us - operation blocked by some protection rules, that can be:

  1. UAC
  2. Computer security policy for user
  3. Domain security policy for user

So, you can solve by setting ClickOnce manifest only UAC. I created ClickOnce manifest, that has minimum one file accociation with app, and It works fine. UAC asks user to perfome installation or update app, and all works perfect. But all users don't has any file sync to another computer. If them need my app - them install it on another computer, and then update if needed.

In .proj file I have two general sections of ClicOnce manifest generation:

<ItemGroup>
    <FileAssociation Include=".appex">
      <Visible>False</Visible>
      <Description>Exception info file</Description>
      <Progid>My.AppClient</Progid>
      <DefaultIcon>Images\Exception.ico</DefaultIcon>
    </FileAssociation>
  </ItemGroup>

And prerequsities section:

 <ItemGroup>
    <BootstrapperPackage Include=".NETFramework,Version=v4.7">
      <Visible>False</Visible>
      <ProductName>Microsoft .NET Framework 4.7 %28x86 and x64%29</ProductName>
      <Install>true</Install>
    </BootstrapperPackage>
    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
      <Visible>False</Visible>
      <ProductName>.NET Framework 3.5 SP1</ProductName>
      <Install>false</Install>
    </BootstrapperPackage>
    <BootstrapperPackage Include="Microsoft.SqlServer.SQLSysClrTypes.12.0.x64">
      <Visible>False</Visible>
      <ProductName>System types Microsoft® CLR for SQL Server® 2014 %28x64%29</ProductName>
      <Install>true</Install>
    </BootstrapperPackage>    
  </ItemGroup>

So, let think abount users from your 'Edit 3'. ClickOnce uses when you share your app with other users, but your application installs only for one user, not for all users on computer. All new installs, or any update of your app by ClickOnce create new folder in AppData directory for this purposes:

  1. Install new version of app
  2. Save rollback operation to previouse version
  3. App can run only that user, who install it. So, file binding also only for this user (because app files into user profile folder)

Also, there are creating registry settings to open your app from new location. This combination (registry settings and app folders with files) not propertly worsk for users wich has a lot of workstations with sync they data between workstations. Or you need properly sync registry with app folders (all of them).

But! In your app manifest may contain prerequisities (as i show here) with external packages, or you can add it in new version of your app. What do you think will be when user update your app on one computer or install it, and than run updated app (that correctly synced) on another computer without this external links? App will be crashed.

So, in my opinion, your solution will be:

  1. Use WIX project to create package, that can be installed for all users on one computer. And try to not store files in user profile folder, that can will broken application when not properly copied to new computer. Or rewrite it by your app, if it not properly copied. Any update you can check on startup, or register update service, to install new version of you app in background.

  2. Use ClickOnce with rules of sync profile files to not copy app files via policy. User once install your app on computer, profile not deleted after user logged off. Files of your app must not be synced. And you try to register file extension on app startup with evaluated privilegies. On another computer user run clean install, if them needs your app, or update (if it alredy installed). In my expirience, i store all of app settings in database. In user registry settings of db server name and database name wich my app connected to.

  3. On app startup you can run code from another user like this. But, ClickOnce installs for current user, and this solution will not work properly.

Maxim
  • 854
  • 1
  • 8
  • 16
  • Thank you for your detailed response. Unfortunately, ClickOnce without elevated permissions is required due to the rapid deployment processes we use internally (it's an internal app). Looking at our replication rules, it doesn't look like the users "Local" appdata syncs between desktops anyway. The "shortcut" created however does and drops into the "Roaming" folder. Your answer led me to look more into the registry. The GUIDs of the file association change during update. Do you know what other registry entries would be made during install/update? Is it a conflict in the registry causing error? – Tronald Dec 14 '20 at 18:45
  • I have some issues with ClickOnce update of my app. User run app, app updating, than starts correctly. When user close app, there are may be errors (very rarely): 1. Shortcut on desktop broken and not run app (not updated, and links with empty folder of previouse version) 2. There are two shortcuts for previuse version and current. One run app, another no. So, ClickOnce shortcut is a link https://serverdustibute/AppName.application#AppName.application, Culture=nutral, publicKeyToken=*****, processorArchitecture=msil AppName.application - is manifest file, which register in registry. – Maxim Dec 15 '20 at 03:40
  • ClickOnce stores entries here (I check my registry) HKEY_CURRENT_USER\SOFTWARE\Classes\Software\Microsoft\Windows\CurrentVersion\Deployment HKEY_CURRENT_USER\SOFTWARE\Classes And some other places in HKCU. So, this entries copy to new environment of users that profiles has sync – Maxim Dec 15 '20 at 03:45
  • HKEY_CURRENT_USER\SOFTWARE\Classes\Software\Microsoft\Windows\CurrentVersion\Deployment\SideBySide\2.0\Components\ - all installed by ClickOnce app manifests applications with guids to store version compatibility after update app. Here some registries of app HKEY_CURRENT_USER\SOFTWARE\Classes HKEY_CURRENT_USER\SOFTWARE\Classes\AppName HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ And some other places in HKCU. This registry I found full path to my app HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\bam\State\UserSettings\User SID\app links – Maxim Dec 15 '20 at 03:53
  • In last registry (HKLM), you can see link to your app like this \Device\HarddiskVolume3\Users\{UserName}\AppData\Local\Apps\2.0\OLE34AGA.AQY\CXKHCR6N.EG7\application_932ad0cc9880ff94_0001.0013_c63a8dc009dccbb3\appName.exe So, I think if you have diferent installs with different GUID - this may couse a big problem. That's why, I recommended WIX or another VS setup project for solve problem with sync registre between several environments – Maxim Dec 15 '20 at 03:58
  • Interesting. We never actually assigned a GUID in the Assembly Info of the app. Is it possible the installer is assigning the app a specific GUID with each update and causing conflicts? I wonder if setting it to a static value would resolve the issue. It does seem to occur randomly and I wonder it it's because it changes the GUID of the app during updates randomly. I am going to set and see if it keeps the issue at bay! – Tronald Dec 15 '20 at 04:35
  • I think you should read https://learn.microsoft.com/en-us/visualstudio/deployment/how-to-manage-updates-for-a-clickonce-application?view=vs-2019 and https://learn.microsoft.com/en-us/visualstudio/deployment/troubleshooting-specific-errors-in-clickonce-deployments?view=vs-2019 Aloso, https://learn.microsoft.com/en-us/visualstudio/deployment/security-versioning-and-manifest-issues-in-clickonce-deployments?view=vs-2019 – Maxim Dec 15 '20 at 07:23
  • Thanks at @Maxim. I have read these docs already and the don't detail the registry entries being made. Setting the GUID of the assembly didn't seem to resolve the issue as I was able to get it to occur after updating the ICO file. Then I did it again and the issue didn't occur. It's so freaking random it's driving me mad lol. Will keep digging. – Tronald Dec 16 '20 at 17:32
1

Looking at the Stacktrace I see the Registry namespace at the top. So in addition to Maxim's answer I'd say that it happens while clickonce tries to set the value of a registry key. You can also set permissions in regdit. Right click a key, select permissions, and make sure read and write are set for the user running the application.

Since you already figured out the registry keys involved you might have a good chance to resolve it by giving writing permission to these keys to the users.

AdrAs
  • 676
  • 3
  • 14
  • The people it occurs with do have the proper access though, so I believe its a registry conflict issue causing the exception. Would be nice if it detailed which registry key was causing the issue. – Tronald Dec 16 '20 at 17:30