SHCreatePropertyStoreOnXML

Go to Home Page

Creates a property store backed by a XML document

Syntax

HRESULT WINAPI SHCreatePropertyStoreOnXML (
    IXMLDOMNode* pXmlDomNode,
    DWORD gfrMode,
    IPropertyBag* pPropBagInit,
    REFIID riid,
    PVOID* ppv
)

Parameters

pXmlDomNode
A root node under which to start reading and writing properties. Can be NULL.
gfrMode
Can be STGM_READ, STGM_WRITE, or STGM_READWRITE to indicate whether the underlying XML is modifiable. Used only if pXmlDomNode is not NULL.
pPropBagInit
A property bag to be queried for its underlying registry key. Can be NULL.
riid
IID of the requested interface to return in *ppv
ppv
A pointer to a pointer that receives the interface represented by riid

Return Value

S_OK on success, standard COM error on failure

Remarks

The interfaces that can be queried by the riid parameter are IInitializeWithStream, IPersistPropertyBag, INamedPropertyStore and IPropertyStore along with the following undocumented interfaces:

MIDL_INTERFACE("37941AB6-DADC-47a5-8F42-3F9EE5966224")
struct IObjectWithClassIdentity : public IUnknown
{
    // returns a string identifier for the object
    // The retuned string must be freed with CoTaskMemFree when no longer needed
    virtual STDMETHODIMP GetClassIdentity(LPWSTR* ppwszIdentity) = 0;
};

MIDL_INTERFACE("482df151-d135-439a-badd-3b4b4b986caf")
struct IXMLPropertyStoreInit : public IUnknown
{
    // This method is called internally if you supply the pXMLDOMNode argument
    // It allows you you to do the same init as it does at a later time
    virtual STDMETHODIMP Initialize(IXMLDOMNode* pXMLDOMNode, DWORD grfMode) = 0;
};

To store any changes made to the property store, IPropertyStore::Commit() must be called. IPersistPropertyBag::Save() is unimplemented and returns E_FAIL. If the property store is initialized with IInitializeWithStream, the changes will be written out to that stream. Likewise if the property store is initiliazed with IXMLPropertyStoreInit or passed the pXMLDOMNode argument to the function, the changes will be written out to the nodes owning XML document.

If the pPropBagInit parameter is not NULL, it is queried for a IObjectWithRegistryKey interface. If successful the registry key it represents is saved. When reading and writing properties using IPropertyStore, the key is queried for 'VT' and 'XPath' representing the type of the property id and its XPath location in the XML document.

One of IInitializeWithStream, IXMLPropertyStoreInit, or the pXMLDOMNode parameter must be used to initialize the property store. Any attempt to read or write properties without doing this will return STGM_E_ACCESSDENIED.

If using IPropertyStore to read and write parameters, the pPropBagInit parameter, or calling IPersistPropertyBag::Load is required. If not, GetValue and SetValue will return E_FAIL.

Example

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shlwapi.h>
#include <ole2.h>
#include <msxml6.h>

#pragma comment(lib, "msxml6.lib")

typedef HRESULT (WINAPI*pfnSHCreateXMLPropStore)(IXMLDOMNode* pXmlNode, DWORD grfMode, IPropertyBag* pPropBagInit, REFIID riid, PVOID* ppv);

int main()
{
    CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

    // create an XML document
    IXMLDOMDocument2* pDoc = NULL;
    CoCreateInstance(CLSID_DOMDocument2, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&pDoc));

    // create a root node
    VARIANT nodeType;
    V_VT(&nodeType) = VT_I4;
    V_I4(&nodeType) = NODE_ELEMENT;
    IXMLDOMNode* pNode = NULL;
    pDoc->createNode(nodeType, L"MyRootNode", NULL, &pNode);

    // attach it to the document
    pDoc->appendChild(pNode, NULL);

    // get the function ptr
    HMODULE hMod = LoadLibraryW(L"shlwapi.dll");
    pfnSHCreateXMLPropStore sHCreateXMLPropStore = (pfnShell)GetProcAddress(hMod, (LPCSTR)621);

    // call the function requesting the named property store interface
    INamedPropertyStore* pProps = NULL;
    hr4 = sHCreateXMLPropStore(pNode, STGM_READWRITE, NULL, IID_PPV_ARGS(&pProps));

    // the function takes it's own reference on the node
    // so we can get rid of ours now that we no longer need it
    pNode->Release();

    // set a named property
    PROPVARIANT propVar = {0};
    propVar.vt = VT_UI4;
    propVar.uiVal = 9;
    pProps->SetNamedValue(L"MyNamedProperty", propVar);

    // get the IPropertyStore interface so we can commit (flush) the changes
    // back to the source
    IPropertyStore* pStore = NULL;
    pProps->QueryInterface(&pStore);
    pStore->Commit();

    // we no longer need the interfaces
    pStore->Release();
    pProps->Release();

    // save the xml document
    VARIANT name;
    V_VT(&name) = VT_BSTR;
    V_BSTR(&name) = L"test.xml";
    pDoc->save(name);

    // final cleanup
    pDoc->Release();
    CoUninitialize();
    return 0;
}
OUTPUT - test.xml
------
<MyRootNode>
  <MicrosoftProperties>
    <NamedProperties>
      <Property Name="MyNamedProperty" type="uint32">9</Property>
    </NamedProperties>
  </MicrosoftProperties>
</MyRootNode>

This function is also known as _SHCreatePropertyStoreOnXML@20.