#include #include #include #include #include #include "list.h" #include "manifestnode.h" #include "xmlutil.h" #include "version.h" #define ASSEMBLY L"assembly" #define NAMESPACE_TITLE L"xmlns:asm_namespace_v1" #define NAMESPACE_VALUE L"urn:schemas-microsoft-com:asm.v1" #define MANIFEST_VERSION_TITLE L"manifestVersion" #define MANIFEST_VERSION_VALUE L"1.0" #define DESCRIPTION L"description" #define ASSEMBLY_IDENTITY L"assemblyIdentity" #define DEPENDENCY L"dependency" #define DEPENDENCY_QUERY L"/assembly/dependency" #define DEPENDANT_ASSEMBLY L"dependentAssembly" #define INSTALL L"install" #define CODEBASE L"codebase" #define APPLICATION L"application" #define SHELL_STATE L"shellState" #define ACTIVATION L"activation" #define FILE L"file" #define FILE_NAME L"name" #define FILE_HASH L"hash" class __declspec(uuid("f6d90f11-9c73-11d3-b32e-00c04f990bb4")) private_MSXML_DOMDocument30; #define HASHLENGTH 32 #define HASHSTRINGLENGTH HASHLENGTH+1 ///////////////////////////////////////////////////////////////////////// // FowardSlash ///////////////////////////////////////////////////////////////////////// VOID FowardSlash(LPWSTR pwz) { LPWSTR ptr = pwz; while (*ptr) { if (*ptr == L'\\') *ptr = L'/'; ptr++; } } ///////////////////////////////////////////////////////////////////////// // GetHash ///////////////////////////////////////////////////////////////////////// HRESULT GetHash(LPCWSTR pwzFilename, LPWSTR *ppwzHash) { HRESULT hr = S_OK; HANDLE hFile = INVALID_HANDLE_VALUE; DWORD dwLength = 0; // cblength LPWSTR pwzHash = new WCHAR[HASHSTRINGLENGTH]; // BUGBUG - heap allocate large buffers like this. unsigned char buffer[16384]; MD5_CTX md5c; int i; WCHAR* p; if(!pwzHash) { hr = E_OUTOFMEMORY; goto exit; } MD5Init(&md5c); hFile = CreateFile(pwzFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) { hr = HRESULT_FROM_WIN32(GetLastError()); printf("Open file error during hashing\n"); goto exit; } ZeroMemory(buffer, sizeof(buffer)); // BUGBUG - error checking here. while(ReadFile(hFile, buffer, sizeof(buffer), &dwLength, NULL) && dwLength) MD5Update(&md5c, buffer, (unsigned) dwLength); CloseHandle(hFile); MD5Final(&md5c); // convert hash from byte array to hex p = pwzHash; for (int i = 0; i < sizeof(md5c.digest); i++) { wsprintf(p, L"%02X", md5c.digest[i]); p += 2; } *ppwzHash = pwzHash; pwzHash = NULL; exit: SAFEDELETEARRAY(pwzHash); return hr; } ///////////////////////////////////////////////////////////////////////// // CreateXMLElement ///////////////////////////////////////////////////////////////////////// HRESULT CreateXMLTextNode(IXMLDOMDocument2 *pXMLDoc, LPWSTR pwzText, IXMLDOMNode **ppNode) { HRESULT hr = S_OK; IXMLDOMNode *pNode = NULL; BSTR bstrText = NULL; bstrText = ::SysAllocString(pwzText); if (!bstrText) { hr = E_OUTOFMEMORY; goto exit; } if(FAILED(pXMLDoc->createTextNode(bstrText, (IXMLDOMText**)&pNode))) goto exit; *ppNode = pNode; (*ppNode)->AddRef(); exit: if (bstrText) ::SysFreeString(bstrText); SAFERELEASE (pNode); return hr; } ///////////////////////////////////////////////////////////////////////// // CreateXMLComment ///////////////////////////////////////////////////////////////////////// HRESULT CreateXMLComment(IXMLDOMDocument2 *pXMLDoc, LPWSTR pwzComment, IXMLDOMComment **ppComment) { HRESULT hr=S_OK; BSTR bstrComment = NULL; IXMLDOMComment *pComment = NULL; bstrComment = ::SysAllocString(pwzComment); if (!bstrComment) { hr = E_OUTOFMEMORY; goto exit; } if(FAILED(hr = pXMLDoc->createComment(bstrComment, &pComment))) goto exit; *ppComment = pComment; (*ppComment)->AddRef(); exit: if (bstrComment) ::SysFreeString(bstrComment); SAFERELEASE(pComment); return hr; } ///////////////////////////////////////////////////////////////////////// // AddMgVersionAsComment ///////////////////////////////////////////////////////////////////////// HRESULT AddMgVersionAsComment(IXMLDOMDocument2 *pXMLDoc, IXMLDOMNode **ppRoot) { HRESULT hr = S_OK; CString sComment; IXMLDOMComment *pComment = NULL; IXMLDOMNode *pNewNode = NULL; // ASSERT(pXMLDoc && ppRoot); sComment.Assign(L"Created using mg version "); sComment.Append(VER_PRODUCTVERSION_STR_L); if(FAILED(hr = CreateXMLComment(pXMLDoc, sComment._pwz, &pComment))) goto exit; if(*ppRoot) { if (FAILED(hr = (*ppRoot)->appendChild((IXMLDOMNode *)pComment, &pNewNode))) goto exit; } else { if (FAILED(hr = pXMLDoc->appendChild((IXMLDOMNode *)pComment, ppRoot))) goto exit; } exit: SAFERELEASE(pNewNode); SAFERELEASE(pComment); return hr; } ///////////////////////////////////////////////////////////////////////// // CreateXMLElement ///////////////////////////////////////////////////////////////////////// HRESULT CreateXMLElement(IXMLDOMDocument2 *pXMLDoc, LPWSTR pwzElementName, IXMLDOMElement **ppElement) { HRESULT hr=S_OK; BSTR bstrElementName = NULL; IXMLDOMElement *pElement = NULL; IXMLDOMNode *pNode =NULL, *pNewNode = NULL; bstrElementName = ::SysAllocString(pwzElementName); if (!bstrElementName) { hr = E_OUTOFMEMORY; goto exit; } // NOTENOTE - createElement doesn't append the node to the doc // so we're just using pXMLDoc for convenience of calling create. if(FAILED(hr = pXMLDoc->createElement(bstrElementName, &pElement))) goto exit; *ppElement = pElement; (*ppElement)->AddRef(); exit: if (bstrElementName) ::SysFreeString(bstrElementName); SAFERELEASE(pNode); SAFERELEASE(pNewNode); SAFERELEASE(pElement); return hr; } ///////////////////////////////////////////////////////////////////////// // SetXMLElementAttribute ///////////////////////////////////////////////////////////////////////// HRESULT SetXMLElementAttribute(IXMLDOMElement *pElement, LPWSTR pwzAttributeName, LPWSTR pwzAttributeValue) { HRESULT hr=S_OK; BSTR bstrAttributeName = NULL, bstrAttributeValue = NULL; VARIANT varAttributeValue; bstrAttributeName = ::SysAllocString(pwzAttributeName); bstrAttributeValue = ::SysAllocString(pwzAttributeValue); if (!bstrAttributeName || (!bstrAttributeValue && pwzAttributeValue)) { hr = E_OUTOFMEMORY; goto exit; } VariantInit(&varAttributeValue); varAttributeValue.vt = VT_BSTR; V_BSTR(&varAttributeValue) = bstrAttributeValue; hr = pElement->setAttribute(bstrAttributeName, varAttributeValue); exit: if (bstrAttributeName) ::SysFreeString(bstrAttributeName); if (bstrAttributeValue) ::SysFreeString(bstrAttributeValue); return hr; } ///////////////////////////////////////////////////////////////////////// // CreateXMLAssemblyIdElement ///////////////////////////////////////////////////////////////////////// HRESULT CreateXMLAssemblyIdElement(IXMLDOMDocument2 *pXMLDoc, IAssemblyIdentity *pAssemblyId, IXMLDOMElement **ppElement) { HRESULT hr = S_OK; IXMLDOMElement *pASMIdElement = NULL; LPWSTR pwzBuf = NULL; DWORD ccBuf = 0; CString sBuffer; LPWSTR rpwzAttrNames[6] = { SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_TYPE, SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME, SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_VERSION, SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PUBLIC_KEY_TOKEN, SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PROCESSOR_ARCHITECTURE, SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_LANGUAGE, }; //Create assemblyIdentity Element if(FAILED(hr=CreateXMLElement(pXMLDoc, ASSEMBLY_IDENTITY, &pASMIdElement))) goto exit; for (int i = 0; i < 6; i++) { // BUGBUG - eventually, when we add support for type the only guy which // is optional is the public key token. if (FAILED(hr = pAssemblyId->GetAttribute(rpwzAttrNames[i], &pwzBuf, &ccBuf)) && hr != HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) goto exit; else if (hr == S_OK) { sBuffer.TakeOwnership(pwzBuf, ccBuf); hr = SetXMLElementAttribute(pASMIdElement, rpwzAttrNames[i], sBuffer._pwz); } else hr = S_OK; } *ppElement = pASMIdElement; (*ppElement)->AddRef(); exit: SAFERELEASE(pASMIdElement); return hr; } ///////////////////////////////////////////////////////////////////////// // CreateDependantAssemblyNode ///////////////////////////////////////////////////////////////////////// HRESULT CreateDependantAssemblyNode(IXMLDOMDocument2 *pXMLDoc, ManifestNode*pManifestNode, IXMLDOMNode **ppDependantAssemblyNode) { HRESULT hr = S_OK; LPWSTR pwzBuf = NULL; DWORD dwType; IAssemblyIdentity *pAssemblyId = NULL; IXMLDOMElement *pDependantAssemblyNode = NULL, *pElement = NULL; IXMLDOMNode *pNewNode = NULL; CString sCodeBase; //Get ASMId for Unique Dependency if(FAILED(hr = pManifestNode->GetAssemblyIdentity(&pAssemblyId))) goto exit; //Get the type of manifest // - Private or GAC, for GACs you don't put the codebase. if(FAILED(hr = pManifestNode->GetManifestType(&dwType))) goto exit; //Get Codebase of the Unique Dependancy if(FAILED(hr = pManifestNode->GetManifestFilePath(&pwzBuf))) goto exit; sCodeBase.TakeOwnership(pwzBuf); //Create a dependentAssembly node if(FAILED(hr = CreateXMLElement(pXMLDoc, DEPENDANT_ASSEMBLY, &pDependantAssemblyNode))) goto exit; //Create the AssemblyId for the Dependant Assembly if (FAILED(CreateXMLAssemblyIdElement(pXMLDoc, pAssemblyId, &pElement))) goto exit; if (FAILED(hr=pDependantAssemblyNode->appendChild((IXMLDOMNode *)pElement, &pNewNode))) goto exit; // Node is added and element, node can be released. SAFERELEASE(pElement); SAFERELEASE(pNewNode); //read the codebase for this DependantAssembly // GACs don't have a codebase. if (1) // we need codebase for all assemblies (dwType == PRIVATE_ASSEMBLY) { if(FAILED(hr = CreateXMLElement(pXMLDoc, INSTALL, &pElement))) goto exit; FowardSlash(sCodeBase._pwz); if(FAILED(hr = SetXMLElementAttribute(pElement, CODEBASE, sCodeBase._pwz))) goto exit; if (FAILED(hr=pDependantAssemblyNode->appendChild((IXMLDOMNode *)pElement, &pNewNode))) goto exit; SAFERELEASE(pElement); SAFERELEASE(pNewNode); } *ppDependantAssemblyNode = pDependantAssemblyNode; (*ppDependantAssemblyNode)->AddRef(); exit: SAFERELEASE(pAssemblyId); SAFERELEASE(pDependantAssemblyNode); return hr; } ///////////////////////////////////////////////////////////////////////// // GetNode ///////////////////////////////////////////////////////////////////////// HRESULT GetNode(IXMLDOMDocument2 *pXMLDoc, LPCWSTR pwzNode, IXMLDOMNode **ppNode) { HRESULT hr = S_OK; BSTR bstrtQueryString; IXMLDOMNode *pNode=NULL; IXMLDOMNodeList *pNodeList = NULL; LONG nNodes = 0; bstrtQueryString = ::SysAllocString(pwzNode); if (!bstrtQueryString) { hr = E_OUTOFMEMORY; goto exit; } if ((hr = pXMLDoc->selectNodes(bstrtQueryString, &pNodeList)) != S_OK) goto exit; // NOTENOTE - nNodes > 1 should never happen because only one root node in doc. hr = pNodeList->get_length(&nNodes); if (nNodes > 1) { // multiple file callouts having the exact same file name/path within a single source assembly hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT); goto exit; } else if (nNodes < 1) { hr = S_FALSE; goto exit; } if ((hr = pNodeList->get_item(0, &pNode)) != S_OK) { hr = S_FALSE ? E_FAIL : hr; goto exit; } *ppNode=pNode; (*ppNode)->AddRef(); exit: if(bstrtQueryString) ::SysFreeString(bstrtQueryString); SAFERELEASE(pNodeList); SAFERELEASE(pNode); return hr; } ///////////////////////////////////////////////////////////////////////// // FormatXML // Called recursively. // BUGBUG - t-peterf to document why selectNodes should not be used when // adding nodes to an existing document. ///////////////////////////////////////////////////////////////////////// HRESULT FormatXML(IXMLDOMDocument2 *pXMLDoc, IXMLDOMNode *pRootNode, LONG dwLevel) { HRESULT hr = S_OK; IXMLDOMNode *pNode=NULL, *pNewNode=NULL; IXMLDOMNode *pTextNode1=NULL, *pTextNode2=NULL; CString sWhiteSpace1, sWhiteSpace2; BOOL bHasChildren = FALSE; int i = 0; sWhiteSpace1.Assign(L"\n"); for (i = 0; i < (dwLevel-1); i++) sWhiteSpace1.Append(L"\t"); sWhiteSpace2.Assign(L"\n"); for (i = 0; i < dwLevel; i++) sWhiteSpace2.Append(L"\t"); hr = pRootNode->get_firstChild(&pNode); while(pNode != NULL) { bHasChildren = TRUE; // create whitespace with one extra tab. if(FAILED(CreateXMLTextNode(pXMLDoc, sWhiteSpace2._pwz, &pTextNode2))) goto exit; VARIANT varRefNode; VariantInit(&varRefNode); varRefNode.vt = VT_UNKNOWN; V_UNKNOWN(&varRefNode) = pNode; if (FAILED(hr = pRootNode->insertBefore(pTextNode2, varRefNode, &pNewNode))) goto exit; SAFERELEASE(pNewNode); SAFERELEASE(pTextNode2); // Recursively call format on the node. if (FAILED(FormatXML(pXMLDoc, pNode, dwLevel+1))) goto exit; pNode->get_nextSibling(&pNewNode); SAFERELEASE(pNode); pNode = pNewNode; } if (bHasChildren) { if(FAILED(CreateXMLTextNode(pXMLDoc, sWhiteSpace1._pwz, &pTextNode1))) goto exit; if (FAILED(hr = pRootNode->appendChild(pTextNode1, &pNewNode))) goto exit; } exit: return hr; } ///////////////////////////////////////////////////////////////////////// // CreateManifestFromAssembly ///////////////////////////////////////////////////////////////////////// HRESULT CreateAppManifestTemplate(LPWSTR pwzTempFile) { HRESULT hr=S_OK; IXMLDOMDocument2 *pXMLDoc = NULL; IXMLDOMElement *pElement=NULL, *pChildElement=NULL, *pChildElement2=NULL, *pChildElement3=NULL; IXMLDOMNode *pNewNode=NULL, *pRoot=NULL, *pTextNode = NULL; if(FAILED(hr = CoCreateInstance(__uuidof(private_MSXML_DOMDocument30), NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument2, (void**)&pXMLDoc))) goto exit; /* if(FAILED(hr = AddMgVersionAsComment(pXMLDoc, &pRoot))) goto exit; */ //create the root assembly node and add the default properties if(FAILED(hr = CreateXMLElement(pXMLDoc, ASSEMBLY, &pElement))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pElement, NAMESPACE_TITLE, NAMESPACE_VALUE))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pElement, MANIFEST_VERSION_TITLE, MANIFEST_VERSION_VALUE))) goto exit; //append the root to the DOMDocument if (FAILED(hr = pXMLDoc->appendChild((IXMLDOMNode *)pElement, &pRoot))) goto exit; SAFERELEASE(pElement); //create the tempate assemblyIdentity node with blank attributes if(FAILED(hr = CreateXMLElement(pXMLDoc, ASSEMBLY_IDENTITY, &pElement))) goto exit; hr = SetXMLElementAttribute(pElement, L"type", L"application"); hr = SetXMLElementAttribute(pElement, L"name", L""); hr = SetXMLElementAttribute(pElement, L"version", L""); hr = SetXMLElementAttribute(pElement, L"processorArchitecture", L""); hr = SetXMLElementAttribute(pElement, L"publicKeyToken", L""); hr = SetXMLElementAttribute(pElement, L"language", L""); //append this to the root node if (FAILED(hr=pRoot->appendChild((IXMLDOMNode *)pElement, &pNewNode))) goto exit; SAFERELEASE(pElement); SAFERELEASE(pNewNode); //create a sample description if(FAILED(hr = CreateXMLElement(pXMLDoc, DESCRIPTION, &pElement))) goto exit; if(FAILED(hr = CreateXMLTextNode(pXMLDoc, L"Put a description of your application here", &pTextNode))) goto exit; if (FAILED(hr=pElement->appendChild(pTextNode, &pNewNode))) goto exit; SAFERELEASE(pNewNode); SAFERELEASE(pTextNode); if (FAILED(hr=pRoot->appendChild((IXMLDOMNode *)pElement, &pNewNode))) goto exit; SAFERELEASE(pNewNode); SAFERELEASE(pElement); //Create the shellState tag and enter in default information if(FAILED(hr = CreateXMLElement(pXMLDoc, APPLICATION, &pElement))) goto exit; if(FAILED(hr = CreateXMLElement(pXMLDoc, SHELL_STATE, &pChildElement))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement, L"friendlyName", L""))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement, L"entryPoint", L""))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement, L"entryImageType", L""))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement, L"showCommand", L""))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement, L"hotKey", L""))) goto exit; if (FAILED(hr=pElement->appendChild((IXMLDOMNode *)pChildElement, &pNewNode))) goto exit; SAFERELEASE (pNewNode); SAFERELEASE(pChildElement); if(FAILED(hr = CreateXMLElement(pXMLDoc, ACTIVATION, &pChildElement))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement, L"assemblyName", L""))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement, L"assemblyClass", L""))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement, L"assemblyMethod", L""))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement, L"assemblyMethodArgs", L""))) goto exit; if (FAILED(hr=pElement->appendChild((IXMLDOMNode *)pChildElement, &pNewNode))) goto exit; SAFERELEASE (pNewNode); SAFERELEASE(pChildElement); if (FAILED(hr=pRoot->appendChild((IXMLDOMNode *)pElement, &pNewNode))) goto exit; SAFERELEASE(pElement); SAFERELEASE (pNewNode); //Create the dependency platform tag and enter in default information if(FAILED(hr = CreateXMLElement(pXMLDoc, L"dependency", &pElement))) goto exit; if(FAILED(hr = CreateXMLElement(pXMLDoc, L"platform", &pChildElement))) goto exit; if(FAILED(hr = CreateXMLElement(pXMLDoc, L"osVersionInfo", &pChildElement2))) goto exit; if(FAILED(hr = CreateXMLElement(pXMLDoc, L"os", &pChildElement3))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement3, L"majorVersion", L"5"))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement3, L"minorVersion", L"1"))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement3, L"buildNumber", L"2600"))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement3, L"servicePackMajor", L"0"))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement3, L"servicePackMinor", L"0"))) goto exit; if (FAILED(hr=pChildElement2->appendChild((IXMLDOMNode *)pChildElement3, NULL))) goto exit; SAFERELEASE (pChildElement3); if (FAILED(hr=pChildElement->appendChild((IXMLDOMNode *)pChildElement2, NULL))) goto exit; SAFERELEASE (pChildElement2); if(FAILED(hr = CreateXMLElement(pXMLDoc, L"platformInfo", &pChildElement2))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement2, L"friendlyName", L"Microsoft Windows XP"))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement2, L"href", L"http://www.microsoft.com/windows"))) goto exit; if (FAILED(hr=pChildElement->appendChild((IXMLDOMNode *)pChildElement2, NULL))) goto exit; SAFERELEASE (pChildElement2); if (FAILED(hr=pElement->appendChild((IXMLDOMNode *)pChildElement, NULL))) goto exit; SAFERELEASE(pChildElement); if(FAILED(hr = CreateXMLElement(pXMLDoc, L"platform", &pChildElement))) goto exit; if(FAILED(hr = CreateXMLElement(pXMLDoc, L"dotNetVersionInfo", &pChildElement2))) goto exit; if(FAILED(hr = CreateXMLElement(pXMLDoc, L"supportedRuntime", &pChildElement3))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement3, L"version", L"v1.0.3705"))) goto exit; if (FAILED(hr=pChildElement2->appendChild((IXMLDOMNode *)pChildElement3, NULL))) goto exit; SAFERELEASE (pChildElement3); if (FAILED(hr=pChildElement->appendChild((IXMLDOMNode *)pChildElement2, NULL))) goto exit; SAFERELEASE (pChildElement2); if(FAILED(hr = CreateXMLElement(pXMLDoc, L"platformInfo", &pChildElement2))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement2, L"friendlyName", L"Microsoft .Net Frameworks"))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pChildElement2, L"href", L"http://www.microsoft.com/net"))) goto exit; if (FAILED(hr=pChildElement->appendChild((IXMLDOMNode *)pChildElement2, NULL))) goto exit; SAFERELEASE (pChildElement2); if (FAILED(hr=pElement->appendChild((IXMLDOMNode *)pChildElement, NULL))) goto exit; SAFERELEASE(pChildElement); if (FAILED(hr=pRoot->appendChild((IXMLDOMNode *)pElement, NULL))) goto exit; SAFERELEASE(pElement); //Format and save the document if(FAILED(hr = FormatXML(pXMLDoc, pRoot, 1))) goto exit; if(FAILED(hr = SaveXMLDocument(pXMLDoc, pwzTempFile))) goto exit; printf("\nTemplate file created succesfully\n%ws\n", pwzTempFile); exit: SAFERELEASE(pXMLDoc); SAFERELEASE(pElement); SAFERELEASE(pChildElement3); SAFERELEASE(pChildElement2); SAFERELEASE(pChildElement); SAFERELEASE(pNewNode); SAFERELEASE(pTextNode); SAFERELEASE(pRoot); return hr; } ///////////////////////////////////////////////////////////////////////// // CreateSubscriptionManifest ///////////////////////////////////////////////////////////////////////// HRESULT CreateXMLSubscriptionManifest(LPWSTR pwzSubscriptionPath, IAssemblyIdentity *pApplictionAssemblyId, LPWSTR pwzUrl, LPWSTR pwzPollingInterval) { HRESULT hr=S_OK; IXMLDOMDocument2 *pXMLDoc = NULL; IXMLDOMElement *pElement=NULL, *pChildElement=NULL, *pDependantAssemblyNode=NULL; IXMLDOMNode *pNewNode=NULL, *pRoot=NULL, *pTextNode = NULL, *pDependancyNode = NULL; CString sSubscriptionPath, sSubscriptionName; sSubscriptionPath.Assign(pwzSubscriptionPath); sSubscriptionPath.LastElement(sSubscriptionName); sSubscriptionPath.Append(L".manifest"); if(FAILED(hr = CoCreateInstance(__uuidof(private_MSXML_DOMDocument30), NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument2, (void**)&pXMLDoc))) goto exit; if(FAILED(hr = AddMgVersionAsComment(pXMLDoc, &pRoot))) goto exit; //create the root assembly node and add the default properties if(FAILED(hr = CreateXMLElement(pXMLDoc, ASSEMBLY, &pElement))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pElement, NAMESPACE_TITLE, NAMESPACE_VALUE))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pElement, MANIFEST_VERSION_TITLE, MANIFEST_VERSION_VALUE))) goto exit; //append the root to the DOMDocument if (FAILED(hr = pXMLDoc->appendChild((IXMLDOMNode *)pElement, &pRoot))) goto exit; SAFERELEASE(pElement); //Create the AssemblyId for the Subscription //Use the AssemblyId of the application, but change the name and type if (FAILED(CreateXMLAssemblyIdElement(pXMLDoc, pApplictionAssemblyId, &pElement))) goto exit; // bugbug - check return code for consistency. hr = SetXMLElementAttribute(pElement, L"type", L"subscription"); hr = SetXMLElementAttribute(pElement, L"name", sSubscriptionName._pwz); if (FAILED(hr=pRoot->appendChild((IXMLDOMNode *)pElement, &pNewNode))) goto exit; SAFERELEASE(pElement); SAFERELEASE(pNewNode); //create a sample description //bugbug, should grab description for original manifest and paste it here if(FAILED(hr = CreateXMLElement(pXMLDoc, L"description", &pElement))) goto exit; if(FAILED(hr = CreateXMLTextNode(pXMLDoc, L"Put a description of your application here", &pTextNode))) goto exit; if (FAILED(hr=pElement->appendChild(pTextNode, &pNewNode))) goto exit; SAFERELEASE(pNewNode); SAFERELEASE(pTextNode); if (FAILED(hr=pRoot->appendChild((IXMLDOMNode *)pElement, &pNewNode))) goto exit; SAFERELEASE(pNewNode); SAFERELEASE(pElement); //Create the Dependancy Node if(FAILED(hr = CreateXMLElement(pXMLDoc, DEPENDENCY, &pElement))) goto exit; if (FAILED(hr=pRoot->appendChild((IXMLDOMNode *)pElement, &pDependancyNode))) goto exit; SAFERELEASE(pElement); //Create a dependentAssembly node if(FAILED(hr = CreateXMLElement(pXMLDoc, DEPENDANT_ASSEMBLY, &pDependantAssemblyNode))) goto exit; //Create the AssemblyId for the Dependant Assembly if (FAILED(CreateXMLAssemblyIdElement(pXMLDoc, pApplictionAssemblyId, &pElement))) goto exit; //Append the AssemblyId to the dependantAssemblyNode if (FAILED(hr=pDependantAssemblyNode->appendChild((IXMLDOMNode *)pElement, &pNewNode))) goto exit; SAFERELEASE(pElement); SAFERELEASE(pNewNode); //Add the install codebase to the dependantAssemblyNode if(FAILED(hr = CreateXMLElement(pXMLDoc, INSTALL, &pElement))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pElement, CODEBASE, pwzUrl))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pElement, L"type", L"required"))) goto exit; if (FAILED(hr=pDependantAssemblyNode->appendChild((IXMLDOMNode *)pElement, &pNewNode))) goto exit; SAFERELEASE(pElement); SAFERELEASE(pNewNode); //Add the install codebase to the dependantAssemblyNode if(FAILED(hr = CreateXMLElement(pXMLDoc, L"subscription", &pElement))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pElement, L"synchronizeInterval", pwzPollingInterval))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pElement, L"intervalUnit", L"hours"))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pElement, L"synchronizeEvent", L"onApplicationStartup"))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pElement, L"eventDemandConnection", L"no"))) goto exit; if (FAILED(hr=pDependantAssemblyNode->appendChild((IXMLDOMNode *)pElement, &pNewNode))) goto exit; SAFERELEASE(pElement); SAFERELEASE(pNewNode); //Append the dependantAssemblyNode to the dependancy node if (FAILED(hr=pDependancyNode->appendChild(pDependantAssemblyNode, &pNewNode))) goto exit; SAFERELEASE(pDependantAssemblyNode); SAFERELEASE(pNewNode); //Format and save the document hr = FormatXML(pXMLDoc, pRoot, 1); if(FAILED(hr = SaveXMLDocument(pXMLDoc, sSubscriptionPath._pwz))) goto exit; printf("Subscription manifest succesfully created\n%ws\n", sSubscriptionPath._pwz); exit: SAFERELEASE(pXMLDoc); SAFERELEASE(pElement); SAFERELEASE(pChildElement); SAFERELEASE(pNewNode); SAFERELEASE(pTextNode); SAFERELEASE(pRoot); SAFERELEASE(pDependancyNode); SAFERELEASE(pDependantAssemblyNode); return hr; } ///////////////////////////////////////////////////////////////////////// // CreateXMLAppManifest // Creates the app manifest - may want to rename. ///////////////////////////////////////////////////////////////////////// // NOTENOTE: rename pList -> pAsmList ? HRESULT CreateXMLAppManifest(LPWSTR pwzAppBase, LPWSTR pwzTemplateFilePath, List *pList, List *pFileList) { HRESULT hr = S_OK; DWORD cc = 0, cb = 0, ccName = 0; LPWSTR pwz=NULL, pwzCodeBase = NULL, pwzName = NULL; IAssemblyIdentity *pASMId= NULL; IXMLDOMDocument2 *pXMLDoc=NULL; IXMLDOMElement *pElement=NULL, *pAssemblyIdElement = NULL; IXMLDOMNode *pRoot=NULL, *pDependancyNode = NULL, *pNewNode = NULL; IXMLDOMNode *pAssemblyIdNode = NULL, *pDependantAssemblyNode=NULL; BSTR bstrAttribute = NULL; VARIANT varAttribute; ManifestNode *pManNode = NULL; CString sAppName, sFileName, sFileHash, sAbsoluteFilePath, sManifestFilePath; LISTNODE pos = NULL; VariantInit(&varAttribute); //Load the template if(FAILED(hr = LoadXMLDocument(pwzTemplateFilePath, &pXMLDoc))) goto exit; //grab the first child(the only child) as the root node if(FAILED(hr = GetNode(pXMLDoc, ASSEMBLY, &pRoot))) goto exit; if (hr == S_FALSE) { hr = E_INVALIDARG; goto exit; } //Get the name from the assemblyId, this will be the manifests file name if(FAILED(hr = pRoot->get_firstChild(&pAssemblyIdNode))) goto exit; //Query for the Element interface if (FAILED(hr = pAssemblyIdNode->QueryInterface(IID_IXMLDOMElement, (void**) &pAssemblyIdElement))) goto exit; bstrAttribute = ::SysAllocString(L"name"); if (!bstrAttribute) { hr = E_OUTOFMEMORY; goto exit; } if ((hr = pAssemblyIdElement->getAttribute(bstrAttribute, &varAttribute)) != S_OK) goto exit; ccName = ::SysStringLen(varAttribute.bstrVal) + 1; pwzName = new WCHAR[ccName]; if (!pwzName) { hr = E_OUTOFMEMORY; goto exit; } memcpy(pwzName, varAttribute.bstrVal, ccName * sizeof(WCHAR)); if((*pwzName)== NULL) { hr = E_FAIL; printf("Invalid Template Format. Template must have a name attribute in the assemblyIdentity tag\n"); goto exit; } ::SysFreeString(varAttribute.bstrVal); ::SysFreeString(bstrAttribute); SAFERELEASE(pAssemblyIdElement); SAFERELEASE(pAssemblyIdNode); if(FAILED(hr = AddMgVersionAsComment(pXMLDoc, &pRoot))) goto exit; // Add all the raw files to the manifest pos = pFileList->GetHeadPosition(); while (pos) { pwz = pFileList->GetNext(pos); sFileName.Assign(pwz); if(FAILED(hr = CreateXMLElement(pXMLDoc, FILE, &pElement))) goto exit; if(FAILED(hr = SetXMLElementAttribute(pElement, FILE_NAME, sFileName._pwz))) goto exit; if (FAILED(hr=pRoot->appendChild((IXMLDOMNode *)pElement, &pNewNode))) goto exit; //Get Absolute File Path of file sAbsoluteFilePath.Assign(pwzAppBase); sAbsoluteFilePath.Append(sFileName); //get the hash of the file if(FAILED(hr = GetHash(sAbsoluteFilePath._pwz, &pwz))) goto exit; sFileHash.TakeOwnership(pwz); if(FAILED(hr = SetXMLElementAttribute(pElement, FILE_HASH, sFileHash._pwz))) goto exit; SAFERELEASE(pNewNode); } // Get Dependency Node if exists if (FAILED(hr = GetNode(pXMLDoc, DEPENDENCY_QUERY, &pDependancyNode))) goto exit; if (hr == S_FALSE) { //Create the Dependancy Node if(FAILED(hr = CreateXMLElement(pXMLDoc, DEPENDENCY, &pElement))) goto exit; if (FAILED(hr=pRoot->appendChild((IXMLDOMNode *)pElement, &pDependancyNode))) goto exit; SAFERELEASE(pElement); } //Walk thorugh the list of dependant assemblies and add them to the App Manifest pos = pList->GetHeadPosition(); while (pos) { //Get next Dependant Assembly from list pManNode = pList->GetNext(pos); if (FAILED(hr = CreateDependantAssemblyNode(pXMLDoc, pManNode, &pDependantAssemblyNode))) goto exit; if (FAILED(hr=pDependancyNode->appendChild(pDependantAssemblyNode, &pNewNode))) goto exit; SAFERELEASE(pDependantAssemblyNode); SAFERELEASE(pNewNode); } //Indent the manifest hr = FormatXML(pXMLDoc, pRoot, 1); // Save the manifest to a file sManifestFilePath.Assign(pwzAppBase); sManifestFilePath.Append(pwzName); sManifestFilePath.Append(L".manifest"); if(FAILED(hr = SaveXMLDocument(pXMLDoc, sManifestFilePath._pwz))) goto exit; printf("\nManifest created succesfully\n%ws\n", sManifestFilePath._pwz); exit: if (varAttribute.bstrVal) ::SysFreeString(varAttribute.bstrVal); SAFEDELETEARRAY(pwzName); SAFERELEASE(pXMLDoc); SAFERELEASE(pElement); SAFERELEASE(pAssemblyIdElement); SAFERELEASE(pNewNode); SAFERELEASE(pAssemblyIdNode); SAFERELEASE(pRoot); SAFERELEASE(pDependancyNode); SAFERELEASE(pDependantAssemblyNode); return hr; } ///////////////////////////////////////////////////////////////////////// // SaveXMLDocument ///////////////////////////////////////////////////////////////////////// HRESULT SaveXMLDocument(IXMLDOMDocument2 *pXMLDoc, LPWSTR pwzDocumentName) { HRESULT hr = S_OK; CString sDocumentName; BSTR bstrFileName = NULL; VARIANT varFileName; // Save the manifest to a file sDocumentName.Assign(pwzDocumentName); bstrFileName = ::SysAllocString(sDocumentName._pwz); if (!bstrFileName) { hr = E_OUTOFMEMORY; goto exit; } VariantInit(&varFileName); varFileName.vt = VT_BSTR; V_BSTR(&varFileName) = bstrFileName; hr = pXMLDoc->save(varFileName); exit: if(bstrFileName) ::SysFreeString(bstrFileName); return hr; } ///////////////////////////////////////////////////////////////////////// //LoadXMLDocument ///////////////////////////////////////////////////////////////////////// HRESULT LoadXMLDocument(LPWSTR pwzDocumentPath, IXMLDOMDocument2 **ppXMLDoc) { HRESULT hr = S_OK; IXMLDOMDocument2 *pXMLDoc; VARIANT varFileName; VARIANT_BOOL varBool; BSTR bstrFileName = NULL; bstrFileName = ::SysAllocString(pwzDocumentPath); if (!bstrFileName) { hr = E_OUTOFMEMORY; goto exit; } VariantInit(&varFileName); varFileName.vt = VT_BSTR; V_BSTR(&varFileName) = bstrFileName; if(FAILED(hr = CoCreateInstance(__uuidof(private_MSXML_DOMDocument30), NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument2, (void**)&pXMLDoc))) goto exit; // Load synchronously if (FAILED(hr = pXMLDoc->put_async(VARIANT_FALSE))) goto exit; if ((hr = pXMLDoc->load(varFileName, &varBool)) != S_OK) { if(!varBool) hr = E_INVALIDARG; goto exit; } *ppXMLDoc=pXMLDoc; (*ppXMLDoc)->AddRef(); exit: if(bstrFileName) ::SysFreeString(bstrFileName); SAFERELEASE(pXMLDoc); return hr; }