Partager via


CoCreateInstanceAsAdmin or CreateElevatedComObject sample

The COM elevation moniker is one of the three recommended ways to have a user application do tasks that require admin privileges. The UAC document from September 2006 refers to it as the Admin COM Object model under the section “Key Decisions for Designing Administrator-Only Applications”.

Apparently CoCreateInstanceAsAdmin from the SDK documentation has been rebranded as CreateElevatedComObject in the UAC doc. I have a sample with an ATL component and a console client attached that show this working. (Disclaimer: It is for demo purposes only and the code does not do any error or exception handling.)

The only changes I had to make was in the two rgs files. In order to make the inproc COM component run in the dllhost.exe surrogate, I had to add this to MyElevatedCOM.rgs:

val DllSurrogate = s ''

I also had to add this to the MyElevated.rgs file to make it both Elevation capable and MUI aware respectively:

Elevation

{

val Enabled = d 1

}

val LocalizedString = s <'@%MODULE%,-101'>

Finally to match up the LocalizedString entry with an entry from the resource, I added a new string in the String table with a matching entry of 101.

The client side is literally copied from the SDK docs.

[updated]

If you try to launch this application from a real standard user (so not a filtered admin), you will get an E_ACCESSDENIED on the actual method call. In order to get around this you will need to give the interactive user access permission to the COM component.

Steps:

  1. Launch COM+ explorer (start, run, dcomcnfg)
  2. Navigate to Component Services\Computers\My Computer\DCOM Config and get to MyElevatedCOM (for this demo app that is)
  3. Select Properties and go to security tab.
  4. Under Access Permissions, select the Customize button radio button and click Edit.
  5. Click Add. Change the "locations" to the local machine.
  6. Enter "Interactive" and OK out of all the dialogs.

If you need to script this you can use DCOMPERM from the platform SDK.

Maarten

MyElevatedCom.zip

Comments

  • Anonymous
    October 06, 2006
    i ran this sample code on vista rc1 (build 5600), and it worked except the 2nd ShowMe() call failed with E_ACCESSDENIED. i was prompted for admin credentials during the CoGetObject() call and it succeeded. any ideas? thanks, justin

  • Anonymous
    October 26, 2006
    Someone reported the same issue to me. i will update the blog.

  • Anonymous
    November 01, 2006
    Just curious: Given the significant gotcha with the custom DCOM setup being required for this approach to work when running as a standard user, would you still recommend this COM-based technique for commercial software to achieve elevation to administrator? If so, do you recommend basically doing the COM permission changes described in steps 1-6 (or, more precisely their programmatic equivalent) during setup?  How?  As an MSI custom action?   What security implications are there of granting INTERACTIVE (effectively the same as EVERYONE on the local machine) access in this way?  Any security gotchas there?  Is this how standard Microsoft applications (like the Windows shell) achieve elevation to administrator when running parts of their UI inside of a DLLHOST? Nick

  • Anonymous
    January 03, 2007
    Is there anything else other than VS2005 SP1 and Vista RTM to install to get this sample to work?  I get a compilation error for BIND_OPTS3. Thanks. Rob.

  • Anonymous
    January 03, 2007
    Rob, You will need the vista platform sdk: http://www.microsoft.com/downloads/details.aspx?FamilyId=C2B1E300-F358-4523-B479-F53D234CDCCF&displaylang=en

  • Anonymous
    January 14, 2007
    My had some test about this attachments with Vista (no development tools installed) Compiled with WinXP SP2 (with Vista SDK) and run with Vista (no dev tools installed) But regsvr32 cannot register dll file to registry regsvr32 says, 'there is no library to run.', but I copied files such as 'atl80.dll', 'msvcr80.dll' and i checked dependency with depends.exe. What was wrong with my work? please let me know. :'(

  • Anonymous
    February 14, 2007
    I have everything working with the Elevation Moniker except getting the Icon specified by the IconReference registry key. This ICON should (If I understand it correctly) display my ICON in the admin login dialog when elevation is requested by my app. What format should I use ? The MyElevatedCom example doesn't specify one. So far, I have tried by making a reference to the icon to display the same way I specified the LocalizedString key for "Friendly Name" (Replacing the String ID with the constant that is generated in my DLL for the ICON I want). but it doesn't seem to work.

  • Anonymous
    February 14, 2007
    I have everything working with the Elevation Moniker except getting the Icon specified by the IconReference registry key. This ICON should (If I understand it correctly) display my ICON in the admin login dialog when elevation is requested by my app. What format should I use ? The MyElevatedCom example doesn't specify one. So far, I have tried by making a reference to the icon to display the same way I specified the LocalizedString key for "Friendly Name" (Replacing the String ID with the constant that is generated in my DLL for the ICON I want). but it doesn't seem to work.

  • Anonymous
    February 27, 2007
    Hi, //justinf -- Are you trying second method on XP? //VistaCompatTeam what option did you included in ATL project wizard and Atl simple object wizard? I'm trying to do the same on vista and your example works weel, but mine not ( in moment I'm trying to obtain pointer to IMyElevatedCom) it says me "Element not found" ( works fine on XP) Tryied regsvr32 to my dll and no changes... Best regards

  • Anonymous
    May 10, 2007
    I think I've got my implementation working. This blog was very useful. Some feedback for others who might read it: Lots of good information also at http://msdn2.microsoft.com/en-us/library/ms679687.aspx ("The COM Elevation moniker"). This shows how to solve the E_ACCESSDENIED problem without resorting to dcomcnfg. You need to add registry keys to your class AppId registry key to set up the AccessPermission and LaunchPermission ACLs. The ACLs allow the Interactive group access, and also allow low integrity applications to launch. I found the best way to do this was to add code to call SetAccessPermissions() and SetLaunchActPermissions() during DLLRegisterServer time. Also, regarding the presence of the custom icon in the elevation prompt dialog: the custom icon will only appear if the DLL is signed.

  • Anonymous
    May 01, 2008
    I tried using DCOMCNFG to set the interactive user but i still got Access Denied however following the instructions given in the link above does allow non-admin access. However, is it possible to stop the Elevation warning dialogs popping up? Does signing either the client/server make a difference.

  • Anonymous
    November 20, 2008
    I couldn't make the 'CoCreateInstanceAsAdmin' work from a DLL so I implemented it the way the docs suggested. HRESULT CoCreateAdminInstance(HWND hwnd, REFCLSID rclsid, REFIID riid, __out void ** ppv) { // Manual implementation of CreateInstanceAsAdmin CComPtr<IBindCtx> BindCtx; HRESULT hr = CreateBindCtx(0,&BindCtx); BIND_OPTS3 bo; memset(&bo, 0, sizeof(bo)); bo.cbStruct = sizeof(bo); bo.grfMode = STGM_READWRITE; bo.hwnd = NULL; bo.dwClassContext = CLSCTX_LOCAL_SERVER; hr = BindCtx->SetBindOptions(&bo); if (SUCCEEDED(hr)) { // Use the passed in CLSID to help create the COM elevation moniker string CComPtr<IMoniker> Moniker; WCHAR wszCLSID[50]; WCHAR wszMonikerName[300]; StringFromGUID2(rclsid,wszCLSID,sizeof(wszCLSID) / sizeof(wszCLSID[0])); hr = StringCchPrintfW(wszMonikerName, sizeof(wszMonikerName)/sizeof(wszMonikerName[0]), L"Elevation:Administrator!new:%s", wszCLSID); if (SUCCEEDED(hr)) { // Create the COM elevation moniker ULONG ulEaten = 0; ULONG ulLen = (ULONG)wcslen(wszMonikerName); LPBC pBindCtx = BindCtx.p; hr = MkParseDisplayName(pBindCtx,wszMonikerName,&ulEaten,&Moniker); if (SUCCEEDED(hr) && ulEaten == ulLen) { // Use passed in RIID to bind to the object IDispatch * pv = NULL; hr = Moniker->BindToObject(pBindCtx,NULL,riid,ppv); } } } return hr; }

  • Anonymous
    September 08, 2010
    The comment has been removed