📄 locplugin.cpp
字号:
DEBUGMSG(ZONE_INIT | ZONE_RESOLVER,(L"LOC: Beginning to uninit Resolver DLL <%s>\r\n",GetName()));
if (m_pluginState >= PLUGIN_STATE_UNAVAILABLE) {
// The plugin's stop still needs to be called.
if (m_getRepThrdCalledFirstTime) {
m_pluginState = PLUGIN_STATE_SHUTTING_DOWN;
CallResStop();
}
}
// Wait until any outstanding references to the resolver have stopped
WaitOnOpenIoctlCalls();
WaitOnRunningGetLocThread();
// Finally, call the uninit.
CallResUnInit();
DEBUGMSG(ZONE_INIT | ZONE_RESOLVER,(L"LOC: Completed uninit Resolver DLL <%s>\r\n",GetName()));
}
// Called on initialization of resolver - reads in base settings & calls
// ResolverInitialize
void resolver_t::InitResolver(CReg *pRegPlugin, const WCHAR *keyName) {
DEBUGMSG(ZONE_RESOLVER,(L"LOC: Initializing resolver <%s>\r\n",keyName));
DEBUGCHK(m_pluginState == PLUGIN_STATE_ERROR); // Should've been reset before calling here
DWORD regValueType;
DWORD regValueLen;
m_lastResolution = 0;
m_getRepThrdCalledFirstTime = FALSE;
SetAllReportStates(PLUGIN_STATE_OFF);
m_pluginState = PLUGIN_STATE_ERROR;
// Only indicate no providers when we actually have providers indicating failure.
// By default assume providers can in theory work, only set this FALSE when
// all providers we would care about actually fail on us.
m_providersAvailable = TRUE;
m_providerGenerator = NULL;
m_reportCollector = NULL;
// Fill out remainder of array with report types not generated
for (DWORD i = m_numGeneratedReportTypes; i < MAX_PLUGIN_REPORT_TYPES; i++)
m_reportStates[i] = PLUGIN_STATE_NOT_SUPPORTED;
// Read registry settings
if (! pRegPlugin->GetLengthAndType(g_rvMinimumRequery, ®ValueLen, ®ValueType)) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Resolver <%s> does not have MinimumRequery set.\r\n",keyName));
return;
}
m_minRequery = pRegPlugin->ValueDW(g_rvMinimumRequery);
m_resolverFlags = pRegPlugin->ValueDW(g_rvResolverFlags);
m_numSupportedReportTypes = 0;
if (! ReadGuidsFromReg(pRegPlugin,keyName,g_rvSupportedReports,m_supportedReportTypes,
&m_numSupportedReportTypes,MAX_PLUGIN_REPORT_TYPES)) {
return;
}
// Load dll and get function exports
if (! LoadPlugin())
return;
m_pfnInitialize = (PFN_RESINITIALIZE)GetProcAddress(m_dllHInstance,L"ResolverInitialize");
m_pfnGetLocation = (PFN_RESGETLOCATION)GetProcAddress(m_dllHInstance,L"ResolverGetLocation");
m_pfnStop = (PFN_RESSTOP)GetProcAddress(m_dllHInstance,L"ResolverStop");
m_pfnUnInitialize = (PFN_RESUNINITIALIZE)GetProcAddress(m_dllHInstance,L"ResolverUnInitialize");
m_pfnIoctlOpen = (PFN_RESOPEN)GetProcAddress(m_dllHInstance,L"ResolverIoctlOpen");
m_pfnIoctlCall = (PFN_RESIOCTL)GetProcAddress(m_dllHInstance,L"ResolverIoctlCall");
m_pfnIoctlClose = (PFN_RESCLOSE)GetProcAddress(m_dllHInstance,L"ResolverIoctlClose");
if (! (m_pfnInitialize && m_pfnGetLocation && m_pfnStop &&
m_pfnUnInitialize && m_pfnIoctlOpen && m_pfnIoctlCall && m_pfnIoctlClose))
{
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: Provider <%s> does not export all required functions\r\n",keyName));
return;
}
RESOLVER_INFORMATION resInfo;
GetResolverInfo(&resInfo);
DWORD err;
resInfo.pluginInfo.pluginState = PLUGIN_STATE_OFF;
if (ERROR_SUCCESS != (err = CallResInit(&resInfo))) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: ResolverInitialize for <%s> returned <0x%08x>. Will not use this provider\r\n",
GetName(),err));
return;
}
m_pluginState = PLUGIN_STATE_OFF;
m_loadSuccess = TRUE;
#ifdef DEBUG
if (ZONE_RESOLVER) {
DEBUGMSG(1,(L"LOC: Loaded Resolver from reg key <%s>. Settings:\r\n",keyName));
DbgPrintSettings();
DEBUGMSG(1,(L"LOC: MinRequery = <0x%08x>, ResolverFlags = <0x%08x>\r\n",m_minRequery,m_resolverFlags));
DEBUGMSG(1,(L"LOC: Supported Guids\r\n"));
DbgPrintGuids(m_supportedReportTypes,m_numSupportedReportTypes);
}
#endif
return;
}
// Fills out RESOLVER_INFORMATION structure for this resolver
void resolver_t::GetResolverInfo(RESOLVER_INFORMATION *pResInfo) {
GetPluginInfo(&pResInfo->pluginInfo);
pResInfo->minRequeryInterval = m_minRequery;
pResInfo->numReportsSupported = m_numSupportedReportTypes;
memcpy(&pResInfo->reportsSupported,m_supportedReportTypes,sizeof(m_supportedReportTypes));
pResInfo->resolverFlags = m_resolverFlags;
}
// Returns which reportTypes the plugin can possibly generate
void resolver_t::GetSupportedReportInfo(GUID *pReportTypes, DWORD *numReportTypes) {
if ((m_numSupportedReportTypes == 0) || (m_numSupportedReportTypes > 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_numSupportedReportTypes;
memcpy(pReportTypes,m_supportedReportTypes,m_numSupportedReportTypes*sizeof(GUID));
}
// Returns TRUE if the resolver can (in theory) support reports of a particular
// report type for resolution.
BOOL resolver_t::CanSupportReportType(const GUID *pReportType) {
for (DWORD i = 0; i < m_numSupportedReportTypes; i++) {
if (0 == memcmp(&m_supportedReportTypes[i],pReportType,sizeof(GUID)))
return TRUE;
}
return FALSE;
}
// For resolvers, since each report type may or may not be available independent
// of the other report types *for the same resolver DLL*, need a little more
// complicated logic here. (Note that provider implementation of this function
// just returns the global state for that provider)
PLUGIN_STATE resolver_t::GetReportTypeState(const GUID *pReportType) {
for (DWORD i = 0; i < m_numGeneratedReportTypes; i++) {
if (0 == memcmp(pReportType,&m_generatedReportTypes[i],sizeof(GUID)))
return m_reportStates[i];
}
// Indicates plugin does not support this type.
return PLUGIN_STATE_NOT_SUPPORTED;
}
// Indicates particular report type isn't available anymore
void resolver_t::ReportTypeUnavailable(const GUID *pReportType) {
SetState(pReportType,PLUGIN_STATE_UNAVAILABLE);
}
void resolver_t::ReportTypeAvailable(const GUID *pReportType) {
SetState(pReportType,PLUGIN_STATE_ON);
}
// Indicates that the Resolver should generate the requested report type
void resolver_t::RequestReportGeneration(const GUID *pReportType) {
DEBUGCHK(m_pluginState != PLUGIN_STATE_ERROR);
DWORD index = FindGeneratedReportIndex(pReportType);
DEBUGCHK(index != (DWORD)-1);
if (m_reportStates[index] == PLUGIN_STATE_OFF) {
// Only update the state if we're transitioning from the OFF state.
// If we're in another state (say already ON or Unavail) then leave it as it previously was.
SetState(pReportType,PLUGIN_STATE_STARTING_UP);
}
}
void resolver_t::CancelReportGeneration(const GUID *pReportType) {
DEBUGCHK(CanGenerateReportType(pReportType));
DEBUGCHK(m_pluginState >= PLUGIN_STATE_UNAVAILABLE);
// Set individual report state to shutting down for now. resolver_t::StopPlugin
// and/or GetResolverLocation will ultimately set this state to OFF.
SetState(pReportType,PLUGIN_STATE_SHUTTING_DOWN);
}
// Change the state of particular reportType in resolver. Note that report
// types in the same resolver may be independent of each other; i.e. generated
// report type #1 may be PLUGIN_STATE_ON while #2 report is PLUGIN_STATE_OFF/UNAVAIL/...
void resolver_t::SetState(const GUID *pReportType, PLUGIN_STATE newState) {
if (m_pluginState == PLUGIN_STATE_ERROR) {
// Once plugin has entered an error condition, it can never get out of it.
return;
}
DWORD index = FindGeneratedReportIndex(pReportType);
// Plugin Manager will only call this function if resolver supports it.
DEBUGCHK(index < m_numGeneratedReportTypes);
#ifdef DEBUG
if (newState != m_reportStates[index]) {
DEBUGMSG(ZONE_RESOLVER && ZONE_VERBOSE,(L"LOC: Changing plugin <%s>, for Report type <" SVSUTIL_GUID_FORMAT_W
L"> from state <%d> to state <%d>\r\n",
GetName(),SVSUTIL_PGUID_ELEMENTS(pReportType),
m_pluginState,newState));
}
#endif
m_reportStates[index] = newState;
// What we change the "global" resolver state to (i.e. what we tell
// apps querying this plugin state) is based on the "highest" available
// report. The PLUGIN_STATE enum is ordered with the highest
// (PLUGIN_STATE_ON) coming last.
m_pluginState = PLUGIN_STATE_ERROR;
for (DWORD i = 0; i < m_numGeneratedReportTypes; i++)
m_pluginState = max(m_pluginState,m_reportStates[i]);
}
// Helper to change all report states at the same type
void resolver_t::SetAllReportStates(PLUGIN_STATE newState) {
for (DWORD i = 0; i < m_numGeneratedReportTypes; i++)
m_reportStates[i] = newState;
m_pluginState = newState;
}
// Indicates that a fatal error has occured
void resolver_t::SetFatalError() {
SetAllReportStates(PLUGIN_STATE_ERROR);
}
// Function that sets up resolver control block to be sent to the resolver
void resolver_t::FillRCB(RESOLVER_CONTROL_BLOCK *pRcb, RESOLVER_INFORMATION *pResInfo, reportSmartPtr_t &pProvReport) {
pRcb->numTypesToResolve = 0;
// Determine which report types the resolver should be asked to return.
for (DWORD i = 0; i < m_numGeneratedReportTypes; i++) {
PLUGIN_STATE repState = m_reportStates[i];
if ((repState == PLUGIN_STATE_ON) || (repState == PLUGIN_STATE_STARTING_UP) ||
(repState == PLUGIN_STATE_UNAVAILABLE))
{
// In this case we try to resolve this report
memcpy(&pRcb->typesToResolve[pRcb->numTypesToResolve],&m_generatedReportTypes[i],sizeof(GUID));
pRcb->numTypesToResolve++;
}
}
if (pRcb->numTypesToResolve == 0) {
// No work to do in this case; caller will return immediately
return;
}
GetResolverInfo(pResInfo);
pRcb->version = LOCATION_FRAMEWORK_VERSION_CURRENT;
pRcb->resContext = (HANDLE)this;
pRcb->pResInfo = pResInfo;
pProvReport = m_reportCollector->GetReport();
pRcb->provReport = pProvReport;
pRcb->NewResolverReport = NewResolverReportInd;
}
// Calls into the resolver's ResolverGetLocation to resolve reports.
void resolver_t::GetResolverLocation(void) {
RESOLVER_CONTROL_BLOCK rcb;
RESOLVER_INFORMATION resInfo;
DWORD i;
FILETIME reportCreationTime;
g_pLocLock->Lock();
DEBUGCHK(m_workerThrdCookie != 0);
// Hold a smart pointer reference to the memory returned by the RC.
// Do this so that should the RC receive a new report during processing
// of this function, the memory won't be freed because we'll have an
// extra ref count.
reportSmartPtr_t pProvReport = NULL;
DEBUGMSG(ZONE_RESOLVER | ZONE_THREAD,(L"LOC: Beginning ResolverGetLocation thread for resolver <%s>\r\n",GetName()));
if (m_pluginState <= PLUGIN_STATE_SHUTTING_DOWN) {
DEBUGMSG(ZONE_RESOLVER,(L"LOC: Exiting thread for ResolveLookup for <%s> since state = <%d>\r\n",
GetName(),m_pluginState));
m_workerThrdCookie = 0;
goto done;
}
if (m_providersAvailable == FALSE) {
// There is a small time window where the last provider could've become unavailable
// before this worker thread could be unscheduled. Since we ignore
// new resolver reports once we reach this stage anyway, don't even
// bother calling resolver DLL export.
DEBUGMSG(ZONE_RESOLVER,(L"LOC: Exiting thread for ResolveLookup for <%s> since no providers are available\r\n",GetName()));
m_workerThrdCookie = 0;
goto done;
}
// Fill out data structures to pass to LF.
FillRCB(&rcb,&resInfo,pProvReport);
memcpy(&reportCreationTime,&((LOCATION_REPORT_BASE*)rcb.provReport)->creationTime,sizeof(reportCreationTime));
// Reset our received reports for the next pass
memset(m_receivedReport,0,sizeof(m_receivedReport));
// If we don't need any report types resolved, then stop now.
if (rcb.numTypesToResolve == 0) {
DEBUGMSG(ZONE_RESOLVER,(L"LOCATION: GetResolverLocation thread for <%s> returning since no reports needed to resolve\r\n",GetName()));
m_workerThrdCookie = 0;
goto done;
}
#ifdef DEBUG
if (ZONE_RESOLVER) {
DEBUGMSG(1,(L"LOC: About to call ResolverGetLocation for Resolver <%s> with following report type(s) to resolve\r\n",GetName()));
DbgPrintGuids(rcb.typesToResolve,rcb.numTypesToResolve);
}
#endif
// Indicate that this thread has now been called.
m_getRepThrdCalledFirstTime = TRUE;
// Actually call the DLL export. This may block for a long time potentially,
// but it is not designed to block as long as there are apps registered
// for it (unlike ProviderGetLocation()).
DWORD err = CallResGetLocation(&rcb);
if (err != ERROR_SUCCESS) {
ReportFatalError();
m_workerThrdCookie = 0;
goto done;
}
// During the resolution cycle, the LF service itself has
// been shutdown. No point in continuing.
if (g_serviceState != SERVICE_STATE_ON) {
m_workerThrdCookie = 0;
goto done;
}
// Now that call has returned, for any registered report type for
// which a report was not returned, mark as unavailable and have
// plugin manager start the next in line.
for (i = 0; i < m_numGeneratedReportTypes; i++) {
if ((m_reportStates[i] >= PLUGIN_STATE_STARTING_UP) && !m_receivedReport[i]) {
// We wanted a report for this type but resolver did not generate one.
// The first time this occurs, alert plugin manager.
g_pPluginMgr->ResolverReportTypeUnavailable(this, &m_generatedReportTypes[i]);
DEBUGCHK(m_reportStates[i] == PLUGIN_STATE_UNAVAILABLE);
}
}
m_workerThrdCookie = 0;
GetCurrentFT((FILETIME*)&m_lastResolution);
if (m_providersAvailable == FALSE) {
// During ResolverGetLocationCall(), all possible providers that could
// generate reports for this resolver have become unavailable.
// Do not reschedule another worker thread - wait for provider
// to become available again.
goto done;
}
if (m_pluginState == PLUGIN_STATE_UNAVAILABLE) {
// If we failed to resolve any reports in our last resolution
// attempt, then we need to try again.
ScheduleNextResolution();
}
else if ((m_pluginState >= PLUGIN_STATE_STARTING_UP) && (m_reportCollector->HasNewReport(&reportCreationTime))) {
// A new provider report has arrived since we have completed this resolution.
// Schedule a new worker thread to do the lookup
ScheduleNextResolution();
}
else {
;
// else {...} we have resolved a report & no new provider reports have
// since arrived, so no need to reschedule. This worker will be rescheduled
// when the next provider report comes in.
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -