// 语言:C++
// 支持编译为Unicode版本,不支持ANSI版本
#include <string>
#include <tchar.h>
#include <Windows.h>
#include <CommCtrl.h>
#include <LM.h>
#include <MsXml6.h>
#include <ShlObj.h>
using namespace std;
typedef basic_string<TCHAR> tstring;
#pragma comment(lib, "comctl32.lib")
#pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' language='*' publicKeyToken='6595b64144ccf1df'\"")
#pragma comment(lib, "msxml6.lib")
#pragma comment(lib, "Netapi32.lib")
BSTR bstr;
VARIANT vbstr;
inline void alert(LPTSTR msg)
{
MessageBox(NULL, msg, TEXT("错误"), MB_ICONWARNING);
}
void setNode(IXMLDOMDocument *pXMLDoc, IXMLDOMElement *pElem, LPWSTR name, LPCWSTR value)
{
bstr = SysAllocString(name);
IXMLDOMElement *pNew;
HRESULT hr = pXMLDoc->createElement(bstr, &pNew);
SysFreeString(bstr);
if (SUCCEEDED(hr))
{
bstr = SysAllocString(value);
hr = pNew->put_text(bstr);
SysFreeString(bstr);
if (SUCCEEDED(hr))
{
hr = pElem->appendChild(pNew, NULL);
pNew->Release();
}
}
if (FAILED(hr))
throw 0;
}
void write(tstring folder, IXMLDOMDocument *pXMLDoc, IXMLDOMElement *pElem)
{
WIN32_FIND_DATA fd;
HANDLE hFind = FindFirstFile((folder + TEXT("\\*")).c_str(), &fd);
if (hFind == INVALID_HANDLE_VALUE)
throw 1;
int err = -1;
BSTR bstrLink = SysAllocString(L"link");
BSTR bstrFolder = SysAllocString(L"folder");
HRESULT hr;
IXMLDOMElement *pFileElem = NULL;
IXMLDOMElement *pFolderElem = NULL;
IPersistFile *pFile = NULL;
IShellLink *pLink = NULL;
try
{
do
{
tstring filename = fd.cFileName;
if (filename == TEXT(".") || filename == TEXT(".."))
continue;
tstring filepath = folder + TEXT("\\") + fd.cFileName;
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
// 创建<folder>
hr = pXMLDoc->createElement(bstrFolder, &pFolderElem);
if (FAILED(hr))
throw 0;
setNode(pXMLDoc, pFolderElem, L"name", filename.c_str());
write(filepath, pXMLDoc, pFolderElem);
hr = pElem->appendChild(pFolderElem, NULL);
if (FAILED(hr))
throw 0;
pFolderElem->Release();
pFolderElem = NULL;
continue;
}
int len = filename.length();
if (filename.substr(len - 4) != TEXT(".lnk"))
continue; // 跳过非快捷方式文件
// 创建<link>
hr = pXMLDoc->createElement(bstrLink, &pFileElem);
if (FAILED(hr))
throw 0;
setNode(pXMLDoc, pFileElem, L"name", filename.substr(0, len - 4).c_str());
hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pLink));
if (FAILED(hr))
throw 0;
hr = pLink->QueryInterface(&pFile);
if (FAILED(hr))
throw 0;
bstr = SysAllocString(filepath.c_str());
hr = pFile->Load(bstr, STGM_READ);
SysFreeString(bstr);
if (FAILED(hr))
throw 0;
TCHAR szPath[MAX_PATH];
hr = pLink->GetPath(szPath, MAX_PATH, NULL, SLGP_RAWPATH);
if (SUCCEEDED(hr) && szPath[0] != '\0')
setNode(pXMLDoc, pFileElem, L"path", szPath);
TCHAR szDesc[INFOTIPSIZE];
hr = pLink->GetArguments(szDesc, INFOTIPSIZE);
if (SUCCEEDED(hr) && szDesc[0] != '\0')
setNode(pXMLDoc, pFileElem, L"arguments", szDesc);
hr = pLink->GetDescription(szDesc, INFOTIPSIZE);
if (SUCCEEDED(hr) && szDesc[0] != '\0')
setNode(pXMLDoc, pFileElem, L"description", szDesc);
WORD hotkey;
hr = pLink->GetHotkey(&hotkey);
if (SUCCEEDED(hr))
{
_stprintf_s(szPath, TEXT("%d"), hotkey);
setNode(pXMLDoc, pFileElem, L"hotkey", szPath);
}
int icon;
hr = pLink->GetIconLocation(szPath, MAX_PATH, &icon);
if (SUCCEEDED(hr) && szPath[0] != '\0')
{
_stprintf_s(szDesc, TEXT("%d"), icon);
setNode(pXMLDoc, pFileElem, L"icon", szPath);
IXMLDOMNode *pLast;
IXMLDOMElement *pLastElem;
hr = pFileElem->get_lastChild(&pLast);
if (SUCCEEDED(hr))
{
hr = pLast->QueryInterface(&pLastElem);
if (SUCCEEDED(hr))
{
bstr = SysAllocString(L"index");
vbstr.bstrVal = SysAllocString(szDesc);
pLastElem->setAttribute(bstr, vbstr);
SysFreeString(bstr);
SysFreeString(vbstr.bstrVal);
pLastElem->Release();
}
pLast->Release();
}
}
int nCmdShow; // 这个就是WinMain函数里的第四个参数
hr = pLink->GetShowCmd(&nCmdShow);
if (SUCCEEDED(hr))
{
switch (nCmdShow)
{
case SW_SHOWNORMAL:
setNode(pXMLDoc, pFileElem, L"show_cmd", L"SW_SHOWNORMAL");
break;
case SW_SHOWMAXIMIZED:
setNode(pXMLDoc, pFileElem, L"show_cmd", L"SW_SHOWMAXIMIZED");
break;
case SW_SHOWMINIMIZED:
setNode(pXMLDoc, pFileElem, L"show_cmd", L"SW_SHOWMINIMIZED");
break;
default:
setNode(pXMLDoc, pFileElem, L"show_cmd", L"Unknown");
break;
}
}
hr = pLink->GetWorkingDirectory(szPath, MAX_PATH);
if (SUCCEEDED(hr) && szPath[0] != '\0')
setNode(pXMLDoc, pFileElem, L"working_dir", szPath);
pFile->Release();
pFile = NULL;
pLink->Release();
pLink = NULL;
hr = pElem->appendChild(pFileElem, NULL);
if (FAILED(hr))
throw 0;
} while (FindNextFile(hFind, &fd));
}
catch (int i)
{
err = i;
}
FindClose(hFind);
SysFreeString(bstrLink);
SysFreeString(bstrFolder);
if (pFileElem != NULL)
pFileElem->Release();
if (pFolderElem != NULL)
pFolderElem->Release();
if (pLink != NULL)
pLink->Release();
if (pFile != NULL)
pFile->Release();
if (err != -1)
throw err;
}
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
vbstr.vt = VT_BSTR;
InitCommonControls();
TCHAR szFolder[MAX_PATH];
BOOL bResult = SHGetSpecialFolderPath(NULL, szFolder, CSIDL_COMMON_STARTMENU, FALSE);
if (!bResult)
{
alert(TEXT("获取开始菜单文件夹路径失败!"));
return 0;
}
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (FAILED(hr))
{
alert(TEXT("初始化COM失败!"));
return 0;
}
IXMLDOMDocument *pXMLDoc;
hr = CoCreateInstance(CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pXMLDoc));
if (SUCCEEDED(hr))
{
IXMLDOMElement *pRoot = NULL;
IXMLDOMElement *pComm = NULL;
IXMLDOMElement *pUser = NULL;
IXMLDOMElement *pInfo = NULL;
IXMLDOMProcessingInstruction *pProInstruction = NULL;
try
{
/* 在文档中创建XML声明 */
bstr = SysAllocString(L"xml");
vbstr.bstrVal = SysAllocString(L"version=\"1.0\" encoding=\"utf-8\"");
hr = pXMLDoc->createProcessingInstruction(bstr, vbstr.bstrVal, &pProInstruction);
SysFreeString(bstr);
SysFreeString(vbstr.bstrVal);
if (SUCCEEDED(hr))
hr = pXMLDoc->appendChild(pProInstruction, NULL);
if (FAILED(hr))
throw 0;
pProInstruction->Release();
// 创建根节点<menu>
bstr = SysAllocString(L"menu");
hr = pXMLDoc->createElement(bstr, &pRoot);
SysFreeString(bstr);
if (FAILED(hr))
throw 0;
// 创建<info>
bstr = SysAllocString(L"info");
hr = pXMLDoc->createElement(bstr, &pInfo);
SysFreeString(bstr);
if (FAILED(hr))
throw 0;
// 工作组名
LPWSTR lpNameBuffer;
NETSETUP_JOIN_STATUS bufferType;
NET_API_STATUS nas = NetGetJoinInformation(NULL, &lpNameBuffer, &bufferType);
if (nas == NERR_Success)
{
switch (bufferType)
{
case NetSetupUnknownStatus:
setNode(pXMLDoc, pInfo, L"network", L"Unknown network status");
break;
case NetSetupUnjoined:
setNode(pXMLDoc, pInfo, L"network", L"Not joined to any workgroup or domain");
break;
case NetSetupWorkgroupName:
setNode(pXMLDoc, pInfo, L"workgroup", lpNameBuffer);
break;
case NetSetupDomainName:
setNode(pXMLDoc, pInfo, L"domain", lpNameBuffer);
break;
}
}
NetApiBufferFree(lpNameBuffer);
// 计算机名
TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD n = MAX_COMPUTERNAME_LENGTH + 1;
if (GetComputerName(szComputerName, &n))
setNode(pXMLDoc, pInfo, L"computer", szComputerName);
// 用户名
TCHAR szUserName[UNLEN + 1];
n = UNLEN + 1;
if (GetUserName(szUserName, &n))
setNode(pXMLDoc, pInfo, L"user", szUserName);
// 添加<info>
hr = pRoot->appendChild(pInfo, NULL);
if (FAILED(hr))
throw 0;
// 创建<common>
bstr = SysAllocString(L"common");
hr = pXMLDoc->createElement(bstr, &pComm);
SysFreeString(bstr);
if (FAILED(hr))
throw 0;
// 设置path属性
bstr = SysAllocString(L"path");
vbstr.bstrVal = SysAllocString(szFolder);
hr = pComm->setAttribute(bstr, vbstr);
SysFreeString(bstr);
SysFreeString(vbstr.bstrVal);
if (FAILED(hr))
throw 0;
write(szFolder, pXMLDoc, pComm);
// 添加<common>
hr = pRoot->appendChild(pComm, NULL);
if (FAILED(hr))
throw 0;
if (SHGetSpecialFolderPath(NULL, szFolder, CSIDL_STARTMENU, FALSE))
{
// 创建<current_user>
bstr = SysAllocString(L"current_user");
hr = pXMLDoc->createElement(bstr, &pUser);
SysFreeString(bstr);
if (FAILED(hr))
throw 0;
// 设置path属性
bstr = SysAllocString(L"path");
vbstr.bstrVal = SysAllocString(szFolder);
hr = pUser->setAttribute(bstr, vbstr);
SysFreeString(bstr);
SysFreeString(vbstr.bstrVal);
if (FAILED(hr))
throw 0;
write(szFolder, pXMLDoc, pUser);
// 添加<current_user>
hr = pRoot->appendChild(pUser, NULL);
if (FAILED(hr))
throw 0;
}
// 添加根节点到文档中
hr = pXMLDoc->appendChild(pRoot, NULL);
if (FAILED(hr))
throw 0;
// 保存文件
vbstr.bstrVal = SysAllocString(L"startmenu.xml");
hr = pXMLDoc->save(vbstr);
SysFreeString(vbstr.bstrVal);
if (FAILED(hr))
alert(TEXT("保存XML文件时出错!"));
}
catch (int i)
{
switch (i)
{
case 0:
alert(TEXT("生成XML文档时出错!"));
break;
case 1:
alert(TEXT("打开开始菜单文件夹时出错!"));
break;
}
}
if (pRoot != NULL)
pRoot->Release();
if (pComm != NULL)
pComm->Release();
if (pUser != NULL)
pUser->Release();
if (pInfo != NULL)
pInfo->Release();
if (pProInstruction != NULL)
pProInstruction->Release();
pXMLDoc->Release();
}
else
alert(TEXT("创建XML文档对象时失败!"));
CoUninitialize();
return 0;
}