* PROJECT: ReactOS Management Console
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: Helper functions for MSXML3
* COPYRIGHT: Copyright 2026 Eric Kohl (eric.kohl@reactos.org)
*/
#include "precomp.h"
#include <initguid.h>
DEFINE_GUID(CLSID_DOMDocument30, 0xf5078f32, 0xc551, 0x11d3, 0x89,0xb9, 0x00,0x00,0xf8,0x1f,0xe2,0x21);
MscFile::MscFile(PCWSTR pszFileName)
{
m_pDocument = NULL;
VariantInit(&m_varFileName);
VariantFromString(pszFileName, m_varFileName);
}
MscFile::~MscFile()
{
VariantClear(&m_varFileName);
SAFE_RELEASE(m_pDocument);
}
HRESULT
MscFile::VariantFromString(PCWSTR wszValue, VARIANT &Variant)
{
HRESULT hr = S_OK;
BSTR bstr = SysAllocString(wszValue);
CHK_ALLOC(bstr);
V_VT(&Variant) = VT_BSTR;
V_BSTR(&Variant) = bstr;
CleanUp:
return hr;
}
HRESULT
MscFile::CreateAndInitDOM()
{
HRESULT hr = CoCreateInstance(CLSID_DOMDocument30,
NULL,
CLSCTX_INPROC_SERVER,
IID_IXMLDOMDocument,
(void**)&m_pDocument);
if (SUCCEEDED(hr))
{
m_pDocument->put_async(VARIANT_FALSE);
m_pDocument->put_validateOnParse(VARIANT_FALSE);
m_pDocument->put_resolveExternals(VARIANT_FALSE);
m_pDocument->put_preserveWhiteSpace(VARIANT_TRUE);
}
return hr;
}
HRESULT
MscFile::CreateElement(PCWSTR wszName, IXMLDOMElement **ppElement)
{
HRESULT hr = S_OK;
*ppElement = NULL;
BSTR bstrName = SysAllocString(wszName);
CHK_ALLOC(bstrName);
CHK_HR(m_pDocument->createElement(bstrName, ppElement));
CleanUp:
SysFreeString(bstrName);
return hr;
}
HRESULT
MscFile::AppendChildToParent(IXMLDOMNode *pChild, IXMLDOMNode *pParent)
{
HRESULT hr = S_OK;
IXMLDOMNode *pChildOut = NULL;
if (pParent == NULL)
CHK_HR(m_pDocument->appendChild(pChild, &pChildOut));
else
CHK_HR(pParent->appendChild(pChild, &pChildOut));
CleanUp:
SAFE_RELEASE(pChildOut);
return hr;
}
HRESULT
MscFile::CreateAndAddPINode(PCWSTR wszTarget, PCWSTR wszData)
{
HRESULT hr = S_OK;
IXMLDOMProcessingInstruction *pPI = NULL;
BSTR bstrTarget = SysAllocString(wszTarget);
BSTR bstrData = SysAllocString(wszData);
CHK_ALLOC(bstrTarget && bstrData);
CHK_HR(m_pDocument->createProcessingInstruction(bstrTarget, bstrData, &pPI));
CHK_HR(AppendChildToParent(pPI, m_pDocument));
CleanUp:
SAFE_RELEASE(pPI);
SysFreeString(bstrTarget);
SysFreeString(bstrData);
return hr;
}
HRESULT MscFile::CreateAndAddCommentNode(PCWSTR wszComment)
{
HRESULT hr = S_OK;
IXMLDOMComment *pComment = NULL;
BSTR bstrComment = SysAllocString(wszComment);
CHK_ALLOC(bstrComment);
CHK_HR(m_pDocument->createComment(bstrComment, &pComment));
CHK_HR(AppendChildToParent(pComment, m_pDocument));
CleanUp:
SAFE_RELEASE(pComment);
SysFreeString(bstrComment);
return hr;
}
HRESULT MscFile::CreateAndAddAttributeNode(PCWSTR wszName, PCWSTR wszValue, IXMLDOMElement *pParent)
{
HRESULT hr = S_OK;
IXMLDOMAttribute *pAttribute = NULL;
IXMLDOMAttribute *pAttributeOut = NULL;
BSTR bstrName = NULL;
VARIANT varValue;
VariantInit(&varValue);
bstrName = SysAllocString(wszName);
CHK_ALLOC(bstrName);
CHK_HR(VariantFromString(wszValue, varValue));
CHK_HR(m_pDocument->createAttribute(bstrName, &pAttribute));
CHK_HR(pAttribute->put_value(varValue));
CHK_HR(pParent->setAttributeNode(pAttribute, &pAttributeOut));
CleanUp:
SAFE_RELEASE(pAttribute);
SAFE_RELEASE(pAttributeOut);
SysFreeString(bstrName);
VariantClear(&varValue);
return hr;
}
HRESULT MscFile::CreateAndAddTextNode(PCWSTR wszText, IXMLDOMNode *pParent)
{
HRESULT hr = S_OK;
IXMLDOMText *pText = NULL;
BSTR bstrText = SysAllocString(wszText);
CHK_ALLOC(bstrText);
CHK_HR(m_pDocument->createTextNode(bstrText, &pText));
CHK_HR(AppendChildToParent(pText, pParent));
CleanUp:
SAFE_RELEASE(pText);
SysFreeString(bstrText);
return hr;
}
HRESULT MscFile::CreateAndAddCDATANode(PCWSTR wszCDATA, IXMLDOMNode *pParent)
{
HRESULT hr = S_OK;
IXMLDOMCDATASection *pCDATA = NULL;
BSTR bstrCDATA = SysAllocString(wszCDATA);
CHK_ALLOC(bstrCDATA);
CHK_HR(m_pDocument->createCDATASection(bstrCDATA, &pCDATA));
CHK_HR(AppendChildToParent(pCDATA, pParent));
CleanUp:
SAFE_RELEASE(pCDATA);
SysFreeString(bstrCDATA);
return hr;
}
HRESULT MscFile::CreateAndAddElementNode(PCWSTR wszName, IXMLDOMNode *pParent, IXMLDOMElement **ppElement)
{
HRESULT hr = S_OK;
IXMLDOMElement* pElement = NULL;
CHK_HR(CreateElement(wszName, &pElement));
CHK_HR(AppendChildToParent(pElement, pParent));
CleanUp:
if (ppElement)
*ppElement = pElement;
else
SAFE_RELEASE(pElement);
return hr;
}
LPWSTR
MscFile::ShowCmdToString(
int nShowCmd)
{
switch (nShowCmd)
{
case SW_HIDE:
return (LPWSTR)L"SW_HIDE";
case SW_SHOWNORMAL:
return (LPWSTR)L"SW_SHOWNORMAL";
case SW_SHOWMINIMIZED:
return (LPWSTR)L"SW_SHOWMINIMIZED";
case SW_SHOWMAXIMIZED:
return (LPWSTR)L"SW_SHOWMAXIMIZED";
case SW_SHOWNOACTIVATE:
return (LPWSTR)L"SW_SHOWNOACTIVATE";
case SW_SHOW:
return (LPWSTR)L"SW_SHOW";
case SW_MINIMIZE:
return (LPWSTR)L"SW_MINIMIZE";
case SW_SHOWMINNOACTIVE:
return (LPWSTR)L"SW_SHOWMINNOACTIVE";
case SW_SHOWNA:
return (LPWSTR)L"SW_SHOWNA";
case SW_RESTORE:
return (LPWSTR)L"SW_RESTORE";
case SW_SHOWDEFAULT:
return (LPWSTR)L"SW_SHOWDEFAULT";
case SW_FORCEMINIMIZE:
return (LPWSTR)L"SW_FORCEMINIMIZE";
}
return (LPWSTR)L"-1";
}
HRESULT
MscFile::SaveWindowPlacement(CWindow *pWindow, IXMLDOMElement *pParentNode)
{
IXMLDOMElement *pWindowPlacement = NULL;
IXMLDOMElement *pPointElement = NULL;
IXMLDOMElement *pRectangleElement = NULL;
WINDOWPLACEMENT wndpl;
WCHAR szBuffer[32];
HRESULT hr = S_OK;
pWindow->GetWindowPlacement(&wndpl);
CHK_HR(CreateAndAddElementNode(L"WindowPlacement", pParentNode, &pWindowPlacement));
CHK_HR(CreateAndAddAttributeNode(L"ShowCommand", ShowCmdToString(wndpl.showCmd), pWindowPlacement));
CHK_HR(CreateAndAddElementNode(L"Point", pWindowPlacement, &pPointElement));
CHK_HR(CreateAndAddAttributeNode(L"Name", L"MinPosition", pPointElement));
_swprintf(szBuffer, L"%ld", wndpl.ptMinPosition.x);
CHK_HR(CreateAndAddAttributeNode(L"X", szBuffer, pPointElement));
_swprintf(szBuffer, L"%ld", wndpl.ptMinPosition.y);
CHK_HR(CreateAndAddAttributeNode(L"Y", szBuffer, pPointElement));
SAFE_RELEASE(pPointElement);
CHK_HR(CreateAndAddElementNode(L"Point", pWindowPlacement, &pPointElement));
CHK_HR(CreateAndAddAttributeNode(L"Name", L"MaxPosition", pPointElement));
_swprintf(szBuffer, L"%ld", wndpl.ptMaxPosition.x);
CHK_HR(CreateAndAddAttributeNode(L"X", szBuffer, pPointElement));
_swprintf(szBuffer, L"%ld", wndpl.ptMaxPosition.y);
CHK_HR(CreateAndAddAttributeNode(L"Y", szBuffer, pPointElement));
SAFE_RELEASE(pPointElement);
CHK_HR(CreateAndAddElementNode(L"Rectangle", pWindowPlacement, &pRectangleElement));
CHK_HR(CreateAndAddAttributeNode(L"Name", L"NormalPosition", pRectangleElement));
_swprintf(szBuffer, L"%ld", wndpl.rcNormalPosition.top);
CHK_HR(CreateAndAddAttributeNode(L"Top", szBuffer, pRectangleElement));
_swprintf(szBuffer, L"%ld", wndpl.rcNormalPosition.bottom);
CHK_HR(CreateAndAddAttributeNode(L"Bottom", szBuffer, pRectangleElement));
_swprintf(szBuffer, L"%ld", wndpl.rcNormalPosition.left);
CHK_HR(CreateAndAddAttributeNode(L"Left", szBuffer, pRectangleElement));
_swprintf(szBuffer, L"%ld", wndpl.rcNormalPosition.right);
CHK_HR(CreateAndAddAttributeNode(L"Right", szBuffer, pRectangleElement));
SAFE_RELEASE(pRectangleElement);
CleanUp:
SAFE_RELEASE(pWindowPlacement);
return hr;
}
HRESULT
MscFile::LoadDOM()
{
IXMLDOMParseError *pXMLErr = NULL;
BSTR bstrErr = NULL;
VARIANT_BOOL varStatus;
HRESULT hr = S_OK;
hr = m_pDocument->load(m_varFileName, &varStatus);
if (varStatus != VARIANT_TRUE)
{
CHK_HR(m_pDocument->get_parseError(&pXMLErr));
CHK_HR(pXMLErr->get_reason(&bstrErr));
}
CleanUp:
SAFE_RELEASE(pXMLErr);
SysFreeString(bstrErr);
return hr;
}
HRESULT
MscFile::SaveDOM()
{
return m_pDocument->save(m_varFileName);
}