## Marking a Control as Safe

There are two ways to make a COM object as safe for scripting and initializing—either through a component category entry in the registry, or by supporting the IObjectSafety interface.

### Component Category Registry Entry

A control can be marked as safe for scripting or initializing by adding it to the CATID_SafeForScripting and CATID_SafeForInitializing component categories in the registry, respectively. This should be done using the component category manager, which already a standard part of IE3.

#### Marking Controls As Safe

Use the following code to mark your control as SafeForScripting:

    hr = CreateComponentCategory(CATID_SafeForScripting, L"Controls that are safely scriptable");
    hr = RegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);

or this code to mark your control as SafeForInitializing:

    hr = CreateComponentCategory(CATID_SafeForInitializing, L"Controls safely initializable from persistent data");
    hr = RegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);

Both of these snippets use the helper functions below, and assume that CLSID_SafeItem contains the CLSID of the control, while CATID_SafeForInitializing and CATID_SafeForScripting are defined in objsafe.h.

#### RegisterCLSIDInCategory

This function can be used to create a component category and associated description.

    #include "comcat.h"
    HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription)
    	{

        ICatRegister* pcr = NULL ;
        HRESULT hr = S_OK ;

        hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
    			NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
    	if (FAILED(hr))
    		return hr;

        // Make sure the HKCR\Component Categories\{..catid...}
        // key is registered
        CATEGORYINFO catinfo;
        catinfo.catid = catid;
        catinfo.lcid = 0x0409 ; // english

    	// Make sure the provided description is not too long.
    	// Only copy the first 127 characters if it is
    	int len = wcslen(catDescription);
    	if (len>127)
    		len = 127;
        wcsncpy(catinfo.szDescription, catDescription, len);
    	// Make sure the description is null terminated
    	catinfo.szDescription[len] = '\0';

        hr = pcr->RegisterCategories(1, &catinfo);
    	pcr->Release();

    	return hr;
    	}

#### RegisterCLSIDInCategory

This function can be used to register a CLSID as belonging to a component category.

    #include "comcat.h"
    HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
    	{
    // Register your component categories information.
        ICatRegister* pcr = NULL ;
        HRESULT hr = S_OK ;
        hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
    			NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
        if (SUCCEEDED(hr))
        {
           // Register this category as being "implemented" by
           // the class.
           CATID rgcatid[1] ;
           rgcatid[0] = catid;
           hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid);
        }

        if (pcr != NULL)
            pcr->Release();

    	return hr;
    	}

#### UnRegisterCLSIDInCategory

This function can be used to unregister a CLSID as belonging to a component category.

    #include "comcat.h"
    HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
    	{
        ICatRegister* pcr = NULL ;
        HRESULT hr = S_OK ;
        hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
    			NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
        if (SUCCEEDED(hr))
        {
           // Unregister this category as being "implemented" by
           // the class.
           CATID rgcatid[1] ;
           rgcatid[0] = catid;
           hr = pcr->UnRegisterClassImplCategories(clsid, 1, rgcatid);
        }

        if (pcr != NULL)
            pcr->Release();

    	return hr;
    	}

Calls to these snippets should be inserted in your DLL registration and unregistration routines.

### IObjectSafety

The IObjectSafety interface is an interface that allows an object user to ask the object to make itself safe, or to ask the current safety of the object, with regards to various capabilities on the object. The current defined capabilites are INTERFACESAFE_FOR_UNTRUSTED_CALLER and INTERFACESAFE_FOR_UNTRUSTED_DATA, corresponding the "Safe for Scripting" and "Safe for Initializing", but the design allows us to later define other capabilities.

The interface is as follows.

    // Option bit definitions for IObjectSafety:
    #define	INTERFACESAFE_FOR_UNTRUSTED_CALLER	0x00000001	// Caller of interface may be untrusted
    #define	INTERFACESAFE_FOR_UNTRUSTED_DATA	0x00000002	// Data passed into interface may be untrusted

    // {CB5BDC81-93C1-11cf-8F20-00805F2CD064}
    DEFINE_GUID(IID_IObjectSafety, 0xcb5bdc81, 0x93c1, 0x11cf, 0x8f, 0x20, 0x0, 0x80, 0x5f, 0x2c, 0xd0, 0x64);

    interface IObjectSafety : public IUnknown
        {
        public:
            virtual HRESULT __stdcall GetInterfaceSafetyOptions(
                /* [in] */ REFIID riid,
                /* [out] */ DWORD __RPC_FAR *pdwSupportedOptions,
                /* [out] */ DWORD __RPC_FAR *pdwEnabledOptions) = 0;

            virtual HRESULT __stdcall SetInterfaceSafetyOptions(
                /* [in] */ REFIID riid,
                /* [in] */ DWORD dwOptionSetMask,
                /* [in] */ DWORD dwEnabledOptions) = 0;

        };

#### SetInterfaceSafetyOptions

    HRESULT SetInterfaceSafetyOptions(
                /* [in] */ REFIID riid,
                /* [in] */ DWORD dwOptionSetMask,
                /* [in] */ DWORD dwEnabledOptions);

The SetInterfaceSafetyOptions function makes an object safe for initialization or scripting.

- If the function is successful, it returns S_OK. If the argument riid specifies an interface that is unknown to the object, this function returns E_NOINTERFACE. If the dwOptionSetMask specifies an option that is not supported by the object, this function returns E_FAIL.

riid
  Specifies the interface ID for the object to be made safe.
dwOptionSetMask
  Specifies the options to be changed.
dwEnabledOptions
  Specifies the settings for the options that are to be changed. This argument can be one of the following values:

  Value | Meaning
  INTERFACESAFE_FOR_UNTRUSTED_CALLER | Specifies that the interface identified by riid should be made safe for scripting.
  INTERFACESAFE_FOR_UNTRUSTED_DATA | Specifies that the interface identified by riid should be made safe for untrusted data during initialization.

Typically, a control client would call SetInterfaceSafetyOptions before attempting to script or initialize the object, to attempt to require that the object is safe for the desired action. If SetInterfaceSafetyOptions returns failure, it client will display UI to the user to confirm whether the action should be allowed.

SetInterfaceOptions takes an interface (either IDispatch for scripting or IPersist* for initialization), a bitmask of options to change (dwOptionSetMask) and the new settings for those options (dwEnabledOptions). The currently supported capabilities are, as described above, INTERFACESAFE_FOR_UNTRUSTED_CALLER and INTERFACESAFE_FOR_UNTRUSTED_DATA.

#### GetInterfaceSafetyOptions

    HRESULT  GetInterfaceSafetyOptions(
                /* [in] */ REFIID riid,
                /* [out] */ DWORD __RPC_FAR *pdwSupportedOptions,
                /* [out] */ DWORD __RPC_FAR *pdwEnabledOptions);

The GetInterfaceSafetyOptions function retrieves the safety options supported by an object as well as the safety options that are currently set for that object.

- TBD.

riid
  Specifies the interface ID for a given object.
pdwSupportedOptions
  Specifies the options supported for the interface identified by riid.
pdwEnabledOptions
  Specifies the options currently enabled for the interace identified by riid.

GetInterfaceSafetyOptions returns a set of bits in pdwSupportedOptions for each capability that the control knows about, and a set of bits in pdwEnabledOptions for each capability for which the control is currently safe.

For example, my control might say that it knows about INTERFACESAFE_FOR_UNTRUSTED_DATA and INTERFACESAFE_FOR_UNTRUSTED_CALLER, and is currently safe for just INTERFACESAFE_FOR_UNTRUSTED_DATA.

© 1996 Microsoft Corporation