⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 upnploader.cpp

📁 Windows CE 6.0 Server 源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
#include <windows.h>
#include <winsock2.h>
#include <upnphost.h>
#include <linklist.h>
#include <regentry.h>
#include <ncdefine.h>
#include <ncdebug.h>
#include <service.h>
#include <upnphostkeys.h>
#include <upnpmem.h>

#include <auto_xxx.hxx>
#include <string.hxx>

#define ttidLoader      1
#define LOADER_SIGNAL_STOP 1      // registry value that tells the loader to exit

IUPnPRegistrar *g_upnpRegistrar = NULL;
PCWSTR g_pszHTMLDeviceListPath = L"\\windows\\upnp\\loader.htm";
HANDLE g_hUPnPHostEvent = NULL;

BOOL fShutdown;
LONG  g_fState;

static void UpdateRunningDeviceList();

class HostedDeviceInfo
{
    public:
    HostedDeviceInfo(
        PCWSTR pszDeviceId
        ) :
            newState(UPNPREG_DISABLED)
        {
            link.Flink = link.Blink = 0;
            bstrDeviceId = SysAllocString(pszDeviceId);
        }
    HRESULT Run(RegEntry *pDeviceKey);
    HRESULT Stop();
    ~HostedDeviceInfo();
    static void InitializeRunningDeviceList();
    static void UpdateRunningDeviceList();
    static void CleanupRunningDeviceList();
    static BOOL CreateHTMLDeviceList();
    static HostedDeviceInfo *FindRunningDevice(PCWSTR pszDeviceId);   
    private:
    static LIST_ENTRY runningDeviceList;
    LIST_ENTRY link;
    BSTR bstrDeviceId;
    DWORD newState;
};

LIST_ENTRY HostedDeviceInfo::runningDeviceList;

HRESULT
HostedDeviceInfo::Run(
        RegEntry *pupnpDeviceKey
        )
{
    HRESULT                 hr;
    PWSTR                   pszProgId;
    ce::auto_bstr           bstrInitString;
    ce::auto_bstr           bstrXMLDesc;
    ce::auto_bstr           bstrResourcePath;
    DWORD                   dwLifetime = 0;
    IUPnPDeviceControl*     pdev = NULL;
    IUPnPReregistrar*       pupnpReregistrar = NULL;
    CLSID                   clsid;
    ce::wistring            wstrXMLDesc;
    ce::wistring::size_type n;
    char                    pszHostName[256];
    ce::wstring             wstrHostName;

    //need to make copies of the registry values because RegEntry only holds onto the last string value
    pszProgId = _wcsdup(pupnpDeviceKey->GetString(UPNPPROGIDVALUE));
    bstrInitString = SysAllocString(pupnpDeviceKey->GetString(UPNPINITSTRINGVALUE));
    wstrXMLDesc = pupnpDeviceKey->GetString(UPNPXMLDESCVALUE);
    bstrResourcePath = SysAllocString(pupnpDeviceKey->GetString(UPNPRESOURCEPATHVALUE));
    dwLifetime = pupnpDeviceKey->GetNumber(UPNPLIFETIME);

    if(wstrXMLDesc.empty())
    {
        ce::auto_hfile hFile;

        hFile = CreateFile(pupnpDeviceKey->GetString(UPNPXMLDESCFILE), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

        if(hFile.valid())
        {
            DWORD       cbFile = GetFileSize(hFile, NULL);
            ce::string  strXMLDesc;

            strXMLDesc.reserve(cbFile);

            if(ReadFile(hFile, strXMLDesc.get_buffer(), strXMLDesc.capacity(), &cbFile, NULL))
            {
                ce::MultiByteToWideChar(CP_UTF8, strXMLDesc, cbFile, &wstrXMLDesc);
            }
        }
    }

    // Get device host name
    gethostname(pszHostName, sizeof(pszHostName));
    ce::MultiByteToWideChar(CP_ACP, pszHostName, sizeof(pszHostName), &wstrHostName);

    //
    // Replace every instance of %!HOST_NAME! in the device description with the host name of the device
    //
    for(n = 0; ce::wstring::npos != (n = wstrXMLDesc.find(L"%!HOST_NAME!", n)); )
        wstrXMLDesc.replace(n, sizeof("%!HOST_NAME!") - 1, wstrHostName);

    bstrXMLDesc = SysAllocString(wstrXMLDesc);

    if (pszProgId == NULL || *pszProgId == NULL || bstrXMLDesc == NULL || *bstrXMLDesc == NULL)
    {
        TraceTag(ttidError, "Run: Invalid parameters\n");
        hr =  E_INVALIDARG;
    }
    else if (!g_upnpRegistrar 
        || FAILED(g_upnpRegistrar->QueryInterface(__uuidof(IUPnPReregistrar), (void **)&pupnpReregistrar)))
    {
        hr = E_FAIL;
    }
    else
    {
        hr = CLSIDFromProgID(pszProgId, &clsid);
        if (FAILED(hr))
        {
            TraceTag(ttidError, "Failed to get clsid for %ls\n", pszProgId);
        }
        else
            hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
                                __uuidof(IUPnPDeviceControl), (LPVOID *)&pdev);

        if (FAILED(hr))
        {
            TraceTag(ttidError, "Failed to create %ls\n", pszProgId);
        }
        else
        {
            if(SysStringLen(bstrDeviceId))
            {
                TraceTag(ttidLoader,"Loading device %ls with ProgId %ls\n",bstrDeviceId,pszProgId);
                hr = pupnpReregistrar->ReregisterRunningDevice(
                        bstrDeviceId,
                        bstrXMLDesc,
                        pdev,
                        bstrInitString,
                        bstrResourcePath,
                        dwLifetime);
            }
            else
            {
                TraceTag(ttidLoader,"Loading device with ProgId %ls for the first time\n", pszProgId);
                hr = g_upnpRegistrar->RegisterRunningDevice(
                        bstrXMLDesc, 
                        pdev, 
                        bstrInitString, 
                        bstrResourcePath, 
                        dwLifetime, 
                        &bstrDeviceId);
                if (SUCCEEDED(hr))
                {
                    pupnpDeviceKey->SetValue(UPNPUDN, bstrDeviceId);
                }
            }

            if (SUCCEEDED(hr))
            {   // add to running device list
                Assert(link.Flink == 0);
                InsertHeadList(&runningDeviceList,&link);
            }
        }
    }
    if (pdev)
        pdev->Release();
    if (pupnpReregistrar)
        pupnpReregistrar->Release();
    if (pszProgId)
        free (pszProgId);
    return hr;
}

HRESULT HostedDeviceInfo::Stop()
{
    HRESULT hr;
    // we should be on the running device list
    if (!link.Flink || !link.Blink)
        return E_FAIL;
    // need to use IUPnPRegistrar 
    if (!g_upnpRegistrar)
        return E_FAIL;

    TraceTag(ttidLoader, "Stopping device %ls\n", bstrDeviceId);

    hr = g_upnpRegistrar->UnregisterDevice(bstrDeviceId, FALSE);

    RemoveEntryList(&link);
    link.Flink = link.Blink = 0;
    return hr;
}

HostedDeviceInfo::~HostedDeviceInfo()
{
    Assert(link.Flink == 0 && link.Blink == 0);
    if (bstrDeviceId)
        SysFreeString(bstrDeviceId);
}

void HostedDeviceInfo::InitializeRunningDeviceList()
{
    InitializeListHead(&runningDeviceList);
}


void HostedDeviceInfo::UpdateRunningDeviceList()
{
    HRESULT hr;
    LIST_ENTRY *pListEntry = NULL;
    HostedDeviceInfo *pDev = NULL;

    RegEntry upnpDevicesKey(UPNPDEVICESKEY,HKEY_LOCAL_MACHINE,FALSE);
    if(!upnpDevicesKey.Success())
    {
        TraceTag(ttidError, "%S: Unable to open registry entry [HKLM\\%S]\n", __FUNCTION__, UPNPDEVICESKEY);
        return;
    }

    TraceTag(ttidLoader, "%S: Marking devices disabled until we read registry settings\n", __FUNCTION__);
    for (pListEntry = runningDeviceList.Flink; pListEntry != &runningDeviceList; pListEntry = pListEntry->Flink)
    {
        pDev = CONTAINING_RECORD(pListEntry,HostedDeviceInfo,link);
        pDev->newState = UPNPREG_DISABLED;   // until proven otherwise
    }

    // enumerate subkeys
    TraceTag(ttidLoader, "%S: Enumerating [HKLM\\%S] subkeys\n", __FUNCTION__, UPNPDEVICESKEY);
    RegEnumSubKeys enumDevices(&upnpDevicesKey);
    if(!enumDevices.Success())
    {
        TraceTag(ttidError, "%S: Error enumerating UpnpLoader subkeys\n", __FUNCTION__);
        return;
    }


    while (enumDevices.Next() == 0)
    {
        RegEntry upnpDeviceKey(enumDevices.GetName(), upnpDevicesKey.GetKey());
        if(!upnpDeviceKey.Success())
        {
            TraceTag(ttidError, "%S: Error reading %S from registry.  Continuing.\n", __FUNCTION__, enumDevices.GetName());
            continue;
        }

        UPNPREG_STATE state = (UPNPREG_STATE) upnpDeviceKey.GetNumber(L"State", UPNPREG_DISABLED);
        pDev = FindRunningDevice(upnpDeviceKey.GetString(UPNPUDN));
        // Now compare the registry state with our list and resolve the differences
        //  Registry:           RunningDeviceList:
        //  DISABLED          absent            => OK
        //  STARTING          absent            => new device, write STARTED
        //  STARTED           absent            => new device, write STARTED
        //  DISABLED          present           => remove device
        //  STARTING          present           => restart device, write STARTED
        //  STARTED           present           => OK
        if (!pDev)
        {
            switch (state)
            {
                case UPNPREG_DISABLED:
                    // nothing to do
                    break;
                case UPNPREG_STARTING:
                case UPNPREG_STARTED:
                    // new device
                    pDev = new HostedDeviceInfo(upnpDeviceKey.GetString(UPNPUDN));

                    if (pDev)
                    {
                        hr = pDev->Run(&upnpDeviceKey);
                        if (FAILED(hr))
                        {
                            TraceTag(ttidError, "%S:  Could not start device %ls hr=%x\n",__FUNCTION__, pDev->bstrDeviceId, hr);
                            delete pDev;
                            pDev = NULL;
                        }
                    }
                    if (!pDev)
                    {
                        // failed to start the device
                        upnpDeviceKey.SetValue(L"State",UPNPREG_DISABLED);
                    }
                    else
                    {
                        pDev->newState = UPNPREG_STARTED;
                        upnpDeviceKey.SetValue(L"State",pDev->newState);
                    }
                    break;
            }
        }
        else
        {
            // device is already in the list
            pDev->newState = state;
        }
    }

    // now go through the running devices and see if we need to stop any
    TraceTag(ttidLoader, "%S: Determine whether any devices need to be stopped.\n", __FUNCTION__);
    for (pListEntry = runningDeviceList.Flink; pListEntry != &runningDeviceList; )
    {
        pDev = CONTAINING_RECORD(pListEntry,HostedDeviceInfo,link);
        pListEntry = pListEntry->Flink;
        switch (pDev->newState)
        {
            case UPNPREG_STARTING:
            {
                TraceTag(ttidLoader,"%S: Stopping and restarting [%ls]\n", __FUNCTION__, pDev->bstrDeviceId);

                // anomalous. Handle by stopping and then restarting
                RegEntry upnpDeviceKey(pDev->bstrDeviceId, upnpDevicesKey.GetKey());
                pDev->Stop();   // removes the device from the running list
                
                // run will re-add the device to the list we are traversing but this should not be a problem
                hr = pDev->Run(&upnpDeviceKey);
                if(FAILED(hr))
                {
                    TraceTag(ttidError, "%S: Error restarting device [%ls]\n", __FUNCTION__, pDev->bstrDeviceId);
                    delete pDev;
                }
                break;
            }
            case UPNPREG_STARTED:
                // nothing to do
                break;

            case UPNPREG_DISABLED:
            default:
                // stop the device. The unregister is gratuitous since somebody has probably already
                // called Unregister to cause the registry key to go away.
                TraceTag(ttidLoader, "%S: Unregistering device [%ls]\n", __FUNCTION__, pDev->bstrDeviceId);
                hr = pDev->Stop();
                if(FAILED(hr))
                {
                    TraceTag(ttidError, "%S: Failed to unregister device [%ls].  May already be unregistered.\n", __FUNCTION__, pDev->bstrDeviceId);
                }
                delete pDev;
                break;
        }
    }

    CreateHTMLDeviceList();
    TraceTag(ttidLoader, "%S: Updated UpnpLoader running devices list\n", __FUNCTION__);
}


void HostedDeviceInfo::CleanupRunningDeviceList()
{
    HRESULT hr;
    LIST_ENTRY *pListEntry;
    HostedDeviceInfo *pDev;
    // now go through the running devices and see if we need to stop any
    for (pListEntry = runningDeviceList.Flink; pListEntry != &runningDeviceList; )
    {
        pDev = CONTAINING_RECORD(pListEntry,HostedDeviceInfo,link);
        hr = pDev->Stop();
        TraceTag(ttidInit, "Stop() returned %x\n", hr);
        delete pDev;
        pListEntry = runningDeviceList.Flink;
    }
}

BOOL
HostedDeviceInfo::CreateHTMLDeviceList()
{
    HANDLE hFile = INVALID_HANDLE_VALUE;
    LIST_ENTRY *pListEntry;
    HostedDeviceInfo *pDev;
    BOOL fRet = FALSE;
    DWORD dwWritten;
    PCSTR pszHTMLHeader = "<html>\r\n"
                         "<head><title>Registered UPnP Devices</title></head>\r\n"
                         "<h2>Hosted Devices</h2>\r\n";
    PCSTR pszHTMLTrailer = "</html>\r\n";
    CHAR szBuffer[1024];
    PWSTR pszTmpPath = new WCHAR [wcslen(g_pszHTMLDeviceListPath)+5];
    if (!pszTmpPath)
        return FALSE;
    wcscpy(pszTmpPath,g_pszHTMLDeviceListPath);
    wcscat(pszTmpPath,L".bak");  // append .bak to create the temp file name
    hFile = CreateFileW(pszTmpPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,0, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
        goto Cleanup;
    fRet = WriteFile(hFile, pszHTMLHeader, strlen(pszHTMLHeader), &dwWritten,NULL);
    if (!fRet)
        goto Cleanup;
    for (pListEntry = runningDeviceList.Flink; pListEntry != &runningDeviceList; pListEntry = pListEntry->Flink)
    {
        pDev = CONTAINING_RECORD(pListEntry,HostedDeviceInfo,link);
        sprintf(szBuffer,"<p>%ls",pDev->bstrDeviceId);
        fRet = WriteFile(hFile, szBuffer,strlen(szBuffer),&dwWritten, NULL);
        if (!fRet)
            break;
    }
    fRet = WriteFile(hFile, pszHTMLTrailer, strlen(pszHTMLTrailer), &dwWritten, NULL);
    if (!fRet)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -