Extensão da classe auxiliar NDF
Este exemplo ilustra como implementar funções de diagnóstico e reparo do NDF. Neste exemplo, um arquivo de configuração crítico deve existir para que o sistema permaneça íntegro. Assim, o problema é determinar se o arquivo existe. Se isso não acontecer, o sistema não estará íntegro e o problema será diagnosticado pelo NDF. O reparo é recriar o arquivo ausente.
Para diagnosticar e reparar o problema, é necessário usar quatro métodos INetDiagHelper : Initialize, LowHealth, GetRepairInfo e Repair.
Inicializando a classe auxiliar
Inicialize e recupere o nome do arquivo a ser localizado. Esse nome de arquivo é passado durante o diagnóstico como um atributo auxiliar chamado "filename".
#include <windows.h>
//utility function to simplify string allocation and copies, user throughout example
HRESULT
StringCchCopyWithAlloc (
PWSTR* Dest,
size_t cchMaxLen,
in PCWSTR Src)
{
if (NULL == Dest || NULL == Src || cchMaxLen > USHRT_MAX)
{
return E_INVALIDARG;
}
size_t cchSize = 0;
HRESULT hr = StringCchLength(Src, cchMaxLen - 1, &cchSize);
if (FAILED(hr))
{
return hr;
}
size_t cbSize = (cchSize + 1)*sizeof(WCHAR);
*Dest = (PWSTR) CoTaskMemAlloc(cbSize);
if (NULL == *Dest)
{
return E_OUTOFMEMORY;
}
SecureZeroMemory(*Dest, cbSize);
return StringCchCopy((STRSAFE_LPWSTR)*Dest, cchSize + 1, Src);
}
HRESULT SimpleFileHelperClass::Initialize(
/* [in] */ ULONG celt,
/* [size_is][in] */ HELPER_ATTRIBUTE rgAttributes[ ])
{
if(celt < 1)
{
return E_INVALIDARG;
}
if(rgAttributes == NULL)
{
return E_INVALIDARG;
}
else
{
//verify the attribute is named as expected
if (wcscmp(rgAttributes[0].pwszName, L"filename")==0)
{
//copy the attribute to member variable
return StringCchCopyWithAlloc(&m_pwszTestFile, MAX_PATH,
rgAttributes[0].PWStr);
} else {
//the attribute isn't named as expected
return E_INVALIDARG;
}
}
}
Verificando a existência do arquivo
O método LowHealth é usado para marcar sobre a existência do arquivo. Se o arquivo existir, o diagnóstico status será definido como DS_REJECTED, indicando que nada está errado. Se o arquivo não puder ser encontrado, o diagnóstico status será definido como DS_CONFIRMED.
#include <windows.h>
HRESULT SimpleFileHelperClass::LowHealth(
/* [unique][string][in] */ LPCWSTR pwszInstanceDescription,
/* [string][out] */ LPWSTR *ppwszDescription,
/* [out] */ long *pDeferredTime,
/* [out] */ DIAGNOSIS_STATUS *pStatus)
{
HANDLE hFile = NULL;
LPWSTR pwszDiagString=NULL;
// does the file already exist?
hFile = CreateFile(
m_pwszTestFile,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(INVALID_HANDLE_VALUE == hFile)
{
// alloc and set the diagnosis description and status
HRESULT hr = StringCchCopyWithAlloc(&pwszDiagString, MAX_PATH,
L"The file was deleted.");
if (FAILED(hr))
{
return hr;
}
*ppwszDescription = pwszDiagString;
*pStatus = DS_CONFIRMED;
return S_OK;
}
CloseHandle(hFile);
//the file exists
*pStatus = DS_REJECTED;
return S_OK;
}
Determinando a ação de reparo
Se LowHealth retornar DS_CONFIRMED, GetRepairInfo será implementado para determinar a ação de reparo apropriada. Neste exemplo, isso significa recriar o arquivo.
#include <windows.h>
HRESULT
SimpleFileHelperClass::GetRepairInfo(
/* [in] */ PROBLEM_TYPE problem,
/* [out] */ ULONG *pcelt,
/* [size_is][size_is][out] */ RepairInfo **ppInfo)
{
HRESULT hr=S_OK;
RepairInfo* pRepair = (RepairInfo *)CoTaskMemAlloc(sizeof(RepairInfo));
if (pRepair == NULL) {
return E_OUTOFMEMORY;
}
SecureZeroMemory(pRepair,sizeof(RepairInfo));
// set the repair description and class name
hr = StringCchCopyWithAlloc(&pRepair->pwszClassName, MAX_PATH,
L"SimpleFileHelperClass");
if (FAILED(hr))
{
goto Error;
}
hr = StringCchCopyWithAlloc(&pRepair->pwszDescription, MAX_PATH,
L"Low Health Repair");
if (FAILED(hr))
{
goto Error;
}
// set the resolution GUID and cost
pRepair->guid = ID_LowHealthRepair;
pRepair->cost = 0;
// set repair status flags
pRepair->sidType = WinWorldSid;
pRepair->scope = RS_SYSTEM;
pRepair->risk = RR_NORISK;
pRepair->flags |= DF_IMPERSONATION; //impersonate the user when repairing
pRepair->UiInfo.type = UIT_NONE;
//pass back the repair
*ppInfo = pRepair;
*pcelt = 1; //number of repairs
return S_OK;
Error:
if(pRepair){
if(pRepair->pwszClassName){
CoTaskMemFree(pRepair->pwszClassName);
}
if(pRepair->pwszDescription){
CoTaskMemFree(pRepair->pwszDescription);
}
}
return hr;
}
Reparando o problema
O usuário recebe as opções de correção retornadas pelo GetRepairInfo, a menos que haja apenas uma opção de reparo, nesse caso, ela é executada automaticamente. O método Repair é chamado com a estrutura RepairInfo aplicável para que o arquivo de configuração possa ser restaurado.
#include <windows.h>
HRESULT
SimpleFileHelperClass::Repair(
/* [in] */ RepairInfo *pInfo,
/* [out] */ long *pDeferredTime,
/* [out] */ REPAIR_STATUS *pStatus)
{
//verify expected repair was requested
if(IsEqualGUID(ID_LowHealthRepair, pInfo->guid)){
HANDLE hFile = NULL;
hFile = CreateFile(m_pwszTestFile,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(INVALID_HANDLE_VALUE == hFile)
{
// repair failed
*pStatus = RS_UNREPAIRED;
return HRESULT_FROM_WIN32(GetLastError());
}
CloseHandle(hFile);
// repair succeeded
*pStatus = RS_REPAIRED;
} else {
return E_INVALIDARG; //unkown repair passed in
}
return S_OK;
}