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

📄 locplugin.cpp

📁 Windows CE 6.0 Server 源码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
//
// 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.
//

// Abstract: Implements routines required to process plugin DLLs

#include <locCore.hpp>



// 
// Callbacks that plugins call
// 

// Process NewProviderReport callback
static DWORD NewProviderReportInd(HANDLE provContext, LOCATION_REPORT *pNewReport) {
    return g_pPluginMgr->NewProviderReportInd(provContext,pNewReport);
}

// Process ProviderUnavailable callback
static DWORD ProviderUnavailableInd(HANDLE provContext) {
    return g_pPluginMgr->ProviderUnavailableInd(provContext);
}

// Process NewResolverReport callback
static DWORD NewResolverReportInd(HANDLE resContext, LOCATION_REPORT *pNewReport) {
    return g_pPluginMgr->NewResolverReportInd(resContext, pNewReport);
}

//
// Helper functions
//

// Helper that reads a REG_MULTI_SZ of GUIDs, parses, and stores in pReportTypes.
static BOOL ReadGuidsFromReg(CReg *pRegPlugin, const WCHAR *pPluginName, const WCHAR *pRegValueName, 
                             GUID *pGuids, DWORD *pNumGuids, DWORD maxToRead) 
{
    const WCHAR *pRegString = pRegPlugin->ValueSZ(pRegValueName);

    DEBUGCHK(*pNumGuids == 0);

    if (NULL == pRegString) {
        DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Plugin <%s> does not have value <%s> set\r\n",pPluginName,pRegValueName));
        return FALSE;
    }

    const WCHAR *pTrav = pRegString;

    while (*pTrav) {
        if (*pNumGuids >= maxToRead) {
            DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Plugin <%s> has > <%d> guids for <%s>\r\n",pPluginName,maxToRead,pRegValueName));
            return FALSE;
        }

        if (! svsutil_ReadGuidW(pTrav,&pGuids[*pNumGuids],TRUE)) {
            DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Plugin <%s> has misformatted GUID report type number: <%d>\r\n",pPluginName,*pNumGuids));
            return FALSE;
        }

        *pNumGuids = (*pNumGuids) + 1;
        // For REG_SZ case, we're done after reading our first GUID
        if (maxToRead == 1)
            return TRUE;

        // REG_MULTI_SZ case, move on to next string.
        pTrav += wcslen(pTrav) + 1;
    }

    return ((*pNumGuids) > 0);
}

//
//  Threads spun up to process GetLocation & Stop calls into the plugins.
//

// Thread spun when a provider is requested to generate reports
static DWORD GetProviderLocationThread(LPVOID lpv) {
    provider_t *pProv = (provider_t*)lpv;
    pProv->GetProviderLocation();
    return 0;
}

// Thread spun when a resolver is requested to resolve reports
static DWORD GetResolverLocationThread(LPVOID lpv) {
    resolver_t *pRes = (resolver_t*)((plugin_t*)lpv);
    pRes->GetResolverLocation();
    return 0;
}


//
// plugin_t implementation - basic plugin object.  The provider
// and resolver inherit from this implementation
//

// Create base plugin, reading as much as possible.
plugin_t::plugin_t(CReg *pRegPlugin, const WCHAR *keyName) {
    DEBUGCHK(pRegPlugin->IsOK());

    DWORD regValueType;
    DWORD regValueLen;

    m_numActiveIoctlCallers = 0;
    m_workerThrdCookie      = 0;
    m_loadSuccess           = FALSE;
    m_pluginState           = PLUGIN_STATE_ERROR;
    m_immediateRestart      = FALSE;

    memset(m_receivedReport,0,sizeof(m_receivedReport));

    m_dllName = pRegPlugin->ValueSZ(g_rvDll);
    if (m_dllName.empty()) {
        DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Plugin <%s> does not have DLL set\r\n",keyName));
        return;
    }

    DWORD numGuids = 0; // dummy variable...
    if (! ReadGuidsFromReg(pRegPlugin,keyName,g_rvGuid,&m_guid,&numGuids,1))
        return;

    if (! pRegPlugin->GetLengthAndType(g_rvPreference,&regValueLen,&regValueType)) {
        DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Plugin <%s> does not have Preference set\r\n",keyName));
        return;
    }
    m_preference = pRegPlugin->ValueDW(g_rvPreference);

    
    m_pluginFlags = pRegPlugin->ValueDW(g_rvPluginFlags);
    if (PLUGIN_FLAGS_DISABLED & m_pluginFlags) {
        DEBUGMSG(ZONE_PLUGIN,(L"LOC: ERROR: Plugin <%s> has been disabled via PLUGIN_FLAGS_DISABLED setting\r\n",keyName));
        return;
    }


    if (! pRegPlugin->GetLengthAndType(g_rvRetryOnFailure,&regValueLen,&regValueType)) {
        DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Plugin <%s> does not have RetryOnFailure set.\r\n",keyName));
        return;
    }
    m_retryOnFailure = pRegPlugin->ValueDW(g_rvRetryOnFailure);

			
    if (! pRegPlugin->GetLengthAndType(g_rvMaximumInitialWait,&regValueLen,&regValueType)) {
        DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Plugin <%s> does not have MaximumInitialWait set.\r\n",keyName));
        return;
    }
    m_initialWaitTime = pRegPlugin->ValueDW(g_rvMaximumInitialWait);


    m_numGeneratedReportTypes = 0;
    if (! ReadGuidsFromReg(pRegPlugin,keyName,g_rvGeneratedReports,m_generatedReportTypes,
                           &m_numGeneratedReportTypes,MAX_PLUGIN_REPORT_TYPES)) {
        return;
    }

    m_friendlyName = pRegPlugin->ValueSZ(g_rvFriendlyName);    
    if (m_friendlyName.size() >= MAX_PLUGIN_FRIENDLY_NAME) {
        DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Plugin <%s> has friendly name > <%d> characters\r\n",keyName,MAX_PLUGIN_FRIENDLY_NAME));
        // This is not a fatal error.  However we do need to clear this, since
        // later we assume the length is < MAX_PLUGIN_FRIENDLY_NAME chars.
        m_friendlyName = NULL;
    }

    m_version = pRegPlugin->ValueDW(g_rvVersion,1);
    m_pluginState = PLUGIN_STATE_OFF; // Indicate no errors so far.
    memset(&m_lastUpdate,0,sizeof(m_lastUpdate));
}

// Helper to load the plugin DLL itself
BOOL plugin_t::LoadPlugin(void) {
    DEBUGMSG(ZONE_PLUGIN,(L"LOC: Loading plugin for DLL <%s>\r\n",GetName()));

    m_dllHInstance = LoadLibrary(m_dllName);
    if (!m_dllHInstance.valid()) {
        DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: LoadLibrary on plugin DLL <%s> failed.  GLE=0x%08x\r\n",GetName(),GetLastError()));
        return FALSE;
    }

    return TRUE;
}

// Returns index int m_generatedReportTypes of given report, -1 if not supported
DWORD plugin_t::FindGeneratedReportIndex(const GUID *pReportType) {
    for (DWORD i = 0; i < m_numGeneratedReportTypes; i++) {
        if (0 == memcmp(&m_generatedReportTypes[i],pReportType,sizeof(GUID)))
            return i;
    }
    return (DWORD)-1;
}

// Returns TRUE if the plugin can generate (in theory, even if it plugin
// is not available at the moment) a report.
BOOL plugin_t::CanGenerateReportType(const GUID *pReportType) {
    return (FindGeneratedReportIndex(pReportType) != (DWORD)-1);
}

// When a plugin has a new report arrived, mark its type as such as such.
void plugin_t::IndicateReceivedReport(const GUID *pReportType) {
    DWORD index = FindGeneratedReportIndex(pReportType);
    DEBUGCHK(index < MAX_PLUGIN_REPORT_TYPES);
    m_receivedReport[index] = TRUE;
    GetCurrentFT(&m_lastUpdate);
}

// Determines whether a plugin has received a callback indicating
// report of this type.
BOOL plugin_t::HasReceivedReport(const GUID *pReportType) {
    DWORD index = FindGeneratedReportIndex(pReportType);
    DEBUGCHK(index < MAX_PLUGIN_REPORT_TYPES);
    return m_receivedReport[index];
}

// Fills out PLUGIN_INFORMATION structure for this plugin 
void plugin_t::GetPluginInfo(PLUGIN_INFORMATION *pPluginInfo) {
    pPluginInfo->version             = m_version;
    memcpy(&pPluginInfo->guid,&m_guid,sizeof(m_guid));
    wcscpy(pPluginInfo->friendlyName,m_friendlyName);
    pPluginInfo->pluginState         = m_pluginState;
    pPluginInfo->retryInterval       = m_retryOnFailure;
	pPluginInfo->maximumInitialWait = m_initialWaitTime;
    memcpy(&pPluginInfo->lastUpdate,&m_lastUpdate,sizeof(FILETIME));
    pPluginInfo->numReportsGenerated = m_numGeneratedReportTypes;
    memcpy(&pPluginInfo->reportsGenerated,m_generatedReportTypes,
           sizeof(GUID)*m_numGeneratedReportTypes);
    pPluginInfo->pluginFlags         = m_pluginFlags;
}

// Returns which reportTypes the plugin can possibly generate
void plugin_t::GetGeneratedReportInfo(GUID *pReportTypes, DWORD *numReportTypes) {
    if ((m_numGeneratedReportTypes == 0) || (m_numGeneratedReportTypes > MAX_PLUGIN_REPORT_TYPES)) {
        // pReportTypes is guaranteed to be MAX_PLUGIN_REPORT_TYPES*sizeof(GUID)
        // We do run-time check, rather only having DEBUGCHK, to satisfy prefix.
        DEBUGCHK(0);
        *numReportTypes = 0;
        return;
    }

    *numReportTypes = m_numGeneratedReportTypes;
    memcpy(pReportTypes,m_generatedReportTypes,m_numGeneratedReportTypes*sizeof(GUID));
}

// Alerts the plugin manager that a fatal error has occured during
// a callback.  The plugin manager processes this and in turn calls 
// SetFatalError back on the callback
void plugin_t::ReportFatalError() {
    // For locking, most of the time this function is called in the exception
    // handler for one of the callbacks where lock will not be held.  There
    // are some cases where g_pLocLock already is held by caller, but extra
    // lock is OK because FatalPluginError never releases the lock.
    g_pLocLock->Lock();
    g_pPluginMgr->FatalPluginError(this);
    g_pLocLock->Unlock();
}

// Called when a plugin is in the process of shutting down when a new
// application has registered for it and hence it needs to restart right away.
void plugin_t::SetImmediateRestart(void) {
    m_immediateRestart = TRUE;
}


// Blocks until any PSL calls into the plugin IOCTL processor have returned.
void plugin_t::WaitOnOpenIoctlCalls(void) {
    DEBUGCHK(g_pLocLock->IsLocked());

#ifdef DEBUG
    // Number of times we've polled while waiting to shutdown.
    DWORD numRetries = 0;
#endif

    while (m_numActiveIoctlCallers) {
#ifdef DEBUG
        numRetries++;
        // Taking this many retries indicates plugin IOCTL worker(s) blocked too long.
        // This is not fatal but merits investigation.
        DEBUGCHK(g_pollRetriesWarnOnUnload != numRetries);
#endif

        DEBUGMSG(ZONE_PLUGIN | ZONE_THREAD,(L"LOC: Waiting <%d> ms for plugin <%s> IOCTL calls to complete\r\n",
                                            g_pollOnUnload,GetName()));
        g_pLocLock->Unlock();
        Sleep(g_pollOnUnload);
        g_pLocLock->Lock();
    }
}

// Block until the plugin's ProviderGetLocation/ResolverGetLocation
// thread comes to a halt
void plugin_t::WaitOnRunningGetLocThread(void) {
    DEBUGCHK(g_pLocLock->IsLocked());
#ifdef DEBUG
    // Number of times we've polled while waiting to shutdown.
    DWORD numRetries = 0;
#endif

    while (m_workerThrdCookie) {
#ifdef DEBUG
        numRetries++;
        // Taking this many retries indicate plugin stop thread is blocked for too long.
        // This is not fatal but merits investigation.
        DEBUGCHK(g_pollRetriesWarnOnUnload != numRetries);
#endif

        DEBUGMSG(ZONE_PLUGIN | ZONE_THREAD,(L"LOC: Waiting <%d> ms for plugin <%s> GetLocationReport thread to complete\r\n",
                                            g_pollOnUnload,GetName()));
        g_pLocLock->Unlock();
        Sleep(g_pollOnUnload);
        g_pLocLock->Lock();
    }

}

#ifdef DEBUG
// Print GUIDs in a list to DEBUGOUT
void DbgPrintGuids(const GUID *pGuids, DWORD numGuids) {
    for (DWORD i = 0; i < numGuids; i++) {
        DEBUGMSG(1,(L"LOC:     GUID = <" SVSUTIL_GUID_FORMAT_W L">\r\n",
                  SVSUTIL_RGUID_ELEMENTS(pGuids[i])));
    }
}

// Prints PLUGIN_INFORMATION to DEBUGOUT
void plugin_t::DbgPrintSettings(void) {
    DEBUGMSG(1,(L"LOC:   DllName = <%s>, GUID=<" SVSUTIL_GUID_FORMAT_W L">\r\n",
                GetName(), SVSUTIL_RGUID_ELEMENTS(m_guid)));
    DEBUGMSG(1,(L"LOC:   Preference = <%d>, PluginFlags = <0x%08x>, Retry On Failure = <%d>\r\n",
                m_preference,m_pluginFlags,m_retryOnFailure));
    DEBUGMSG(1,(L"LOC:   Generated GUIDs: \r\n"));
    DbgPrintGuids(m_generatedReportTypes,m_numGeneratedReportTypes);
}
#endif


// Delete resources associated with plugin.  If plugin is on,
// then take care of alerting it to the new state. 
// This BLOCKS until the plugin is ready to be unloaded - i.e. all
// open threads are finished running.

provider_t::~provider_t() {
    if (! m_loadSuccess) {
        DEBUGCHK(g_serviceState == SERVICE_STATE_STARTING_UP);
        // If loading the plugin failed, then we shouldn't call into
        // Stop/Uninitialize at all.
        return;
    }
    DEBUGMSG(ZONE_INIT | ZONE_PROVIDER,(L"LOC: Beginning to uninit Provider DLL <%s>\r\n",GetName()));

    if (m_pluginState >= PLUGIN_STATE_UNAVAILABLE) {
        // The plugin's stop still needs to be called.  Do here, rather
        // than spawning up a thread.
        SetState(PLUGIN_STATE_SHUTTING_DOWN);
        CallProvStop();
    }

    // Wait until any outstanding references to the provider have stopped
    WaitOnOpenIoctlCalls();
    WaitOnRunningGetLocThread();

    // Finally, call the uninit.
    CallProvUnInit();

    DEBUGMSG(ZONE_INIT | ZONE_PROVIDER,(L"LOC: Completed uninit Provider DLL <%s>\r\n",GetName()));
}

//
// provider_t implements provider wrapper
//

// Reads provider registry settings, loads DLLs, and call ProviderInitialize
void provider_t::InitProvider(CReg *pRegPlugin, const WCHAR *keyName) {
    DEBUGMSG(ZONE_PROVIDER,(L"LOC: Initializing provider <%s>\r\n",keyName));
    DEBUGCHK(m_pluginState == PLUGIN_STATE_ERROR); // Should've been reset before calling here

    DWORD regValueType;
    DWORD regValueLen;


    // Read registry settings
    if (! pRegPlugin->GetLengthAndType(g_rvPollInterval, &regValueLen, &regValueType)) {

⌨️ 快捷键说明

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