I've got a WinForms application that I am working on. There is one small piece of functionality that needs to be run as an administrator in Vista/Win7. I understand how I can set the requestedExecutionLevel for the application in the manifest. The trick is, I don't want to require the user to run the entire application as an administrator, just one part of it. So I would like to have most of the functionality run asInvoker.
If I put the admin functionality in a dll, is there a way to mark it as requireAdministrator? I tried to use MT to add a manifest to the dll, but that didn't seem to work. What do I need to do?
No there is no way to differentiate the execution level of an application on a DLL by DLL basis. This is a process wide setting. You'd have to invoke another process within your application that runs the code in that DLL with elevated privs.
One option you do have though is to use either the rundll or rundll32 program to run the DLL directly. This is a standalone windows program designed to load and run a particular DLL. You could elevate the rundll process and get the isolation you desire.
Googling for rundll will give you plenty of advice on how to use it :).
Elevation is per-process, so you can't have a DLL elevated by itself. You need to look at hosting the DLL in a separate, elevated process; or you can look at the elevation COM moniker, and do it that way.
Related
I have a click-once application, which is correctly signed, correctly configured and installs itself without any problem.
It is set to run offline, but install from a specific URL, and if I download and run the setup.exe, it installs updates.
So, it's basically all working... except I cannot print out the version number, or trigger an update from in code. If I try, I get the dreaded: 'Application identity is not set.'
2017-01-10 13:43:14.8367 ERROR System.Deployment.Application.InvalidDeploymentException: Application identity is not set.
at System.Deployment.Application.ApplicationDeployment.get_CurrentDeployment()
at LibDataAgent.Internal.Services.UpdateService.Deployment() System.Deployment.Application.InvalidDeploymentException: Application identity is not set.
at System.Deployment.Application.ApplicationDeployment.get_CurrentDeployment()
at LibDataAgent.Internal.Services.UpdateService.Deployment()
I am not running in debug mode, or using a debug build.
So here's my actual question:
How, does the click-once code in System.Deployment.Application, at runtime, determine what the application identity is?
So, there are whole lot other questions around this, but please don't close this as a duplicate, as far as I can tell it is not one.
Here's a list of things I do not want answers for:
How to sign a click-one application.
How to set the application identity as you build.
How to find where the click-once application is installed.
How to make a click-once application work while debugging.
How to check for updates using ApplicationDeployment.
Just very plainly, exactly what does a click-once application do, at runtime that lets it determine the application identity.
Help!
Notes
My (thus far fruitless) attempts to solve this have yielded these notes:
I'm certain this has something to do with how the application is launched, because executing applications from the command line has never worked with click-once; but executing the same application from the start menu will correctly return IsNetworkDeployed as true.
However, I've not been able to determine what the technical difference is, or why one detects the install correctly and one doesn't. (or indeed, why this specific application doesn't work from the start menu, when others with no obvious difference do).
Things I've tried that make no difference include:
the working directory for the application.
launching the application .exe directly or via a shell
launching the application from a new shortcut
There is some kind magic to the 'MyApplication.appref-ms' that goes into the start menu; the appref-ms is just a url to the install path:
http://s3-ap-southeast-1.amazonaws.com/blahblah/Dev/MyApplication.application#MyApplication.application, Culture=neutral, PublicKeyToken=fdasdfsafads, processorArchitecture=x86
...which somehow launches a 'click once aware' instance of the application. But how?
I'll still happily accept an answer that explains how the guts of launching the application actually sets the application context up with an identity, but for now here's my best stab at what's going on for anyone else who finds this question later:
ClickOnce applications are launched by hitting the install url, or by using the .appref-ms file on the start menu, which contains the url.
The application/x-ms-application MIME type handler is invoked for the downloaded file, which launches the 'ClickOnce aware' instance of the application.
At runtime, the ApplicationContext.Identity is used to determine what the ClickOnce details are, and setup the CurrentDeployment object.
As far as anyone knows, directly launching the deployed executable for a ClickOnce application (in C:\Users\Administrator\AppData\Local\Apps\2.0\b107ee1... or whatever the install folder is) will always return IsNetworkDeployed as false, and will not be able to self update.
Practically speaking, this means:
You're looking for the install folder and path to your .exe? Don't bother. Even when you know where it is, it won't have the correct ApplicationContext when you run it.
To spawn a new 'ClickOnce aware' instance of your application launch internet explorer at its install url. You cannot pass command line arguments to it.
eg.
var url = "http://s3-ap-southeast-1.amazonaws.com/blahblah/Dev/MyApplication.application#MyApplication.application, Culture=neutral, PublicKeyToken=fdasdfsafads, processorArchitecture=x86";
var psi = new ProcessStartInfo
{
FileName = #"iexplore",
Arguments = $"\"{url}\"",
};
Process.Start(psi);
(if you want to find the URL, hunt through the start menu for the appref-ms file for the application; the url is contained in it)
...and how does the executable get launched with an identity?
No idea; but this is as far as anyone seems to ever have got with understanding it:
(tldr; magic. Probably something to do with how CreateProcess is invoked to spawn the appliciation using the ApplicationContext api, in some combination of DFsvc.exe. DFshim.dll and DFdll.dll)
(The rest of this information is taken from this old blog post by Ian Picknel: http://ianpicknell.blogspot.com.au/2010/03/launching-clickonce-application.html)
Once the deployment manifest has been
stored in the Temporary Internet Files folder, Internet Explorer then
attempts to establish how it should handle the file with the (assumed
and actual) .application extension. It checks the user-specific file
types at HKCU\Software\Classes and, if it fails to find an
.application sub-key there, checks for machine-specific file types at
HKCR. Via this means it establishes that the .application extension
denotes an Application.Manifest file. It then uses this information to
check the user-specific HKCU\Software\Classes\Application.Manifest and
machine-specific HKCR\Application.Manifest keys to establish the CLSID
of a library which handles Application.Manifest files and yields the
result {98af66e4-aa41-4226-b80f-0b1a8f34eeb4}. Finally, it looks up
this CLSID in the user-specific
HKCU\Software\Classes\CLSID{98af66e4-aa41-4226-b80f-0b1a8f34eeb4} and
machine-specific HKCR\CLSID{98af66e4-aa41-4226-b80f-0b1a8f34eeb4}
paths to establish that .application files are handled by
C:\WINDOWS\system32\DFshim.dll.
This is where things start to get a little complicated. I said earlier
that no 'magic' was happening behind the scenes. Well, whilst that was
true for the process of retrieving the deployment manifest it most
certainly is not true of the process of actually launching the
ClickOnce application once the deployment manifest has been retrieved
and the handler, DFshim.dll, has been identified.
DFshim.dll is described in the registry as the 'Manifest mime handler'
although its file properties describe it as the 'Application
Deployment Support Library'. It implements the Internet Explorer MIME
handler COM interface. It is a native 32-bit DLL, written in Microsoft
Visual C++ 2005, and was installed into C:\Windows\system32 when the
.NET Framework 2.0 was installed.
DFshim.dll has a hard-coded reference to DFdll.dll, which it locates
by checking the values of
HKLM\SOFTWARE\Microsoft.NETFramework\InstallRoot (typically
C:\Windows\Microsoft.NET\Framework) and the keys beneath
HKLM\SOFTWARE\Microsoft.NETFramework\Policy\AppPatch (typically
v2.0.50727, even if a later version of the Framework is installed).
DFdll.dll too is a native 32-bit DLL written in Microsoft Visual C++
2005.
DFdll.dll uses COM services exposed by DFsvc.exe, which is also
located in the .NET Framework folder. DFsvc.exe is a standard .NET
MSIL assembly. DFsvc contains a single Main method (within the
System.Deployment.Application namespace) which simply calls the
internal System.Deployment.Application.DFServiceEntryPoint.Initialize
method within System.Deployment.dll. The Initialize method registers
System.Deployment.Application.DeploymentServiceCom with COM via
System.Runtime.InteropServices.RegistrationServices (i.e. it performs
the equivalent of CoRegisterClassObject in COM) using the CLSID
{33246f92-d56f-4e34-837a-9a49bfc91df3}. This is the means by which its
services are made available to DFdll.dll.
The COM service exposed by
System.Deployment.Application.DeploymentServiceCom delegates the
majority of its methods to other non-ComVisible classes within the
System.Deployment.Application namespace. For example, the public
ActivateDeployment method calls ActivateDeployment on a new
System.Deployment.Application.ApplicationActivator instance, the
public CheckForDeploymentUpdate method calls CheckForDeploymentUpdate
on System.Deployment.Application.SubscriptionStore, etc.
It is clear that the vast majority of the work surrounding the actual
installation and launch of the ClickOnce application is undertaken by
classes within the System.Deployment namespace, hosted within
DFsvc.exe. DFshim.dll and DFdll.dll appear to primarily be responsible
for arbitrating between the COM-based world of Internet Explorer and
the .NET-based world of ClickOnce.
I have a tool (created in C#) that launches another application using Process.start. This second application is a standalone application handling some external hardware using dlls and APIs.
Now whats happening is, when I launch the standalone application, it doesn't work until I copy paste all dll files (that are required by standalone application) in my tool's folder otherwise standalone application throws errors saying dll's missing.
It is also causing some performance issue with the standalone application too.
My assumption is : Because primary execution thread is from my tool and thus all spawned threads requires dll in the base thread (my tool's) folder. I don't want this. I am not sure what I have to do in this scenario.
If the only way to launch exe file in C# is using Process.start then how can I release the thread so that my tool don't track the standalone application ? (in case my assumption is correct)
If there is any other way to launch the exe file, please do let me know.
Help is much appreciated.
Kind Regards
Have you set WorkingDirectory appropriately?
It should be set to the location where your "another application" is located.
I added an app.manifest to a C# Windows Forms project because I needed the .exe elevated. Worked fine. I deleted the manifest because I no longer needed the app elevated. I changed to create application without manifest in properties.Re_Built...the app still needs admin elevation to run.
Works fine if I right-click run as admin. What gives?
The app just dies unless it is run as admin.
Well, despite what you say, it seems that your program carries out actions that do require elevation. Perhaps you write to a location that standard user does not have rights to. Or perhaps you write to registry keys under HKLM.
To get to the bottom of this you need to do some debugging. Find out what it is that your program does that requires elevation. Use the IDE debugger, or a tool like Process Monitor.
I've developed a tool in C#.NET/Visual Studio, which uses an imported dll.
The dll will be copied to output folder, when the project is built.
It doesn't need to install the application, you can just copy the exe and dll to a local folder to start.
Now I want to start the application from a network share:
\\localhost\program\prog.exe
All is fine while I don't call a function from the external dll. Then it crashes with the following error window:
Program has stopped working...
Question: Is there a way to make it work without copying both to a local folder and without changing policies on client computers?
Answer: Mapping \localhost to Z: solved this problem.
Please feel free to ask, this is my first question ;-)
Best regards,
Christian
This sounds like a "caspol" issue. Network shares like \\localhost\program\ get reduced trust. Interestingly, from (some time ago), named shares actually get more trust - so one simple option is to map, say, z: as \\localhost\program, and access z:\prog.exe - you might find that this makes it work. Beyond that, the options are:
caspol changes to the each client machine
ClickOnce
of those, the latter is simpler. Then you simply run the ClickOnce application (rather than the .exe) - ClickOnce then basically makes it work. The user will, IIRC, need to click an "ok" the first time they run the application, but that's about it. You would need to ensure that the external dll is known the the ClickOnce deployment, i.e. it is in the project and marked to be shipped.
I'm going to make a desktop application that will run in the background, meaning no visible window, and I'd like an option called: "Upload Text" to appear when a user right clicks a file.
Can someone point me in the right direction? I also have to make sure that if someone wants to uninstall the program at any point, that the shell modification is also cleanly eliminated.
The app will run Windows XP, Windows Vista and Windows 7. How different are these OS's in handling my shell dilemma?
This is a shell extension. You've tagged this question with the C# tag; you should know that writing shell extensions in a managed language is strongly discouraged:
Unfortunately unmanaged C++ is really
the only way to go here.
Writing in-process shell extensions
in managed code is actually a very
dangerous thing to do because it has
the effect of injecting your managed
code (and the .NET Framework) into
every application on the machine that
has a file open dialog.
The problems occur because only one
version of the .NET Framework can be
loaded in a process at any given time
(other shared components such as java
and msxml have the same property and
thus the same restriction).
If you write your shell extension
using the 2.0 .NET Framework and an
application built with the 1.1 .NET
Framework uses a file open dialog,
your shell extension will fail because
it can not run on an earlier version.
Things can get even worse if your
shell-extension manages to get loaded
in a process before another
applications managed code does: your
extension may force an existing
application onto a different runtime
version than the one it was expecting
and cause it to fail.
Because of these problems we strongly
recomend against using any
single-instance-per-process runtime or
library (such as the .NET Framework,
java, or msxml) in an in-process shell
extension.
That said, people have done it.
Here's a guide to creating shell extensions, using C++.
You could add your app to the SendTo folder.
What about a stand-alone program using SendTo?
Install the exe to "Program Files\mycompany\myprogram" and a shortcut to the exe into the SendTo folder. Then when a user right clicks on a file, selects SendTo, and then selects your program, your exe will be executed by Windows and the full path to the filename will be passed in via argv[1]. If they select n files they will be in argv[1]..argv[n].
If you want your program to be invisible then do not make the default form visible. You could optionally place an icon in the tray so the user could double click on it to see the upload progress. When the upload of argv[1] is complete, process argv[2]...argv[n] if they exists and exit. To cleanly uninstall, remove your program and the shortcut from the SendTo folder.