目前共有5篇帖子。 內容轉換:不轉換▼
 
點擊 回復
273 4
【原创】获取开始菜单中的全部快捷方式信息并写入XML文件的程序
一派護法 十九級
1樓 發表于:2017-1-7 20:30
// 语言: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;
}
一派護法 十九級
2樓 發表于:2017-1-7 20:31
这个程序开始写的很认真,但是后来为了赶进度就写的很粗糙。
一派護法 十九級
3樓 發表于:2017-1-7 20:32
在Visual Studio中建立Win32空项目,新建一个cpp文件,把代码复制进去就可以编译了。
运行程序会生成一个xml文件,大小大约是110KB左右。
一派護法 十九級
4樓 發表于:2017-1-7 20:34

【生成的XML文件示例】

一派護法 十九級
5樓 發表于:2017-1-8 11:57
STGM_READ中的STGM是Storage Mode的缩写。
SLGP_RAWPATH中的SLGP是ShellLink GetPath的缩写。

回復帖子

內容:
用戶名: 您目前是匿名發表
驗證碼:
(快捷鍵:Ctrl+Enter)
 

本帖信息

點擊數:273 回複數:4
評論數: ?
作者:巨大八爪鱼
最後回復:巨大八爪鱼
最後回復時間:2017-1-8 11:57
 
©2010-2024 Arslanbar Ver2.0
除非另有聲明,本站採用創用CC姓名標示-相同方式分享 3.0 Unported許可協議進行許可。