Extracting a function in shell extension programming - winapi

I want to extract some DropHandler code into a separate function, but have no idea how to do that while working with interface pointers or C++ in general. I want to get just the first item in DragEnter using a separate function.
HRESULT drop_handler::GetFirstItem(IDataObject* p_data_obj, IShellItemArray* items, IShellItem* first_item)
{
HRESULT hr = SHCreateShellItemArrayFromDataObject(p_data_obj, IID_PPV_ARGS(&items));
if (hr != ERROR_SUCCESS)
{
return E_INVALIDARG;
}
DWORD item_count;
items->GetCount(&item_count);
if (item_count != 1)
{
items->Release();
return E_INVALIDARG;
}
hr = items->GetItemAt(0, &first_item);
if (hr != ERROR_SUCCESS)
{
items->Release();
return E_INVALIDARG;
}
return ERROR_SUCCESS;
}
HRESULT drop_handler::DragEnter(IDataObject* p_data_obj, DWORD gtf_key_state, POINTL pt, DWORD* pdw_effect)
{
IShellItemArray* items = nullptr;
IShellItem* dragged_item = nullptr;
HRESULT hr = GetFirstItem(p_data_obj, items, dragged_item);
if (hr != ERROR_SUCCESS)
{
return E_INVALIDARG;
}
//...use dragged_item
This code attempt crashes Explorer big time. I'm not sure what kind of function signature and pointers I should be using to make it work.
Edit: Fixed answer per Anders
HRESULT drop_handler::GetFirstItem(IDataObject* p_data_obj, IShellItemArray*& items, IShellItem*& first_item)
{
HRESULT hr = SHCreateShellItemArrayFromDataObject(p_data_obj, IID_PPV_ARGS(&items));
if (hr != ERROR_SUCCESS)
{
return E_INVALIDARG;
}
DWORD item_count;
hr = items->GetCount(&item_count);
if (hr != ERROR_SUCCESS || item_count != 1)
{
items->Release();
return E_INVALIDARG;
}
hr = items->GetItemAt(0, &first_item);
if (hr != ERROR_SUCCESS)
{
items->Release();
return E_INVALIDARG;
}
return ERROR_SUCCESS;
}
HRESULT drop_handler::DragEnter(IDataObject* p_data_obj, DWORD gtf_key_state, POINTL pt, DWORD* pdw_effect)
{
IShellItemArray* items;
IShellItem* dragged_item;
HRESULT hr = GetFirstItem(p_data_obj, items, dragged_item);
if (hr != ERROR_SUCCESS)
{
return E_INVALIDARG;
}
//...use dragged_item

Your handling of IShellItemArray* and IShellItem* is wrong. GetFirstItem will free IShellItemArray* on failure but on success you will leak it and first_item will never be returned correctly. items and first_item in DragEnter will never be valid.
IShellItemArray* should probably be a local variable in GetFirstItem.
The IShellItem* first_item parameter needs to be IShellItem** first_item or IShellItem*& first_item so that the pointer value is returned correctly to the caller.
You never check the return value of GetCount.
Since you are having problems with pointers you might want to add some asserts to verify that your interface pointers are non-null before using them.

Related

C++ - Windows Shell API - Wrong path while iterating through a folder

Consider the following code:
bool ListFolderContent(const std::wstring& fileName)
{
PIDLIST_ABSOLUTE pidl = nullptr;
if (FAILED(::SHILCreateFromPath(fileName.c_str(), &pidl, nullptr)))
return false;
IShellFolder* pShellfolder = nullptr;
LPCITEMIDLIST pidlRelative = nullptr;
HRESULT hr = SHBindToParent(pidl, IID_IShellFolder, (void**)&pShellfolder, &pidlRelative);
if (FAILED(hr))
{
::CoTaskMemFree(pidl);
return false;
}
IEnumIDList* pEnumIDList = nullptr;
hr = pShellfolder->EnumObjects(nullptr, SHCONTF_NONFOLDERS, &pEnumIDList);
if (FAILED(hr))
{
pShellfolder->Release();
::CoTaskMemFree(pidl);
return false;
}
while (1)
{
LPITEMIDLIST pChild = nullptr;
hr = pEnumIDList->Next(1, &pChild, nullptr);
if (FAILED(hr))
{
pShellfolder->Release();
::CoTaskMemFree(pidl);
return false;
}
if (hr == S_FALSE)
break;
wchar_t buffer[MAX_PATH + 1];
if (::SHGetPathFromIDListW(pChild, buffer))
{
::OutputDebugString(buffer);
::OutputDebugString(L"\r\n");
}
}
pShellfolder->Release();
::CoTaskMemFree(pidl);
return true;
}
This code works well and logs the content of the folder owning the given file I pass through the fileName parameter.
However I have an issues with this code: Whatever I pass as file name, the logged path is always C:\Users\Admin\Desktop, and NOT the path to the parent folder I'm iterating, as expected. On the other hand the file names are correct.
Can someone explain me what I'm doing wrong?
You are passing just the last component ("filename") here: SHGetPathFromIDListW(pChild, buffer). Since the desktop is the root you are basically asking to get the filesystem path of [Desktop] [Filename] from the namespace.
There are two solutions:
pShellfolder->GetDisplayNameOf(pChild, SHGDN_FORPARSING, ...)+StrRetToBuf. This is fast since you already have an instance of the folder interface.
Call SHGetPathFromIDList with an absolute (full) pidl. On the pidl from SHILCreateFromPath, call ILCloneFull, ILRemoveLastID and ILCombine(clone, pChild).
HRESULT Example()
{
WCHAR buf[MAX_PATH];
GetWindowsDirectory(buf, MAX_PATH);
PathAppend(buf, L"Explorer.exe");
PIDLIST_ABSOLUTE pidl, pidlFullItem;
HRESULT hr = SHILCreateFromPath(buf, &pidl, nullptr); // %windir%\Explorer.exe
if (FAILED(hr)) return hr;
LPITEMIDLIST pLeaf;
IShellFolder*pShellfolder; // %windir%
hr = SHBindToParent(pidl, IID_IShellFolder, (void**)&pShellfolder, nullptr);
if (SUCCEEDED(hr))
{
IEnumIDList*pEnum;
// Method 1:
hr = pShellfolder->EnumObjects(nullptr, SHCONTF_NONFOLDERS, &pEnum);
if (SUCCEEDED(hr))
{
for (; S_OK == (hr = pEnum->Next(1, &pLeaf, nullptr));)
{
STRRET sr;
hr = pShellfolder->GetDisplayNameOf(pLeaf, SHGDN_FORPARSING, &sr);
if (SUCCEEDED(hr))
{
hr = StrRetToBuf(&sr, pLeaf, buf, MAX_PATH);
if (SUCCEEDED(hr)) wprintf(L"M1: Item: %s\n", buf);
}
}
pEnum->Release();
}
// Method 2:
ILRemoveLastID(pidl); // %windir%\Explorer.exe => %windir%
hr = pShellfolder->EnumObjects(nullptr, SHCONTF_NONFOLDERS, &pEnum);
if (SUCCEEDED(hr))
{
for (; S_OK == (hr = pEnum->Next(1, &pLeaf, nullptr));)
{
pidlFullItem = ILCombine(pidl, pLeaf); // %windir% + Filename
if (pidlFullItem)
{
hr = SHGetPathFromIDListW(pidlFullItem, buf);
if (SUCCEEDED(hr)) wprintf(L"M2: Item: %s\n", buf);
ILFree(pidlFullItem);
}
}
pEnum->Release();
}
pShellfolder->Release();
}
ILFree(pidl);
return hr;
}

Credential provider not displayed for all users (Other user included)

I am trying to show credential provider for all local and for other user(Domain users) in signing options but I am not able to. I developed this credential provider taking reference from here. I made following changes in _EnumerateCredentials and GetCredentialCount functions of CSampleprovider.cpp file.
GetCredentialCount()
HRESULT GetCredentialCount([out] DWORD* pdwCount,
[out] DWORD* pdwDefault,
[out] BOOL* pbAutoLogonWithDefault)
{
*pdwDefault = CREDENTIAL_PROVIDER_NO_DEFAULT;
*pbAutoLogonWithDefault = FALSE;
if (_fRecreateEnumeratedCredentials)
{
_fRecreateEnumeratedCredentials = false;
_ReleaseEnumeratedCredentials();
_CreateEnumeratedCredentials();
}
DWORD dwUserCount;
HRESULT hr;
if (_pCredProviderUserArray != nullptr) {
hr = _pCredProviderUserArray->GetCount(&dwUserCount);
}
if ((dwUserCount == 0) || (IsOS(OS_DOMAINMEMBER) == 1)) {
dwUserCount += 1;//display additional empty tile
}
*pdwCount = dwUserCount;
return S_OK;
}
_EnumerateCredentials()
HRESULT CSampleProvider::_EnumerateCredentials()
{
HRESULT hr = E_UNEXPECTED;
DWORD dwUserCount;
if (_pCredProviderUserArray != nullptr)
{
//DWORD dwUserCount = 0;
_pCredProviderUserArray->GetCount(&dwUserCount);
if (dwUserCount > 0)
{
//_pCredential = new CSampleCredential*[dwUserCount];
for (DWORD i = 0; i < dwUserCount; i++) {
ICredentialProviderUser* pCredUser;
hr = _pCredProviderUserArray->GetAt(i, &pCredUser);
if (SUCCEEDED(hr))
{
//_pCredential[i] = new(std::nothrow) CSampleCredential();
_pCredential.push_back(new(std::nothrow) CSampleCredential());
if (_pCredential[i] != nullptr)
{
//logfile << "new CSampleCredential()\n";
hr = _pCredential[i]->Initialize(_cpus, s_rgCredProvFieldDescriptors, s_rgFieldStatePairs, pCredUser);
if (FAILED(hr))
{
_pCredential[i]->Release();
_pCredential[i] = nullptr;
}
}
else
{
hr = E_OUTOFMEMORY;
}
pCredUser->Release();
}
}
}
//if you are in a domain or have no users on the list you have to show "Other user tile"
if (DEVELOPING) PrintLn(L"IsOS(OS_DOMAINMEMBER): %d", IsOS(OS_DOMAINMEMBER));
if ((dwUserCount == 0) || (IsOS(OS_DOMAINMEMBER) == 1)) {
if (DEVELOPING) PrintLn(L"Adding empty user tile");
_pCredential.push_back(new(std::nothrow) CSampleCredential());
if (_pCredential[_pCredential.size() - 1] != nullptr) {
hr = _pCredential[_pCredential.size() - 1]->Initialize(_cpus, s_rgCredProvFieldDescriptors, s_rgFieldStatePairs, nullptr);
}
else {
if (DEVELOPING) PrintLn(L"Error adding user: %d", _pCredential.size());
}
}
return hr;
}
}
And I have changed a private header of type CSampleCredential to
std::vector<CSampleCredential> _pCredentialVector;
// SampleV2CredentialCSampleProvider.h
in CSampleProvider.h file.
When I tested this Credential provider of mine it is working fine i.e it is displaying for all local users in sign in options when no domain is added (No other user) but when domain is added(other user enabled) then I am being stuck at the welcome wallpaper and screen keeps on flickering.
So, How do I display my Credential provider for all local and domain users (Other user) in sign in options and over come that flickering of screen. I am new to this VC++ please help me out.
While I was trying to enable the custom credential provider to all the tiles including the other user tile I made few changes in GetCredentialCount() method and _EnumerateCredentials() method in SampleProvider.cpp file in Credential provider Sample given by Microsoft. The changes I made are:
HRESULT CServiceProvider::GetCredentialCount(
_Out_ DWORD *pdwCount,
_Out_ DWORD *pdwDefault,
_Out_ BOOL *pbAutoLogonWithDefault){
*pdwDefault = CREDENTIAL_PROVIDER_NO_DEFAULT;
*pbAutoLogonWithDefault = FALSE;
if (_fRecreateEnumeratedCredentials)
{
_fRecreateEnumeratedCredentials = false;
_ReleaseEnumeratedCredentials();
_CreateEnumeratedCredentials();
}
DWORD dwUserCount;
HRESULT hr;
if (_pCredProviderUserArray != nullptr) {
hr = _pCredProviderUserArray->GetCount(&dwUserCount);
}
if ((dwUserCount == 0) || (IsOS(OS_DOMAINMEMBER) == 1)) {
dwUserCount += 1;//display additional empty tile
}
*pdwCount = dwUserCount;
return S_OK;}
HRESULT CServiceProvider::_EnumerateCredentials(){
HRESULT hr = E_UNEXPECTED;
DWORD dwUserCount;
if (_pCredProviderUserArray != nullptr)
{
_pCredProviderUserArray->GetCount(&dwUserCount);
if (dwUserCount > 0)
{
//You need to initialize all the fields in LogonUI for each and every user
for (DWORD i = 0; i < dwUserCount; i++) {
ICredentialProviderUser* pCredUser;
hr = _pCredProviderUserArray->GetAt(i, &pCredUser);
if (SUCCEEDED(hr))
{
_pCredential.push_back(new(std::nothrow) CUserCredential());
if (_pCredential[i] != nullptr)
{
hr = _pCredential[i]->Initialize(_cpus, s_rgCredProvFieldDescriptors, s_rgFieldStatePairs, pCredUser);
if (FAILED(hr))
{
_pCredential[i]->Release();
_pCredential[i] = nullptr;
}
}
else
{
hr = E_OUTOFMEMORY;
}
pCredUser->Release();
}
}
}
//if you are in a domain or have no users on the list you have to show "Other user tile"
if ((dwUserCount == 0) || (IsOS(OS_DOMAINMEMBER) == 1)) {
_pCredential.push_back(new(std::nothrow) CUserCredential());
if (_pCredential[_pCredential.size() - 1] != nullptr) {
hr = _pCredential[_pCredential.size() - 1]->Initialize(_cpus, s_rgCredProvFieldDescriptors, s_rgFieldStatePairs, nullptr);
}
}
return hr;
}
return hr;
}
Now as you see we are sending nullptr as one of the argument while calling Initialize() method after checking if system is connected to domain, we need to handle that nullptr in Initialize() method by checking with if condition in SampleCredential.cpp file.
HRESULT CUserCredential::Initialize(CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus,
_In_ CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR const* rgcpfd,
_In_ FIELD_STATE_PAIR const* rgfsp,
_In_ ICredentialProviderUser* pcpUser){
HRESULT hr = S_OK;
_cpus = cpus;
_nNextScreenID = e_ARSNone;
GUID guidProvider;
LPOLESTR clsid;
if (pcpUser != nullptr) {
pcpUser->GetProviderID(&guidProvider);
StringFromCLSID(guidProvider, &clsid);
CoTaskMemFree(clsid);
_fIsLocalUser = (guidProvider == Identity_LocalUserProvider);
}
else {
_fIsLocalUser = true;//CP V1 or Domain
}
// Copy the field descriptors for each field. This is useful if you want to vary the field
// descriptors based on what Usage scenario the credential was created for.
for (DWORD i = 0; SUCCEEDED(hr) && i < ARRAYSIZE(_rgCredProvFieldDescriptors); i++)
{
_rgFieldStatePairs[i] = rgfsp[i];
hr = FieldDescriptorCopy(rgcpfd[i], &_rgCredProvFieldDescriptors[i]);
}
// Initialize the String value of all the fields.
if (SUCCEEDED(hr))
{
hr = SHStrDupW(L"SomeLable1", &_rgFieldStrings[SFI_LABEL]);
}
if (SUCCEEDED(hr))
{
hr = SHStrDupW(L"SomeLable2", &_rgFieldStrings[SFI_LARGE_TEXT]);
}
if (SUCCEEDED(hr))
{
hr = SHStrDupW(L"", &_rgFieldStrings[SFI_PASSWORD]);
}
if (SUCCEEDED(hr))
{
hr = SHStrDupW(L"Somelabel4", &_rgFieldStrings[SFI_SUBMIT_BUTTON]);
}
hr = S_OK;
if (SUCCEEDED(hr))
{
if (pcpUser != nullptr) {
hr = pcpUser->GetStringValue(PKEY_Identity_QualifiedUserName, &_pszQualifiedUserName);//get username from the LogonUI user object
PWSTR pszUserName1;
pcpUser->GetStringValue(PKEY_Identity_UserName, &pszUserName1);
if (_fIsLocalUser) {
PWSTR pszUserName;
pcpUser->GetStringValue(PKEY_Identity_UserName, &pszUserName);
if (pszUserName != nullptr)
{
wchar_t szString[256];
StringCchPrintf(szString, ARRAYSIZE(szString), L"User Name: %s", pszUserName);
if (DEVELOPING) PrintLn(szString);
hr = SHStrDupW(pszUserName, &_rgFieldStrings[SFI_LARGE_TEXT]);
CoTaskMemFree(pszUserName);
}
else
{
hr = SHStrDupW(L"User Name is NULL", &_rgFieldStrings[SFI_LARGE_TEXT]);
}
}
else {
if (DEVELOPING) PrintLn(L"Domain user, skip SFI_LARGE_TEXT");
}
}
else {
PWSTR connectedDomainName = getNetworkName();
wchar_t szString[256];
StringCchPrintf(szString, ARRAYSIZE(szString), L"Sign in to: %s", connectedDomainName);
hr = SHStrDupW(szString, &_rgFieldStrings[SFI_DOMAIN_NAME_TEXT]);
if (DEVELOPING) PrintLn("Unknown user -> display LoginName");
hr = SHStrDupW(L"", &_pszQualifiedUserName);
_fUserNameVisible = true;
_rgFieldStatePairs[SFI_LOGIN_NAME].cpfs = CPFS_DISPLAY_IN_SELECTED_TILE;//unhide login name
//switch focus to login
_rgFieldStatePairs[SFI_LOGIN_NAME].cpfis = CPFIS_FOCUSED;
_rgFieldStatePairs[SFI_PASSWORD].cpfis = CPFIS_NONE;
//Don't panic!!!
}
}
if (pcpUser != nullptr)
{
hr = pcpUser->GetSid(&_pszUserSid);
}
return hr;}
Using above code you can solve flickering (which is crashing of CP) as well as enable Credential provider for all user tiles.

Getting GUID of group with IADs interface

I'm using the following C++ code to get all groups for a user:
(from https://msdn.microsoft.com/en-us/library/windows/desktop/aa746342(v=vs.85).aspx. I just added a few liens to get the group GUID as well)
HRESULT CheckUserGroups(IADsUser *pUser)
{
IADsMembers *pGroups;
HRESULT hr = S_OK;
hr = pUser->Groups(&pGroups);
pUser->Release();
if (FAILED(hr)) return hr;
IUnknown *pUnk;
hr = pGroups->get__NewEnum(&pUnk);
if (FAILED(hr)) return hr;
pGroups->Release();
IEnumVARIANT *pEnum;
hr = pUnk->QueryInterface(IID_IEnumVARIANT, (void**)&pEnum);
if (FAILED(hr)) return hr;
pUnk->Release();
// Enumerate.
BSTR bstr;
VARIANT var;
IADs *pADs;
ULONG lFetch;
IDispatch *pDisp;
VariantInit(&var);
hr = pEnum->Next(1, &var, &lFetch);
while (hr == S_OK)
{
if (lFetch == 1)
{
pDisp = V_DISPATCH(&var);
pDisp->QueryInterface(IID_IADs, (void**)&pADs);
pADs->get_Name(&bstr);
printf("Group belonged: %S\n", bstr);
SysFreeString(bstr);
pADs->get_GUID(&bstr);
printf("Group guid: %S\n", bstr);
SysFreeString(bstr);
pADs->Release();
}
VariantClear(&var);
pDisp = NULL;
hr = pEnum->Next(1, &var, &lFetch);
};
hr = pEnum->Release();
return S_OK;
}
int main()
{
CoInitialize(NULL);
CComPtr<IADsUser> pUser;
std::wstring ADpathName = std::wstring(L"WinNT://domain/user");
if( ADsGetObject(ADpathName.c_str(), IID_IADsUser, (void**)&pUser) == S_OK )
{
CheckUserGroups(pUser);
}
return 0;
}
However, the GUID for all groups is the same and doesn't reflect the real group GUID. why is that?

How to get the supported 802.11 operation modes for a WLAN adapter in user mode?

I'm working on a packet capture software on Windows which supports to capture raw 802.11 packets on monitor mode. One thing I need to do is to get the supported 802.11 operation modes for a WLAN adapter.
I know how to do this in a kernel mode: just query the OID OID_DOT11_OPERATION_MODE_CAPABILITY in a kernel driver.
However, I also want to know how to do this in user mode (a DLL). I already know that Microsoft has provided the Native Wifi API. I can use the functions like WlanQueryInterface, WlanSetInterface to get/set the current operation mode (the code below shows it). But it doesn't provide a function to get the operation modes supported by the adapter.
Is there any way to solve this without relying on the kernel code? Thanks!
DWORD SetInterface(WLAN_INTF_OPCODE opcode, PVOID pData, GUID* InterfaceGuid)
{
TRACE_ENTER();
DWORD dwResult = 0;
HANDLE hClient = NULL;
DWORD dwCurVersion = 0;
if (!initWlanFunctions())
{
TRACE_PRINT("SetInterface failed, initWlanFunctions error");
TRACE_EXIT();
return ERROR_INVALID_FUNCTION;
}
// Open Handle for the set operation
dwResult = My_WlanOpenHandle(WLAN_CLIENT_VERSION_VISTA, NULL, &dwCurVersion, &hClient);
if (dwResult != ERROR_SUCCESS)
{
TRACE_PRINT1("SetInterface failed, My_WlanOpenHandle error, errCode = %x", dwResult);
TRACE_EXIT();
return dwResult;
}
dwResult = My_WlanSetInterface(hClient, InterfaceGuid, opcode, sizeof(ULONG), pData, NULL);
if (dwResult != ERROR_SUCCESS)
{
TRACE_PRINT1("SetInterface failed, My_WlanSetInterface error, errCode = %x", dwResult);
}
My_WlanCloseHandle(hClient, NULL);
TRACE_EXIT();
return dwResult;
}
DWORD GetInterface(WLAN_INTF_OPCODE opcode, PVOID* ppData, GUID* InterfaceGuid)
{
TRACE_ENTER();
DWORD dwResult = 0;
HANDLE hClient = NULL;
DWORD dwCurVersion = 0;
DWORD outsize = 0;
WLAN_OPCODE_VALUE_TYPE opCode = wlan_opcode_value_type_invalid;
if (!initWlanFunctions())
{
TRACE_PRINT("SetInterface failed, initWlanFunctions error");
TRACE_EXIT();
return ERROR_INVALID_FUNCTION;
}
// Open Handle for the set operation
dwResult = My_WlanOpenHandle(WLAN_CLIENT_VERSION_VISTA, NULL, &dwCurVersion, &hClient);
if (dwResult != ERROR_SUCCESS)
{
TRACE_PRINT1("GetInterface failed, My_WlanOpenHandle error, errCode = %x", dwResult);
TRACE_EXIT();
return dwResult;
}
dwResult = My_WlanQueryInterface(hClient, InterfaceGuid, opcode, NULL, &outsize, ppData, &opCode);
if (dwResult != ERROR_SUCCESS)
{
TRACE_PRINT1("GetInterface failed, My_WlanQueryInterface error, errCode = %x", dwResult);
}
My_WlanCloseHandle(hClient, NULL);
TRACE_EXIT();
return dwResult;
}

c++ check installed programms

How do I list all programs installed on my computer? I've tried using the MsiEnumProducts and MsiGetProductInfo functions, but they do not return a full list of installed applications like I see in "Add/Remove Programs".
Enumerate the registry key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
bool EnumInstalledSoftware(void)
{
HKEY hUninstKey = NULL;
HKEY hAppKey = NULL;
WCHAR sAppKeyName[1024];
WCHAR sSubKey[1024];
WCHAR sDisplayName[1024];
WCHAR *sRoot = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
long lResult = ERROR_SUCCESS;
DWORD dwType = KEY_ALL_ACCESS;
DWORD dwBufferSize = 0;
//Open the "Uninstall" key.
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, sRoot, 0, KEY_READ, &hUninstKey) != ERROR_SUCCESS)
{
return false;
}
for(DWORD dwIndex = 0; lResult == ERROR_SUCCESS; dwIndex++)
{
//Enumerate all sub keys...
dwBufferSize = sizeof(sAppKeyName);
if((lResult = RegEnumKeyEx(hUninstKey, dwIndex, sAppKeyName,
&dwBufferSize, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS)
{
//Open the sub key.
wsprintf(sSubKey, L"%s\\%s", sRoot, sAppKeyName);
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, sSubKey, 0, KEY_READ, &hAppKey) != ERROR_SUCCESS)
{
RegCloseKey(hAppKey);
RegCloseKey(hUninstKey);
return false;
}
//Get the display name value from the application's sub key.
dwBufferSize = sizeof(sDisplayName);
if(RegQueryValueEx(hAppKey, L"DisplayName", NULL,
&dwType, (unsigned char*)sDisplayName, &dwBufferSize) == ERROR_SUCCESS)
{
wprintf(L"%s\n", sDisplayName);
}
else{
//Display name value doe not exist, this application was probably uninstalled.
}
RegCloseKey(hAppKey);
}
}
RegCloseKey(hUninstKey);
return true;
}

Resources