#include "CWindowsFireWall.h"


#include <crtdbg.h>
#include <objbase.h>
#include <oleauto.h>
#include <stdio.h>
#include <tlhelp32.h>
#include <Psapi.h>
#include <strsafe.h>
#include <QStringList>
#include <QDebug>
#include <QFileInfo>
#include <QSettings>
#include <comutil.h>
#include <atlcomcli.h>
#include<QDateTime>
#include "logproc.h"

#pragma comment( lib, "ole32.lib" )
#pragma comment( lib, "oleaut32.lib" )

std::shared_ptr<CWindowsFireWall> g_windowsFireWallPtr = nullptr;

#define STRING_BUFFER_SIZE  500


BOOL EnableDebugPrivilege()
{
    HANDLE hToken;
    BOOL fOk = FALSE;
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
    {
        TOKEN_PRIVILEGES tp;
        tp.PrivilegeCount = 1;
        LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
        fOk = (GetLastError() == ERROR_SUCCESS);
        CloseHandle(hToken);
    }
    return fOk;
}

CWindowsFireWall::CWindowsFireWall(DWORD pid, bool bcheck) : m_pid(pid), m_bcheck(bcheck)
{   
    EnableDebugPrivilege();

    QFileInfo file("coe.cfgi");
    QString sFilePath = file.absoluteFilePath();
    QSettings set(sFilePath, QSettings::IniFormat);
    m_bModifyFireWall = set.value("wallConfig/ModifyWall", false).toBool();
    m_fw_profile2_domain_enabled = set.value("wallConfig/profile2_domain_enabled", VARIANT_TRUE).toInt();
    m_fw_profile2_private_enabled = set.value("wallConfig/profile2_private_enabled", VARIANT_TRUE).toInt();
    m_fw_profile2_public_enabled = set.value("wallConfig/profile2_public_enabled", VARIANT_TRUE).toInt();

    init();

    if(bcheck)
    {
        m_pThrd = new std::thread(std::bind(&CWindowsFireWall::threadProc, this));
    }
}

CWindowsFireWall::~CWindowsFireWall()
{
    m_bIsRun = false;
    if(m_bcheck)
    {
        m_pThrd->join();
        cleanup();
    }
}

void CWindowsFireWall::threadProc()
{
    setWallOn();
    removeLastRules();
    setAllRulesEnabled(VARIANT_FALSE);

    disableAllApp();
    __int64 nLastTime = QDateTime::currentDateTime().toSecsSinceEpoch();

    while(m_bIsRun)
    {
        __int64 nCurrentTime = QDateTime::currentDateTime().toSecsSinceEpoch();
        if(nCurrentTime - nLastTime > m_inprogressCheckSeconds)
        {
            nLastTime = nCurrentTime;
            checkInprogressFireWall();
        }
        Sleep(100);
    }
}

void CWindowsFireWall::checkInprogressFireWall()
{
    //检测防火墙是否开启
    HRESULT hr;

    VARIANT_BOOL fw_profile2_domain_enabled = VARIANT_FALSE;
    VARIANT_BOOL fw_profile2_private_enabled = VARIANT_FALSE;
    VARIANT_BOOL fw_profile2_public_enabled = VARIANT_FALSE;
    hr = m_pNetFwPolicy2->get_FirewallEnabled(NET_FW_PROFILE2_DOMAIN, &fw_profile2_domain_enabled);
    if (FAILED(hr))
    {
        m_sErrMsg = QString("put_FirewallEnabled failed for Domain: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
        myServerLog()<<m_sErrMsg;
    }

    hr = m_pNetFwPolicy2->get_FirewallEnabled(NET_FW_PROFILE2_PRIVATE, &fw_profile2_private_enabled);
    if (FAILED(hr))
    {
        m_sErrMsg = QString("put_FirewallEnabled failed for private: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
        myServerLog()<<m_sErrMsg;
    }

    hr = m_pNetFwPolicy2->get_FirewallEnabled(NET_FW_PROFILE2_PUBLIC, &fw_profile2_public_enabled);
    if (FAILED(hr))
    {
        m_sErrMsg = QString("put_FirewallEnabled failed for public: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
        myServerLog()<<m_sErrMsg;
    }

    if(fw_profile2_domain_enabled != VARIANT_TRUE ||
            fw_profile2_private_enabled != VARIANT_TRUE ||
            fw_profile2_public_enabled != VARIANT_TRUE)
    {
        myServerLog()<<QString::fromLocal8Bit("考试中防火墙被关闭 ")<<",fw_profile2_domain_enabled:"<<fw_profile2_domain_enabled
                    <<",fw_profile2_private_enabled:"<<fw_profile2_private_enabled
                   <<",fw_profile2_public_enabled:"<<fw_profile2_public_enabled;
        setWallOn();
    }

    //遍历进程
    checkRulesIsEnabled();

    disableAllApp();
}

void CWindowsFireWall::checkRulesIsEnabled()
{
    HRESULT hr = S_OK;
    CComVariant var;
    ULONG cFetched = 0;
    IUnknown *pEnumerator;
    IEnumVARIANT* pVariant = NULL;
    INetFwRules *pFwRules = NULL;
    INetFwRule *pFwRule = NULL;

    long fwRuleCount;

    // Retrieve INetFwRules
    hr = m_pNetFwPolicy2->get_Rules(&pFwRules);
    if (FAILED(hr))
    {
        wprintf(L"get_Rules failed: 0x%08lx\n", hr);
    }

    // Obtain the number of Firewall rules
    hr = pFwRules->get_Count(&fwRuleCount);
    if (FAILED(hr))
    {
        wprintf(L"get_Count failed: 0x%08lx\n", hr);
    }

    wprintf(L"The number of rules in the Windows Firewall are %d\n", fwRuleCount);

    // Iterate through all of the rules in pFwRules
    pFwRules->get__NewEnum(&pEnumerator);

    if(pEnumerator)
    {
        hr = pEnumerator->QueryInterface(__uuidof(IEnumVARIANT), (void **) &pVariant);
    }

    while(SUCCEEDED(hr) && hr != S_FALSE)
    {
        var.Clear();
        hr = pVariant->Next(1, &var, &cFetched);

        if (S_FALSE != hr)
        {
            if (SUCCEEDED(hr))
            {
                hr = var.ChangeType(VT_DISPATCH);
            }
            if (SUCCEEDED(hr))
            {
                hr = (V_DISPATCH(&var))->QueryInterface(__uuidof(INetFwRule), reinterpret_cast<void**>(&pFwRule));
            }

            if (SUCCEEDED(hr))
            {
                BSTR szRuleName;
                pFwRule->get_Name(&szRuleName);
                QString sRuleName = QString::fromStdWString(szRuleName);
                VARIANT_BOOL bEnable = VARIANT_FALSE;
                pFwRule->put_Enabled(bEnable);
                if(sRuleName.startsWith("disable_coe_"))
                {
                    if(bEnable == VARIANT_FALSE)
                    {
                        pFwRule->put_Enabled(VARIANT_TRUE);
                    }
                }
                else
                {
                    if(bEnable == VARIANT_TRUE)
                    {
                        pFwRule->put_Enabled(VARIANT_FALSE);
                    }
                }

            }
        }
    }

    // Release pFwRule
    if (pFwRule != NULL)
    {
        pFwRule->Release();
    }

    if(pFwRules != NULL)
    {
        pFwRules->Release();
    }
}

void CWindowsFireWall::uploadAppLog(std::vector<CProcessData> &vAppList)
{
    QStringList appList;
    for(CProcessData data : vAppList)
    {
        appList << QString::fromStdWString(data.sExeName);
    }
    myServerLog()<<appList.join(",");
}
// Instantiate INetFwPolicy2
HRESULT CWindowsFireWall::WFCOMInitialize(INetFwPolicy2** ppNetFwPolicy2)
{
    HRESULT hr = S_OK;

    hr = CoCreateInstance(
        __uuidof(NetFwPolicy2),
        NULL,
        CLSCTX_INPROC_SERVER,
        __uuidof(INetFwPolicy2),
        (void**)ppNetFwPolicy2);

    if (FAILED(hr))
    {
        m_sErrMsg = QString("CoCreateInstance for INetFwPolicy2 failed: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));

    }

    return hr;
}

bool CWindowsFireWall::init()
{   
    HRESULT hr = S_OK;

    // Initialize COM.
    m_comInit = CoInitializeEx(
                    0,
                    COINIT_APARTMENTTHREADED
                    );

    // Ignore RPC_E_CHANGED_MODE; this just means that COM has already been
    // initialized with a different mode. Since we don't care what the mode is,
    // we'll just use the existing mode.
    if (m_comInit != RPC_E_CHANGED_MODE)
    {
        if (FAILED(m_comInit))
        {            
            m_sErrMsg = QString("CoInitializeEx for INetFwPolicy2 failed: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            return false;
        }
    }

    // Retrieve INetFwPolicy2
    hr = WFCOMInitialize(&m_pNetFwPolicy2);
    if (FAILED(hr))
    {        
        return false;
    }
    return true;
}

void CWindowsFireWall::cleanup()
{   
    if(m_vDisableRuleNames.size() > 0)
    {
        INetFwRules *pNetFwRules = NULL;
        HRESULT hr = m_pNetFwPolicy2->get_Rules(&pNetFwRules);
        if (SUCCEEDED(hr))
        {
            for(std::wstring sRuleName: m_vDisableRuleNames)
            {
                pNetFwRules->Remove(const_cast<BSTR>(sRuleName.c_str()));
            }			
        }
    }

    setAllRulesEnabled(VARIANT_TRUE);

    if(m_bModifyFireWall)
    {
        HRESULT hr = m_pNetFwPolicy2->put_FirewallEnabled(NET_FW_PROFILE2_DOMAIN, m_fw_profile2_domain_enabled);
        if (FAILED(hr))
        {
            m_sErrMsg = QString("put_FirewallEnabled failed for Domain: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
        }

        hr = m_pNetFwPolicy2->put_FirewallEnabled(NET_FW_PROFILE2_PRIVATE, m_fw_profile2_private_enabled);
        if (FAILED(hr))
        {
            m_sErrMsg = QString("put_FirewallEnabled failed for Private: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
        }

        hr = m_pNetFwPolicy2->put_FirewallEnabled(NET_FW_PROFILE2_PUBLIC, m_fw_profile2_public_enabled);
        if (FAILED(hr))
        {
            m_sErrMsg = QString("put_FirewallEnabled failed for Public: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
        }

        m_bModifyFireWall = false;
        m_fw_profile2_domain_enabled = VARIANT_TRUE;
        m_fw_profile2_private_enabled = VARIANT_TRUE;
        m_fw_profile2_public_enabled = VARIANT_TRUE;
        QFileInfo file("coe.cfgi");
        QString sFilePath = file.absoluteFilePath();
        QSettings set(sFilePath, QSettings::IniFormat);
        set.setValue("wallConfig/ModifyWall", m_bModifyFireWall);
        set.setValue("wallConfig/profile2_domain_enabled", m_fw_profile2_domain_enabled);
        set.setValue("wallConfig/profile2_private_enabled", m_fw_profile2_private_enabled);
        set.setValue("wallConfig/profile2_public_enabled", m_fw_profile2_public_enabled);
    }

    if (m_pNetFwPolicy2 != NULL)
    {
        m_pNetFwPolicy2->Release();
    }

    if (SUCCEEDED(m_comInit))
    {
        CoUninitialize();
    }    
}

bool CWindowsFireWall::setWallOn()
{
    HRESULT hr;
    if(!m_bModifyFireWall)
    {
        hr = m_pNetFwPolicy2->get_FirewallEnabled(NET_FW_PROFILE2_DOMAIN, &m_fw_profile2_domain_enabled);
        if (FAILED(hr))
        {
            m_sErrMsg = QString("put_FirewallEnabled failed for Domain: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            return false;
        }

        hr = m_pNetFwPolicy2->get_FirewallEnabled(NET_FW_PROFILE2_PRIVATE, &m_fw_profile2_private_enabled);
        if (FAILED(hr))
        {
            m_sErrMsg = QString("put_FirewallEnabled failed for private: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            return false;
        }

        hr = m_pNetFwPolicy2->get_FirewallEnabled(NET_FW_PROFILE2_PUBLIC, &m_fw_profile2_public_enabled);
        if (FAILED(hr))
        {
            m_sErrMsg = QString("put_FirewallEnabled failed for public: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            return false;
        }
    }

    hr = m_pNetFwPolicy2->put_FirewallEnabled(NET_FW_PROFILE2_DOMAIN, TRUE);
    if (FAILED(hr))
    {
        m_sErrMsg = QString("put_FirewallEnabled failed for Domain: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
        return false;
    }

    hr = m_pNetFwPolicy2->put_FirewallEnabled(NET_FW_PROFILE2_PRIVATE, TRUE);
    if (FAILED(hr))
    {
        m_sErrMsg = QString("put_FirewallEnabled failed for Private: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
        return false;
    }

    hr = m_pNetFwPolicy2->put_FirewallEnabled(NET_FW_PROFILE2_PUBLIC, TRUE);
    if (FAILED(hr))
    {
        m_sErrMsg = QString("put_FirewallEnabled failed for Public: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
        return false;
    }

    if(m_fw_profile2_domain_enabled != VARIANT_TRUE ||
            m_fw_profile2_private_enabled != VARIANT_TRUE ||
            m_fw_profile2_public_enabled != VARIANT_TRUE )
    {
        m_bModifyFireWall = true;
        QFileInfo file("coe.cfgi");
        QString sFilePath = file.absoluteFilePath();
        QSettings set(sFilePath, QSettings::IniFormat);
        set.setValue("wallConfig/ModifyWall", m_bModifyFireWall);
        set.setValue("wallConfig/profile2_domain_enabled", m_fw_profile2_domain_enabled);
        set.setValue("wallConfig/profile2_private_enabled", m_fw_profile2_private_enabled);
        set.setValue("wallConfig/profile2_public_enabled", m_fw_profile2_public_enabled);
    }
    return true;
}

void CWindowsFireWall::setAllRulesEnabled(VARIANT_BOOL bEnable)
{
    HRESULT hr = S_OK;
    CComVariant var;
    ULONG cFetched = 0;
    IUnknown *pEnumerator;
    IEnumVARIANT* pVariant = NULL;
    INetFwRules *pFwRules = NULL;
    INetFwRule *pFwRule = NULL;

    long fwRuleCount;

    // Retrieve INetFwRules
    hr = m_pNetFwPolicy2->get_Rules(&pFwRules);
    if (FAILED(hr))
    {
        wprintf(L"get_Rules failed: 0x%08lx\n", hr);
    }

    // Obtain the number of Firewall rules
    hr = pFwRules->get_Count(&fwRuleCount);
    if (FAILED(hr))
    {
        wprintf(L"get_Count failed: 0x%08lx\n", hr);
    }

    wprintf(L"The number of rules in the Windows Firewall are %d\n", fwRuleCount);

    // Iterate through all of the rules in pFwRules
    pFwRules->get__NewEnum(&pEnumerator);

    if(pEnumerator)
    {
        hr = pEnumerator->QueryInterface(__uuidof(IEnumVARIANT), (void **) &pVariant);
    }

    while(SUCCEEDED(hr) && hr != S_FALSE)
    {
        var.Clear();
        hr = pVariant->Next(1, &var, &cFetched);

        if (S_FALSE != hr)
        {
            if (SUCCEEDED(hr))
            {
                hr = var.ChangeType(VT_DISPATCH);
            }
            if (SUCCEEDED(hr))
            {
                hr = (V_DISPATCH(&var))->QueryInterface(__uuidof(INetFwRule), reinterpret_cast<void**>(&pFwRule));
            }

            if (SUCCEEDED(hr))
            {
                // Output the properties of this rule
             //   DumpFWRulesInCollection(pFwRule);
                pFwRule->put_Enabled(bEnable);
            }                        
        }
    }

	// Release pFwRule
	if (pFwRule != NULL)
	{
		pFwRule->Release();
	}

    if(pFwRules != NULL)
    {
        pFwRules->Release();
    }
}

void CWindowsFireWall::removeLastRules()
{
    HRESULT hr = S_OK;
    CComVariant var;
    ULONG cFetched = 0;
    IUnknown *pEnumerator;
    IEnumVARIANT* pVariant = NULL;
    INetFwRules *pFwRules = NULL;
    INetFwRule *pFwRule = NULL;

    long fwRuleCount;

    // Retrieve INetFwRules
    hr = m_pNetFwPolicy2->get_Rules(&pFwRules);
    if (FAILED(hr))
    {
        wprintf(L"get_Rules failed: 0x%08lx\n", hr);
    }

    // Obtain the number of Firewall rules
    hr = pFwRules->get_Count(&fwRuleCount);
    if (FAILED(hr))
    {
        wprintf(L"get_Count failed: 0x%08lx\n", hr);
    }

    wprintf(L"The number of rules in the Windows Firewall are %d\n", fwRuleCount);

    // Iterate through all of the rules in pFwRules
    pFwRules->get__NewEnum(&pEnumerator);

    if(pEnumerator)
    {
        hr = pEnumerator->QueryInterface(__uuidof(IEnumVARIANT), (void **) &pVariant);
    }

    QStringList RuleNamelist;

    while(SUCCEEDED(hr) && hr != S_FALSE)
    {
        var.Clear();
        hr = pVariant->Next(1, &var, &cFetched);

        if (S_FALSE != hr)
        {
            if (SUCCEEDED(hr))
            {
                hr = var.ChangeType(VT_DISPATCH);
            }
            if (SUCCEEDED(hr))
            {
                hr = (V_DISPATCH(&var))->QueryInterface(__uuidof(INetFwRule), reinterpret_cast<void**>(&pFwRule));
            }

            if (SUCCEEDED(hr))
            {
                // Output the properties of this rule
             //   DumpFWRulesInCollection(pFwRule);
                BSTR szRuleName;
                pFwRule->get_Name(&szRuleName);
                QString sRuleName = QString::fromStdWString(szRuleName);
                if(sRuleName.startsWith("disable_coe_"))
                {
                    RuleNamelist<<sRuleName;
                }
            }
        }
        
    }

    for(QString &sRuleName : RuleNamelist)
    {
        std::wstring sName = sRuleName.toStdWString();
        pFwRules->Remove(const_cast<BSTR>(sName.c_str()));
    }

	// Release pFwRule
	if (pFwRule != NULL)
	{
		pFwRule->Release();
	}

    if(pFwRules != NULL)
    {
        pFwRules->Release();
    }
}

bool CWindowsFireWall::disableAllApp()
{   
    HRESULT hr = S_OK;

    std::vector<CProcessData> vAppList;
    if(getAllAppNameList(vAppList))
    {
        uploadAppLog(vAppList);
    }

    INetFwRules *pNetFwRules = NULL;
    hr = m_pNetFwPolicy2->get_Rules(&pNetFwRules);

    if (FAILED(hr))
    {
        m_sErrMsg = QString("Failed to retrieve firewall rules collection : 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
    }

    for(CProcessData &data : vAppList)
    {
        if(data.bDisabled)
        {
            continue;
        }

        bool bSucceed = true;

        INetFwRule  *pNetFwRule = NULL;
        INetFwRule2 *pNetFwRule2 = NULL;

        WCHAR pwszTemp[STRING_BUFFER_SIZE] = L"";

        BSTR RuleName = NULL;
        BSTR RuleGroupName = NULL;
        BSTR RuleDescription = NULL;
        BSTR RuleAppPath = NULL;

        hr = StringCchPrintfW(pwszTemp, STRING_BUFFER_SIZE, (L"disable_coe_" + data.sExeName).c_str());
        if (FAILED(hr))
        {
            m_sErrMsg = QString("Failed to compose a resource identifier string: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            bSucceed = false;
        }

        RuleName = SysAllocString(pwszTemp);
        if (NULL == RuleName)
        {
            m_sErrMsg = QString("ERROR: Insufficient memory");
            bSucceed = false;
        }

        hr = StringCchPrintfW(pwszTemp, STRING_BUFFER_SIZE, L"coe");
        if (FAILED(hr))
        {
            m_sErrMsg = QString("Failed to compose a resource identifier string: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            bSucceed = false;
        }
        RuleGroupName = SysAllocString(pwszTemp);  // Used for grouping together multiple rules
        if (NULL == RuleGroupName)
        {
            m_sErrMsg = QString("ERROR: Insufficient memory");
            bSucceed = false;
        }

        hr = StringCchPrintfW(pwszTemp, STRING_BUFFER_SIZE, (L"disable " + data.sExeName).c_str());
        if (FAILED(hr))
        {
            m_sErrMsg = QString("Failed to compose a resource identifier string: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            bSucceed = false;
        }
        RuleDescription = SysAllocString(pwszTemp);
        if (NULL == RuleDescription)
        {
            m_sErrMsg = "ERROR: Insufficient memory";
            bSucceed = false;
        }

        RuleAppPath = SysAllocString(data.sExePath.c_str());
        if (NULL == RuleAppPath)
        {
            m_sErrMsg = "ERROR: Insufficient memory";
            bSucceed = false;
        }

//        hr = m_pNetFwPolicy2->get_Rules(&pNetFwRules);

//        if (FAILED(hr))
//        {
//            m_sErrMsg = QString("Failed to retrieve firewall rules collection : 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
//            bSucceed = false;
//        }

        hr = CoCreateInstance(
            __uuidof(NetFwRule),    //CLSID of the class whose object is to be created
            NULL,
            CLSCTX_INPROC_SERVER,
            __uuidof(INetFwRule),   // Identifier of the Interface used for communicating with the object
            (void**)&pNetFwRule);

        if (FAILED(hr))
        {
            m_sErrMsg = QString("CoCreateInstance for INetFwRule failed: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            bSucceed = false;
        }



        hr = pNetFwRule->put_Name(RuleName);
        if ( FAILED(hr) )
        {
            m_sErrMsg = QString("Failed INetFwRule::put_Name failed with error: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            bSucceed = false;
        }

        hr = pNetFwRule->put_Grouping(RuleGroupName);
        if ( FAILED(hr) )
        {
            m_sErrMsg = QString("Failed INetFwRule::put_Grouping failed with error: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            bSucceed = false;
        }

        hr = pNetFwRule->put_Description(RuleDescription);
        if ( FAILED(hr) )
        {
            m_sErrMsg = QString("Failed INetFwRule::put_Description failed with error: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            bSucceed = false;
        }

        hr = pNetFwRule->put_Direction(NET_FW_RULE_DIR_OUT);
        if ( FAILED(hr) )
        {
            m_sErrMsg = QString("Failed INetFwRule::put_Direction failed with error: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            bSucceed = false;
        }

        hr = pNetFwRule->put_Action(NET_FW_ACTION_BLOCK);
        if ( FAILED(hr) )
        {
            m_sErrMsg = QString("Failed INetFwRule::put_Action failed with error: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            bSucceed = false;
        }

        hr = pNetFwRule->put_ApplicationName(RuleAppPath);
        if ( FAILED(hr) )
        {
            m_sErrMsg = QString("Failed INetFwRule::put_ApplicationName failed with error: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            bSucceed = false;
        }

        hr = pNetFwRule->put_Profiles(NET_FW_PROFILE2_DOMAIN | NET_FW_PROFILE2_PRIVATE | NET_FW_PROFILE2_PUBLIC);
        if ( FAILED(hr) )
        {
            m_sErrMsg = QString("Failed INetFwRule::put_Profiles failed with error: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            bSucceed = false;
        }

        hr = pNetFwRule->put_Enabled(VARIANT_TRUE);
        if ( FAILED(hr) )
        {
            m_sErrMsg = QString("Failed INetFwRule::put_Enabled failed with error: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            bSucceed = false;
        }


        // Check if INetFwRule2 interface is available (i.e Windows7+)
        // If supported, then use EdgeTraversalOptions
        // Else use the EdgeTraversal boolean flag.

        if (SUCCEEDED(pNetFwRule->QueryInterface(__uuidof(INetFwRule2), (void**)&pNetFwRule2)))
        {
            hr = pNetFwRule2->put_EdgeTraversalOptions(NET_FW_EDGE_TRAVERSAL_TYPE_DENY);
            if ( FAILED(hr) )
            {
                m_sErrMsg = QString("Failed INetFwRule::put_EdgeTraversalOptions failed with error: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            }
        }
        else
        {
            hr = pNetFwRule->put_EdgeTraversal(VARIANT_FALSE);
            if ( FAILED(hr) )
            {
                m_sErrMsg = QString("Failed INetFwRule::put_EdgeTraversal failed with error: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
                bSucceed = false;
            }
        }

        hr = pNetFwRules->Add(pNetFwRule);
        if (FAILED(hr))
        {
            m_sErrMsg = QString("Failed to add firewall rule to the firewall rules collection: 0x%1").arg(hr, 8, 16, QLatin1Char('0'));
            bSucceed = false;
        }

        if(bSucceed)
        {
            data.bDisabled = true;
            m_vDisableRuleNames.push_back(RuleName);
            qDebug()<<QString::fromStdWString(RuleName);
        }
        else
        {
            qDebug()<<RuleName<<":"<<m_sErrMsg;
        }

        SysFreeString(RuleName);
        SysFreeString(RuleGroupName);
        SysFreeString(RuleDescription);
        SysFreeString(RuleAppPath);

        if (pNetFwRule2 != NULL)
        {
            pNetFwRule2->Release();
        }

        if (pNetFwRule != NULL)
        {
            pNetFwRule->Release();
        }

    }

    if (pNetFwRules != NULL)
    {
        pNetFwRules->Release();
    }

    return hr;
}

std::wstring GetPathByProcessID(DWORD pid)
{
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    if (!hProcess)
    {
        return L"";
    }
    WCHAR filePath[MAX_PATH];
    DWORD ret = GetModuleFileNameEx(hProcess, NULL, filePath, MAX_PATH) ;

    CloseHandle(hProcess);
    return ret == 0 ? L"" : filePath;
}

// dos 文件路径转 windows 文件路径
BOOL DosPathToNtPath(LPTSTR pszDosPath, LPTSTR pszNtPath)
{
    TCHAR			szDriveStr[500];
    TCHAR			szDrive[3];
    TCHAR			szDevName[100];
    INT				cchDevName;
    INT				i;

    //检查参数
    if(!pszDosPath || !pszNtPath )
        return FALSE;

    //获取本地磁盘字符串
    if(GetLogicalDriveStrings(sizeof(szDriveStr), szDriveStr))
    {
        for(i = 0; szDriveStr[i]; i += 4)
        {
            if(!lstrcmpi(&(szDriveStr[i]), _T("A:\\")) || !lstrcmpi(&(szDriveStr[i]), _T("B:\\"))){continue;}

            szDrive[0] = szDriveStr[i];
            szDrive[1] = szDriveStr[i + 1];
            szDrive[2] = '\0';
            // 查询 Dos 设备名
            if(!QueryDosDevice(szDrive, szDevName, 100)){return FALSE;}

            // 命中
            cchDevName = lstrlen(szDevName);
            if(_tcsnicmp(pszDosPath, szDevName, cchDevName) == 0){
                // 复制驱动器
                lstrcpy(pszNtPath, szDrive);

                // 复制路径
                lstrcat(pszNtPath, pszDosPath + cchDevName);

                return TRUE;
            }
        }
    }

    lstrcpy(pszNtPath, pszDosPath);

    return FALSE;
}

// 获取进程全路径
BOOL GetProcessFullPath(DWORD dwPID, std::wstring &fullPath){
    TCHAR		szImagePath[MAX_PATH]={'\0'};
    TCHAR		pszFullPath[MAX_PATH]={'\0'};
    HANDLE		hProcess;


    // 获取进程句柄失败
    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, dwPID);
    if(!hProcess){return FALSE;}

    // 获取进程完整路径失败
    if(!GetProcessImageFileName(
        hProcess,					// 进程句柄
        szImagePath,				// 接收进程所属文件全路径的指针
        MAX_PATH					// 缓冲区大小
    )){
        CloseHandle(hProcess);
        return FALSE;
    }

    // 路径转换失败
    if(!DosPathToNtPath(szImagePath, pszFullPath)){
        CloseHandle(hProcess);
        return FALSE;
    }

    CloseHandle(hProcess);

    // 导出文件全路径
    fullPath = pszFullPath;

    return TRUE;
}

bool CWindowsFireWall::getAllAppNameList(std::vector<CProcessData> &vAppList)
{
    bool bRet = false;
    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(pe32);
    HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if(hProcessSnap == INVALID_HANDLE_VALUE)
    {
        return bRet;
    }

    BOOL bMore = Process32First(hProcessSnap,&pe32);
    QStringList list;
    while(bMore)
    {
        std::wstring sExePath = L"";
        GetProcessFullPath( pe32.th32ProcessID, sExePath);
        QString sPath = QString::fromStdWString(sExePath).toLower();

        if(pe32.th32ProcessID != m_pid &&
                !sExePath.empty() &&
//                sPath.indexOf("c:\\windows\\system32") < 0 &&
                sPath.toLower().indexOf("svchost.exe") < 0 &&
//                sPath.toLower().indexOf("upgrade") < 0 &&
                list.indexOf(QString::fromStdWString(pe32.szExeFile).toLower()) < 0)
        {
            list<<QString::fromStdWString(pe32.szExeFile).toLower();
            CProcessData data;
            data.pid = pe32.th32ProcessID;
            data.sExeName = pe32.szExeFile;
            data.sExePath = sExePath;

            vAppList.push_back(data);
            bRet = true;
        }
        bMore = Process32Next(hProcessSnap,&pe32);
    }
    CloseHandle(hProcessSnap);
    return bRet;
}

