Click here to Skip to main content
15,867,308 members
Articles / Desktop Programming / ATL

Elevating your application for dummies: A step-by-step guide to elevate and write in the Registry

Rate me:
Please Sign up or sign in to vote.
5.00/5 (10 votes)
8 Apr 2009CPOL3 min read 43.5K   411   30   6
We are going to enable your application to write entries in HKEY_LOCAL_MACHINE, elevating your application when necessary.

Introduction

We're going to enable your application to write entries in HKEY_LOCAL_MACHINE, elevating your application when necessary using the COM method enumerated in http://msdn.microsoft.com/en-us/library/bb530410.aspx#vistauac_topic6c.

We'll create a new COM object with two methods: WriteString and WriteLong, and we'll use that COM object when writing entries to Local Machine. Then, we'll create a console application to show the use. It is really easy, and we'll finish everything in 5 minutes. So, let's go.

Background

If after reading this topic: http://msdn.microsoft.com/en-us/library/bb530410.aspx#vistauac_topic6b, you determine that your application is a Mixed application, this article is for you.

Using the code

After registering the server, your application can use the CElevatedRegistryWritter class to elevate and write in the Registry anytime you want.

C++
CElevatedRegistryWritter writter(GetConsoleWindow());
if(writter.WriteString(_T("Software\\Microsoft"), 
                       _T("Message"), _T("Hello World")) &&
    writter.WriteLong(_T("Software\\Microsoft"), 
                      _T("MyValue"), 100))
{
    print("All done!");
}

Phase 1: Creating a Registry COM object

  1. Create a new ATL project (I'll name it Elevator).
  2. Image 1

  3. Select Executable (EXE) as Server type in the ATL Project Wizard dialog box.
  4. Image 2

  5. Add a new class to your Elevator project.
  6. Image 3

  7. Choose ATL Simple object, and press Add in the Add Class dialog box.
  8. Image 4

  9. Name your class "LocalMachineWriter" in ATL Simple Object Wizard dialog box, and press Finish.
  10. Image 5

  11. Add a new method to the interface ILocalMachineWritter.
  12. Image 6

  13. Call your new method WriteString, and add three in parameters: path, var, and value, all of them BSTR, and press Finish.
  14. Image 7

  15. Repeat steps 6 and 7 for the WriteLong method (the value parameter must be LONG).
  16. Image 8

  17. Modify the code of CLocalMachineWritter::WriteString and CLocalMachineWritter::WriteLong like this:
  18. C++
    STDMETHODIMP CLocalMachineWriter::WriteString(BSTR path, BSTR var, BSTR value)
    {
        HKEY hk = NULL;
        if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0, 
                 KEY_READ | KEY_WRITE, &hk))
            return E_FAIL;
    
        bool nReturn = E_FAIL;
    
        if(ERROR_SUCCESS == RegSetValueEx( hk, var, 0, REG_SZ, 
               (const BYTE*)value, (1 + (DWORD)_tcslen(value)) * sizeof(TCHAR) ))
            nReturn = S_OK;
    
        RegCloseKey(hk);
    
        return nReturn;
    }
    
    STDMETHODIMP CLocalMachineWriter::WriteLong(BSTR path, BSTR var, LONG value)
    {
        HKEY hk = NULL;
        if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
                      path, 0, KEY_READ | KEY_WRITE, &hk))
            return E_FAIL;
    
        bool nReturn = E_FAIL;
    
        if(ERROR_SUCCESS == RegSetValueEx( hk, var, 0, REG_DWORD, 
                      (const BYTE*)&value, sizeof(LONG)))
            nReturn = S_OK;
    
        RegCloseKey(hk);
    
        return nReturn;
    }
  19. Now, we have to enable our COM object to be elevated, adding two entries to the Registry.
  20. Open LocalMachineWriter.rgs and add the bold lines:

    C++
    HKCR
    {
        Elevator.LocalMachineWriter.1 = s 'LocalMachineWriter Class'
        {
            CLSID = s '{E89BECE0-84AC-4EE0-BC26-835C269C166F}'
        }
        Elevator.LocalMachineWriter = s 'LocalMachineWriter Class'
        {
            CLSID = s '{E89BECE0-84AC-4EE0-BC26-835C269C166F}'
            CurVer = s 'Elevator.LocalMachineWriter.1'
        }
        NoRemove CLSID
        {
            ForceRemove {E89BECE0-84AC-4EE0-BC26-835C269C166F} = 
                           s 'LocalMachineWriter Class'
            {
                ProgID = s 'Elevator.LocalMachineWriter.1'
                VersionIndependentProgID = s 'Elevator.LocalMachineWriter'
                ForceRemove 'Programmable'
                LocalServer32 = s '%MODULE%'
                'TypeLib' = s '{A38F2A11-AF97-4903-9DF3-F757291C9358}'
    
                val LocalizedString = s '@%MODULE%,-100'
                ForceRemove Elevation = s ''
                {
                    val Enabled = d '1'
                }
            }
        }
    }

    For information about .rgs files, refer this link: http://msdn.microsoft.com/en-us/library/k32htktc.aspx. For information about why to add these entries, refer this link: http://msdn.microsoft.com/en-us/library/ms679687.aspx.

  21. Now, compile the COM object.
  22. Finally, we have to register our COM object to enable other applications to use it. Open an elevated Cmd (execute CMD.exe while pressing the Ctrl+Shift keys), go to the Debug or Release directory, and register the server, executing it with the /RegServer parameter:

    Image 9

    And, we're finished!!

    We have created a COM object, enabled to write in the Local Machine. Now, we've to create the client side code to run our COM object with elevated privileges.

  23. Create a new Win32 console application. Call it Client, and press OK.
  24. New project

  25. Select Console Application in the Win32 Application Wizard dialog box, and press Finish.
  26. Image 11

  27. Modify the StdAfx.h file to include Windows.h and comutil.h.
  28. C++
    #include <windows.h>
    #include <comutil.h>
    
    #ifdef _DEBUG
    #pragma comment(lib, "comsuppwd.lib")
    #else
    #pragma comment(lib, "comsuppw.lib")
    #endif

    We've included ComUtil.h and the library comsuppw because we'll use the _bstr_t class (http://msdn.microsoft.com/en-us/library/zthfhkd6(VS.71).aspx).

  29. Copy Elevator_i.c and Elevator_i.h from your Elevator project directory to your brand new client application directory (these files are necessary because they declare the interface and the GUIDs of the interface and the object).
  30. Add a new class to your client application:
  31. Image 12

  32. Select C++ Class in the Add Class dialog box:
  33. Image 13

  34. Call your new class CElevatedRegistryWritter, and press Finish in the Generic C++ Class Wizard dialog box.
  35. Image 14

  36. Replace ElevatedRegistryWritter.h with this:
  37. C++
    #pragma once
    
    #include "Elevator_i.h"
    
    ///    <summary>
    ///    Wrapper class to load the LocalMachineWritter object
    /// with elevated credentials.
    ///    </summary>
    ///    <creation date="08/04/2009" by="Jose Angel"/>
    class CElevatedRegistryWritter
    {
        HWND wndParent;
        ILocalMachineWriter* object;
    
    #pragma region Constructors and destructor
    public:
        ///    <summary>
        ///        Constructor of the class
        ///    </summary>
        ///    <param name="wndParent">
        ///        Handle to a window. 
        ///        Use <c>GetConsoleWindow</c>
        ///         or <c>AfxGetMainWnd</c> for instance
        ///    </param>
        CElevatedRegistryWritter(HWND wndParent);
    
        ///    <summary>
        ///        Destructor. It will unload the Com object if necessary.
        ///    </summary>
        ~CElevatedRegistryWritter();
    #pragma endregion
    
    #pragma region Public methods
        ///    <summary>
        ///        This method ininialize the Com object
        ///     if necessary and write a string in the registry.
        ///    </summary>
        ///    <param name="path">Path of the key to write.</param>
        ///    <param name="var">Name of the key to write.</param>
        ///    <param name="value">Value to write.</param>
        ///    <returns>True if success.</returns>
        bool WriteString(LPCTSTR path, LPCTSTR var, LPCTSTR value);
    
        ///    <summary>
        ///        This method ininialize the Com object
        ///     if necessary and write a long in the registry.
        ///    </summary>
        ///    <param name="path">Path of the key to write.</param>
        ///    <param name="var">Name of the key to write.</param>
        ///    <param name="value">Value to write.</param>
        ///    <returns>True if success.</returns>
        bool WriteLong(LPCTSTR path, LPCTSTR var, LONG value);
    #pragma endregion
    
    #pragma region Implementation
    private:
        ///    <summary>
        ///        Utility method to create the object as an administrator.
        ///    </summary>
        HRESULT CoCreateInstanceAsAdmin(HWND hwnd, REFCLSID rclsid, 
                REFIID riid, __out void ** ppv);
    #pragma endregion
    };

    and ElevatedRegistryWritter.cpp with this:

    C++
    #include "StdAfx.h"
    #include "ElevatedRegistryWritter.h"
    #include "Elevator_i.c"
    
    CElevatedRegistryWritter::CElevatedRegistryWritter(HWND _wndParent)
        : object(NULL)
        , wndParent(_wndParent)
    {
    }
    
    CElevatedRegistryWritter::~CElevatedRegistryWritter(void)
    {
        if(NULL != object)
            object->Release();
    }
    
    bool CElevatedRegistryWritter::WriteString(LPCTSTR path, LPCTSTR var, LPCTSTR value)
    {
        if( NULL == object && FAILED(CoCreateInstanceAsAdmin(wndParent, 
                CLSID_LocalMachineWriter, IID_ILocalMachineWriter, (void**)&object)))
            return false;
    
        SUCCEEDED(object->WriteString(_bstr_t(path), _bstr_t(var), _bstr_t(value)));
    }
    
    bool CElevatedRegistryWritter::WriteLong(LPCTSTR path, LPCTSTR var, LONG value)
    {
        if( NULL == object && FAILED(CoCreateInstanceAsAdmin(wndParent, 
                  CLSID_LocalMachineWriter, IID_ILocalMachineWriter, (void**)&object)))
            return false;
    
        SUCCEEDED(object->WriteLong(_bstr_t(path), _bstr_t(var), value));
    }
    
    
    HRESULT CElevatedRegistryWritter::CoCreateInstanceAsAdmin(HWND hwnd, 
            REFCLSID rclsid, REFIID riid, __out void ** ppv)
    {
        BIND_OPTS3 bo;
        WCHAR  wszCLSID[50];
        WCHAR  wszMonikerName[300];
    
        StringFromGUID2(rclsid, wszCLSID, sizeof(wszCLSID)/sizeof(wszCLSID[0])); 
        _stprintf_s(wszMonikerName, L"Elevation:Administrator!new:%s", wszCLSID);
    
        memset(&bo, 0, sizeof(bo));
        bo.cbStruct = sizeof(bo);
        bo.hwnd = hwnd;
        bo.dwClassContext  = CLSCTX_LOCAL_SERVER;
        return CoGetObject(wszMonikerName, &bo, riid, ppv);
    }
  38. And finally, update your main() function, first initializing COM and then using our class.
  39. C++
    #include "stdafx.h"
    #include "ElevatedRegistryWritter.h"
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        CoInitialize(NULL);
    
        MessageBox(NULL, _T("Accept to elevate"), 
                   _T("Testing elevation"), MB_OK);
    
        CElevatedRegistryWritter writter(GetConsoleWindow());
        if(writter.WriteString(_T("Software\\Microsoft"), 
                _T("Message"), _T("Hello World")) && 
                writter.WriteLong(_T("Software\\Microsoft"), 
                _T("MyValue"), 100))
        {}
    
        CoUninitialize();
        return 0;
    }

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Dreaming With Objects S.L.
Spain Spain
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralHow to make this solution work on Windows XP SP3 Pin
Arjun Annam24-Oct-11 1:43
Arjun Annam24-Oct-11 1:43 
GeneralExcellent:: A Small Question Pin
vishalgpt18-Apr-11 17:53
vishalgpt18-Apr-11 17:53 
QuestionDoesnt Work in Win 7 Ultimate Pin
Rahim Jamaluddin17-Jun-10 18:19
Rahim Jamaluddin17-Jun-10 18:19 
AnswerRe: Doesnt Work in Win 7 Ultimate Pin
red_mamba2-Aug-12 3:04
red_mamba2-Aug-12 3:04 
AnswerStep 15 Pin
Stone Free14-Apr-09 5:37
Stone Free14-Apr-09 5:37 
GeneralA fine Video to this topic Pin
KarstenK8-Apr-09 21:26
mveKarstenK8-Apr-09 21:26 
I hope the guys at Channel 9 arent removing it too soon, as often Ms does change it links for some reasons: http://channel9.msdn.com/posts/jmazner/How-To-Use-Vistas-UAC-Feature-To-Avoid-Always-Requiring-Admin-Rights/[^]

The article is outstanding. I wish I would take the time to write such one, Blush | :O

Press F1 for help or google it.
Greetings from Germany

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.