我如何 read/change 另一个 windows 服务创建的注册表值?

How do I read/change the registry values that another windows service created?

所以基本上我有一个服务可以充当我的程序更新管理器。这是我做一个不需要用户登录的自动更新程序的全部努力。

因此,我的更新管理器在安装后会使用以下代码创建一些初始注册表 values/structures:

LPCWSTR strInITKeyName = L"SOFTWARE\InIT\";
DWORD rtime = 0;
HKEY InITKey;
LONG nInITError;
nInITError = RegOpenKeyEx(HKEY_LOCAL_MACHINE, strInITKeyName, 0, 0, &InITKey);
if (ERROR_NO_MATCH == nInITError || ERROR_FILE_NOT_FOUND == nInITError)
{
    std::cout << "Registry key not found.  Setting up..." << std::endl;
    long nError = RegCreateKeyEx(HKEY_LOCAL_MACHINE, strInITKeyName, 0L, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &InITKey, NULL);
    if (ERROR_SUCCESS != nError)
        std::cout << "Error:  Could not create registry key HKEY_LOCAL_MACHINE\" << strInITKeyName << std::endl << "\tERROR: " << nError << std::endl;
    else
    {
        std::cout << "Successfully created registry key HKEY_LOCAL_MACHINE\" << strInITKeyName << std::endl;

        // See https://www.experts-exchange.com/questions/10171094/Using-RegSetKeySecurity.html for example
        //SECURITY_DESCRIPTOR sd;
        //PACL pDacl = NULL;

        //RegSetKeySecurity(InITKey);
    }
}
else if (nInITError == ERROR_ACCESS_DENIED)
{
    long nError = RegCreateKeyEx(HKEY_LOCAL_MACHINE, strInITKeyName, 0L, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &InITKey, NULL);
    if (ERROR_SUCCESS != nError)
        std::cout << "Error:  Could not create registry key HKEY_LOCAL_MACHINE\" << strInITKeyName << std::endl << "\tERROR: " << nError << std::endl;
    else
        std::cout << "Successfully created registry key HKEY_LOCAL_MACHINE\" << strInITKeyName << std::endl;
}
else if (ERROR_SUCCESS != nInITError)
{
    std::cout << "Cannot open registry key HKEY_LOCAL_MACHINE\" << strInITKeyName << std::endl << "\tERROR: " << nInITError << std::endl;
    rtime = 0;
}

// Generate guid
//
GUID guid;
HRESULT hr = CoCreateGuid(&guid);

// Convert the GUID to a string
OLECHAR* guidString;
StringFromCLSID(guid, &guidString);

// Setup registry values
// Sets clientguid value and ties to strInITKeyName
std::wstring clientguid = guidString;   // InITKey
clientguid = clientguid.substr(1, 36);

LONG nClientGUIDError = RegSetValueEx(InITKey, L"clientguid", NULL, REG_SZ, (const BYTE*)clientguid.c_str(), (clientguid.size() + 1) * sizeof(wchar_t));
if (nClientGUIDError)
    std::cout << "Error: " << nClientGUIDError << " Could not set registry value: " << "clientguid" << std::endl;
else
    std::wcout << "Successfully set InIT clientguid to " << clientguid << std::endl;

// ensure memory is freed
::CoTaskMemFree(guidString);
RegCloseKey(InITKey);

卸载后,它会删除注册表值。我的实际程序是 windows 服务,它将在安装的计算机上 运行 需要访问其中一些注册表值。

以前我没有这个更新管理器,而是在实际程序服务中设置注册表中的值。那时阅读和写作工作得很好。但是因为我已经切换到让我的更新管理器设置这些初始值并打算让我的主要 windows 服务访问它们。

当我尝试执行此操作时,尽管尝试了各种不同的安全令牌,例如 KEY_READ ||,但我每次都会收到 ERROR_ACCESS_DENIED 错误。 KEY_WOW64_64KEY 和其他人在尝试打开钥匙时有很多组合。正如您在上面看到的,我在设置令牌时使用了 or-ing KEY_ALL_ACCESS。我想我应该能够很好地访问它,但它不允许我。我能得出的唯一结论是,我的更新管理器以某种方式拥有注册表中 keys/values 的所有权。

从我的主要 windows 服务访问这些注册表文件的正确代码是什么?

我当前用于访问这些注册表值的代码(我在安装更新管理器时生成的 clientguid 参见上面的代码):

// Log a service start message to the Application log.
WriteEventLogEntry(L"InITService Starting in OnStart", EVENTLOG_INFORMATION_TYPE);
this->m_ServiceLogger->info("Initialized logger bruh");

// Query clientguid from registry
HKEY InITKey;
std::wstring valuename;

ULONG nError = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\InIT\", 0, KEY_READ || KEY_WOW64_64KEY, &InITKey);

DWORD dwBufferSize = TOTALBYTES;
DWORD cbData;

WCHAR *wcBuffer = (WCHAR*)malloc(dwBufferSize);
cbData = dwBufferSize;
if (nError == ERROR_SUCCESS)
    this->m_ServiceLogger->info("Getting reg");

if (nError == ERROR_SUCCESS)
{
    std::wstring clientguid;
    clientguid = L"";
    valuename = L"clientguid";

    nError = RegQueryValueExW(HKEY_LOCAL_MACHINE, valuename.c_str(), 0, NULL, (LPBYTE) wcBuffer, &cbData);

    while (nError == ERROR_MORE_DATA)       // Get a buffer that is big enough if not already
    {
        this->m_ServiceLogger->info("Increasing clientguid buffer size");
        dwBufferSize += BYTEINCREMENT;
        wcBuffer = (WCHAR*) realloc( wcBuffer, dwBufferSize );
        cbData = dwBufferSize;

        nError = RegQueryValueExW(HKEY_LOCAL_MACHINE, valuename.c_str(), 0, NULL, (LPBYTE)wcBuffer, &cbData);
    }
    if (ERROR_SUCCESS == nError)
    {
        clientguid = wcBuffer;
        std::string cg(clientguid.begin(), clientguid.end());
        this->m_ClientGuid = cg;
        this->m_ServiceLogger->info("Clientguid yo: " + cg);
    }
    else if (nError = ERROR_ACCESS_DENIED)
        this->m_ServiceLogger->info("ClientGUID:  Access Denied");
    if (!this->checkRegistryValues())
    {
        this->generateRegistry();
    }
}
else
{
    std::stringstream errstr;
    errstr << nError;
    this->m_ServiceLogger->info("Error: " + errstr.str() + " RegOpenKeyEx failed");
}

this->setSchedulingUtility();  // Hardcoded to set scheduled update at 1:00 AM

WriteEventLogEntry(L"InITService Initialized Schedule in OnStart", EVENTLOG_INFORMATION_TYPE);
this->m_ServiceLogger->info("Initialized ClientGUID: " + this->m_ClientGuid);
this->m_ServiceLogger->info("Initialized CurrentVersion: " + this->m_CurrentVersion);
this->m_ServiceLogger->info("Initialized WebServerURL: " + this->m_POSTAddress);
this->m_ServiceLogger->flush();

RegCloseKey(InITKey);

// Queue the main service function for execution in a worker thread.
CThreadPool::QueueUserWorkItem(&CSampleService::ServiceWorkerThread, this);

调用RegOpenKeyEx()时,需要使用BITWISE OR (|)运算符,而不是LOGICAL OR (||)运算符。变化:

KEY_READ || KEY_WOW64_64KEY

收件人:

KEY_READ | KEY_WOW64_64KEY

但是,当您的更新管理器调用 RegOpenKeyEx() 时,它根本没有指定任何访问权限,而是将 samDesired 参数设置为 0。它应该至少将其设置为 KEY_SET_VALUE 代替。如果 RegOpenKeyEx() 失败,当它调用 RegCreateKeyEx() 时,它会将 samDesired 设置为 KEY_ALL_ACCESS。不要那样做。仅使用您实际需要的访问权限(KEY_SET_VALUE,等等)。

无论如何,没必要同时调用RegOpenKeyEx()RegCreateKeyEx()。直接调用 RegCreateKeyEx() 即可。它将打开一个现有密钥,并创建一个不存在的密钥。它的 dwDisposition 输出参数会告诉你发生了什么。

此代码中还有其他错误。就像将错误的 HKEY 传递给 RegQueryValueEx(),并且没有正确检查 ERROR_ACCESS_DENIED 错误代码(使用 = 赋值运算符而不是 == 比较运算符) .和内存泄漏。

尝试更像这样的东西:

更新管理器:

LPCWSTR strInITKeyName = L"SOFTWARE\InIT\";
HKEY InITKey;
DWORD dwDisposition;

LONG nError = RegCreateKeyEx(HKEY_LOCAL_MACHINE, strInITKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE | KEY_WOW64_64KEY, NULL, &InITKey, &dwDisposition);

if (ERROR_SUCCESS != nError)
{
    std::cout << "Error: Could not open/create registry key HKEY_LOCAL_MACHINE\" << strInITKeyName << std::endl << "\tERROR: " << nError << std::endl;
}
else
{
    std::cout << "Successfully " << ((REG_CREATED_NEW_KEY == dwDisposition) ? "created" : "opened") << " registry key HKEY_LOCAL_MACHINE\" << strInITKeyName << std::endl;

    // Generate guid and convert to a string
    //
    std::wstring clientguid;
    GUID guid;

    HRESULT hr = CoCreateGuid(&guid);
    if (FAILED(hr))
    {
        std::cout << "Error: Could not generate clientguid" << std::endl << "\tERROR: " << (int)hr << std::endl;
    }
    else
    {
        WCHAR guidString[40] = {0};
        int len = StringFromGUID2(guid, guidString, 40);
        if (len > 2)
        {
            // Sets clientguid value and ties to strInITKeyName
            clientguid.assign(&guidString[1], len-2);
        }
    }

    // Setup registry values

    nError = RegSetValueEx(InITKey, L"clientguid", NULL, REG_SZ, (const BYTE*) clientguid.c_str(), (clientguid.size() + 1) * sizeof(wchar_t));
    if (ERROR_SUCCESS != nError)
        std::cout << "Error: Could not set registry value: clientguid" << std::endl << "\tERROR: " << nError << std::endl;
    else
        std::wcout << "Successfully set InIT clientguid to " << clientguid << std::endl;

    RegCloseKey(InITKey);
}

节目服务:

...

// Query clientguid from registry
HKEY InITKey;

LONG nError = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\InIT\", 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &InITKey);

if (ERROR_SUCCESS != nError)
{
    std::stringstream errstr;
    errstr << nError;
    this->m_ServiceLogger->info("Error: " + errstr.str() + " RegOpenKeyEx failed");
}
else
{
    this->m_ServiceLogger->info("Getting reg");

    std::vector<BYTE> buffer(TOTALBYTES + sizeof(wchar_t), 0); // extra room for a null terminator, in case it is missing in the Registry data
    DWORD cbData = TOTALBYTES;

    do
    {
        nError = RegQueryValueExW(InITKey, L"clientguid", 0, NULL, &buffer[0], &cbData);

        if (ERROR_MORE_DATA != nError)
            break;

        // Get a buffer that is big enough if not already
        this->m_ServiceLogger->info("Resizing clientguid buffer");

        buffer.resize(cbData + sizeof(wchar_t));
    }
    while (true);

    if (ERROR_SUCCESS == nError)
    {
        std::wstring clientguid = (WCHAR*) &buffer[0];
        std::string cg(clientguid.begin(), clientguid.end());

        this->m_ClientGuid = cg;
        this->m_ServiceLogger->info("Clientguid yo: " + cg);
    }
    else if (ERROR_ACCESS_DENIED == nError)
    {
        this->m_ServiceLogger->info("ClientGUID: Access Denied");
    }
    else
    {
        std::stringstream errstr;
        errstr << nError;
        this->m_ServiceLogger->info("Error: " + errstr.str() + " RegQueryValueEx failed");
    }

    RegCloseKey(InITKey);

    if (!this->checkRegistryValues())
    {
        this->generateRegistry();
    }
}

...