Windows application volume mixer - c++

I would like to list the applications displayed in the windows volume mixer.
In this example, "sons systeme", "Windows" and "spotify"
I write some code and I´m able to count and list those applications. The problem is I cant fetch their name nor their icon path
Here is the output :
Session Name:
Icon path Name:
Session Name:
Icon path Name:
Session Name:
Icon path Name:
Session Name: #%SystemRoot%\System32\AudioSrv.Dll,-202
Icon path Name: #%SystemRoot%\System32\AudioSrv.Dll,-203
I don´t understand why I can´t fetch this kind of data.
Here is my code :
IMMDevice* pDevice = NULL;
IMMDeviceEnumerator* pEnumerator = NULL;
IAudioSessionControl* pSessionControl = NULL;
IAudioSessionControl2* pSessionControl2 = NULL;
IAudioSessionManager2* pSessionManager = NULL;
hr = CoInitialize(NULL);
// Create the device enumerator.
hr = CoCreateInstance(
__uuidof(MMDeviceEnumerator),
NULL, CLSCTX_ALL,
__uuidof(IMMDeviceEnumerator),
(void**)&pEnumerator);
// Get the default audio device.
hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);
hr = pDevice->Activate(__uuidof(IAudioSessionManager2),
CLSCTX_ALL,
NULL, (void**)&pSessionManager);
hr = pSessionManager->GetAudioSessionControl(0, FALSE, &pSessionControl);
// Get the extended session control interface pointer.
hr = pSessionControl->QueryInterface(__uuidof(IAudioSessionControl2), (void**) &pSessionControl2);
// Check whether this is a system sound.
hr = pSessionControl2->IsSystemSoundsSession();
int cbSessionCount = 0;
LPWSTR pswSession = NULL;
IAudioSessionEnumerator* pSessionList = NULL;
hr = pSessionManager->GetSessionEnumerator(&pSessionList);
hr = pSessionList->GetCount(&cbSessionCount);
std::cout << cbSessionCount << std::endl;
for (int index = 0 ; index < cbSessionCount ; index++)
{
hr = pSessionList->GetSession(index, &pSessionControl);
hr = pSessionControl->GetDisplayName(&pswSession);
std::wcout << "Session Name: " << pswSession << std::endl;
hr = pSessionControl->GetIconPath(&pswSession);
std::wcout << "Icon path Name: " << pswSession << std::endl;
}

You can retrieve the name by using the ProcessID
DWORD procID;
pSessionControl2->GetProcessId(&procID);
And then with the ProcessID you can get a handle of the program and find the name and icon.

Related

(WMI) ExecMethod out parameter - ResultingSnapshot is NULL irrespective of the result of the call, Why?

I am using WMI to create an RCT Checkpoint. Below is the code snippet. The problem is when I call the method Create Snapshot using ExecMethodthe checkpoint gets created but the ResultingSnapshot to still points to NULL.
Since the call is asynchronous (as the return value from pOutParameters is 4096) I have also waited till the job gets completed in WaitForJobCompletion but pOutParameters is not updated and still, the ResultingSnapshot is NULL.
Basically, I need this ResultingSnapshot for creating a reference point. If there is any other way to do it, I can write it, need guidance though.
I am new to WMI, any help or lead is appreciated.
HRESULT hr;
CComPtr<IWbemClassObject> pInParams;
CComPtr<IWbemClassObject> pOutParameters;
IWbemCallResult *pResult = 0;
// Set Method Paramters
this->GetMethodParams(L"Msvm_VirtualSystemSnapshotService", L"CreateSnapshot", &pInParams);
IWbemClassObject * pVirtualSystemSnaphotSettingData = NULL;
hr = m_pWbemServices->GetObject(L"Msvm_VirtualSystemSnapshotSettingData", 0, NULL, &pVirtualSystemSnaphotSettingData, &pResult);
IWbemClassObject * pInpInstOfSnapshotSettingData = NULL;
hr = pVirtualSystemSnaphotSettingData->SpawnInstance(0, &pInpInstOfSnapshotSettingData);
VARIANT consistencyLevel;
VariantInit(&consistencyLevel);
V_VT(&consistencyLevel) = VT_BSTR;
V_BSTR(&consistencyLevel) = SysAllocString(L"1");
hr = pInpInstOfSnapshotSettingData->Put(L"ConsistencyLevel", 0, &consistencyLevel, 0);
VariantClear(&consistencyLevel);
VARIANT elementName;
VariantInit(&elementName);
V_VT(&elementName) = VT_BSTR;
V_BSTR(&elementName) = SysAllocString(L"rhel-1");
hr = pInpInstOfSnapshotSettingData->Put(L"ElementName", 0, &elementName, 0);
VariantClear(&elementName);
hr = m_pWbemServices->PutInstance(pInpInstOfSnapshotSettingData, 0, NULL, &pResult);
BSTR objString = NULL;
hr = pInpInstOfSnapshotSettingData->GetObjectText(0, &objString);
BSTR ArgNameTwo = SysAllocString(L"SnapshotSettings");
VARIANT v;
V_VT(&v) = VT_BSTR;
V_BSTR(&v) = objString;
hr = pInParams->Put(ArgNameTwo, 0, &v, 0);
VARIANT vtProp;
m_pVmWbemClassObject->Get(L"__Path", 0, &vtProp, 0, 0);
wprintf(L"Affected System : : %ls", (LPWSTR)vtProp.bstrVal);
HRESULT hres = pInParams->Put(L"AffectedSystem", 0 , &vtProp, NULL);
VARIANT var;
VariantInit(&var);
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(L"2");
CHK_HRES(pInParams->Put(L"SnapshotType", 0, &var, 0));
IEnumWbemClassObject* pEnumOb = NULL;
hr = m_pWbemServices->ExecQuery(
BSTR(L"WQL"),
BSTR(L"select * from Msvm_VirtualSystemSnapshotService"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumOb);
IWbemClassObject *pclsObj1 = NULL;
ULONG uReturn1 = 0;
while (1)
{
HRESULT hr = pEnumOb->Next(WBEM_INFINITE, 1, &pclsObj1, &uReturn1);
if (0 == uReturn1)
{
break;
}
IWbemCallResult *pCallResult = NULL;
IWbemClassObject *pResObj = NULL;
CComBSTR path(this->GetStrProperty(L"__PATH", pclsObj1));
hr = m_pWbemServices->ExecMethod(path, L"CreateSnapshot", 0, NULL, pInParams, &pOutParameters, &pCallResult);
/* cout << "check1 : " << hex << hr << endl;
hr = pCallResult->GetResultObject(0, &pResObj);
cout << "check2" << endl;*/
this->WaitForJobCompletion(pOutParameters);
}
cout << "\nSnpshot Complete" << endl;
}
EDIT
I found that the SnapshotType Parameter is not set correctly it should be 32768 and I have used the following way to convert uint16 to Variant but no Success and I get 0x80070057 Incorrect Parameter Error.
VARIANT var;
VariantInit(&var);
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(L"32768");
hr = pInParams->Put(L"SnapshotType", 0, &var, CIM_UINT16);
HRESULT GetRelated(PWSTR sAssociatePath, PWSTR sResultClass, IWbemClassObject** ppResultObject)
{
CStringW query;
query.Format(L"associators of {%s} where ResultClass = %s", sAssociatePath, sResultClass);
CComPtr<IEnumWbemClassObject> pEnumOb;
HRESULT hr = m_pWbemServices->ExecQuery(
BSTR(L"WQL"),
CComBSTR(query),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumOb));
ULONG uReturn = 0;
CComPtr<IWbemClassObject> pObject;
hr = pEnumOb->Next(WBEM_INFINITE, 1, &pObject, &uReturn);
return hr;
}
// Call the GetRelated function above with the __PATH parameter of JOB
CComPtr<IWbemClassObject> pOutParam = NULL;
CHK_HRES(this->ExecMethod(pHyperVObject, L"ConvertToReferencePoint", pInParams, &pOutParam, NULL));
CComVariant jobPath;
CHK_HRES(pOutParam->Get(L"Job", 0, &jobPath, NULL, NULL));
CComPtr<IWbemClassObject> pResult;
GetRelated(jobPath.bstrVal, L"Msvm_VirtualSystemReferencePoint", &pResult);
You provide a ppCallResult parameter. From the documentation:
ppCallResult [out] If NULL, this is not used. If ppCallResult is
specified, it must be set to point to NULL on entry. In this case, the
call returns immediately with WBEM_S_NO_ERROR. The ppCallResult
parameter receives a pointer to a new IWbemCallResult object, which
must be polled to obtain the result of the method execution using the
GetCallStatus method. The out parameters for the call are available by
calling IWbemCallResult::GetResultObject.
Therefore you need to use GetCallStatus on pCallResult until the method has finished and then GetResultObject to get the out parameters:
LONG status;
while ((hr = pCallResult->GetCallStatus(1000, &status)) == WBEM_S_TIMEDOUT);
/* check hr and status here */
hr = pCallResult->GetResultObject(0, &pResObj);
or use WBEM_INFINITE:
LONG status;
hr = pCallResult->GetCallStatus(WBEM_INFINITE, &status);
/* check hr and status here */
hr = pCallResult->GetResultObject(0, &pResObj);
Alternatively provide NULL instead of pCallResult and it will be a synchronous call where pOutParameters will be set:
hr = m_pWbemServices->ExecMethod(path, L"CreateSnapshot", 0, NULL, pInParams, &pOutParameters, NULL);
Was SnapshotType=32768 giving error to you?
Because snapshot is not created when I use this Snapshot Type.
The following log is getting created:
Checkpoint creation failed for 'Ubuntu1' because an invalid checkpoint type has been specified. (Virtual machine ID 5C773BB5-B630-48B4-AB9E-71C548F3FAE4)
Edit: I am not sure if it will help but this solved my problem:
https://learn.microsoft.com/en-us/answers/questions/160321/wmi-createsnapshot-not-working-with-snapshottype-3.html

cannot get the path for the virtual folder on windows 7 C++(shell namespace extension related)

By using Microsoft windows SDK 7.0, explorerDataProvider, I installed a virtual folder on windows 7.
When I open the file browse dialog from an application,
CFileDialog dlg(TRUE, NULL, 0, OFN_ENABLESIZING | OFN_ALLOWMULTISELECT, L"all(*.*)|*.*||", this);
INT_PTR result = dlg.DoModal();
if (result == IDOK)
{
.
.
.
//some actions
}
it can also display the virtual folder:
But when I select the file, like "Zero" can then clicks "Open",
I tried to add breakpoints to
INT_PTR result = dlg.DoModal();
But it seems that this error happens inside DoModal().
I doing some research and revise the code of virtual folder:
HRESULT CFolderViewImplFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, ULONG *rgfInOut)
{
// If SFGAO_FILESYSTEM is returned, GetDisplayNameOf(SHGDN_FORPARSING) on that item MUST
// return a filesystem path.
HRESULT hr = E_INVALIDARG;
DWORD dwAttribs = 0;
dwAttribs |= SFGAO_BROWSABLE;
if (1 == cidl)
{
int nLevel = 0;
hr = _GetLevel(apidl[0], &nLevel);
if (SUCCEEDED(hr))
{
BOOL fIsFolder = FALSE;
hr = _GetFolderness(apidl[0], &fIsFolder);
if (SUCCEEDED(hr))
{
if (fIsFolder)
{
dwAttribs |= SFGAO_FOLDER;
dwAttribs |= SFGAO_FILESYSANCESTOR;
}
else
{
dwAttribs |= SFGAO_SYSTEM;
dwAttribs |= SFGAO_FILESYSTEM;
}
if (nLevel < g_nMaxLevel)
{
dwAttribs |= SFGAO_HASSUBFOLDER;
}
}
}
}
*rgfInOut &= dwAttribs;
return hr;
}
And return the path inGetDisplayNameOf()
HRESULT CFolderViewImplFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, SHGDNF shgdnFlags, STRRET *pName)
{
HRESULT hr = S_OK;
if (shgdnFlags & SHGDN_FORPARSING)
{
WCHAR szDisplayName[MAX_PATH];
if (shgdnFlags & SHGDN_INFOLDER)
{
// This form of the display name needs to be handled by ParseDisplayName.
hr = _GetName(pidl, szDisplayName, ARRAYSIZE(szDisplayName));
}
else
{
PWSTR pszThisFolder = L"Computer\\Jerry";
StringCchCopy(szDisplayName, ARRAYSIZE(szDisplayName), pszThisFolder);
StringCchCat(szDisplayName, ARRAYSIZE(szDisplayName), L"\\");
WCHAR szName[MAX_PATH];
hr = _GetName(pidl, szName, ARRAYSIZE(szName));
if (SUCCEEDED(hr))
{
StringCchCat(szDisplayName, ARRAYSIZE(szDisplayName), szName);
}
}
if (SUCCEEDED(hr))
{
hr = StringToStrRet(szDisplayName, pName);
}
}
else
{
PWSTR pszName;
hr = _GetName(pidl, &pszName);
if (SUCCEEDED(hr))
{
hr = StringToStrRet(pszName, pName);
CoTaskMemFree(pszName);
}
}
return hr;
}
But it still stats error message of "Path does not exist" in the application.
I add breakpoints in GetDisplayNameOf, but it is never triggered when the application opens a file browse dialog. But if I open a regular folder just by double click "Computer", it will be triggered.
The error message of "Path does not exist" seems cannot be deprecated or covered. Any way that I can revise the virtual folder to return the correct path ?
Update: I tried IFileDialog, I copied the code from the MSDN sample, code, and add breakpoints to see what will happen. However,
// Show the dialog
hr = pfd->Show(NULL);//the breakpoint is added here
if (SUCCEEDED(hr))
{
// Obtain the result once the user clicks
// the 'Open' button.
// The result is an IShellItem object.
IShellItem *psiResult;
hr = pfd->GetResult(&psiResult);
if (SUCCEEDED(hr))
{
//do something
}
}
When I click "Open" button, the error message box of "Path does not exist, check the path and try again" still show up. And it never comes out of pfd->Show(NULL) after I click Open" button.
Based on the comments in the sample code, it should come out of hr = pfd->Show(NULL); and reach to the next line.but the error message happens inside the hr = pfd->Show(NULL);.
Update:
In the IFileDialog, I tried
hr = pfd->GetOptions(&dwFlags);
if (SUCCEEDED(hr))
{
hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS);
if (SUCCEEDED(hr))
{
// Show the dialog
hr = pfd->Show(NULL);
if (SUCCEEDED(hr))
{
// Obtain the result once the user clicks
// the 'Open' button.
// The result is an IShellItem object.
IShellItem *psiResult;
hr = pfd->GetResult(&psiResult);
if (SUCCEEDED(hr))
{
// We are just going to print out the
// name of the file for sample sake.
PWSTR pszFilePath = NULL;
hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH,
&pszFilePath);
if (SUCCEEDED(hr))
{
TaskDialog(NULL,
NULL,
L"CommonFileDialogApp",
pszFilePath,
NULL,
TDCBF_OK_BUTTON,
TD_INFORMATION_ICON,
NULL);
CoTaskMemFree(pszFilePath);
}
psiResult->Release();
}
}
}
I also tried
hr = pfd->SetOptions(dwFlags);//delete FOS_FORCEFILESYSTEM
And tried
DWORD dwFlags = 0;
if (SUCCEEDED(hr))
{
// overwrite options completely
hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS);
I also tried to return the whole name in namespace extension code:
WCHAR szDisplayName[MAX_PATH];
if (shgdnFlags & SHGDN_INFOLDER)
{
// This form of the display name needs to be handled by ParseDisplayName.
hr = _GetName(pidl, szDisplayName, ARRAYSIZE(szDisplayName));
}
else
{
PWSTR pszThisFolder;// = L"Computer\\Jerry";
hr = SHGetNameFromIDList(m_pidl, (shgdnFlags & SHGDN_FORADDRESSBAR) ? SIGDN_DESKTOPABSOLUTEEDITING : SIGDN_DESKTOPABSOLUTEPARSING, &pszThisFolder);
if (SUCCEEDED(hr))
{
StringCchCopy(szDisplayName, ARRAYSIZE(szDisplayName), pszThisFolder);
StringCchCat(szDisplayName, ARRAYSIZE(szDisplayName), L"\\");
WCHAR szName[MAX_PATH];
hr = _GetName(pidl, szName, ARRAYSIZE(szName));
if (SUCCEEDED(hr))
{
StringCchCat(szDisplayName, ARRAYSIZE(szDisplayName), szName);
}
CoTaskMemFree(pszThisFolder);
}
}
if (SUCCEEDED(hr))
{
hr = StringToStrRet(szDisplayName, pName);
}
But the result is:
Update:
hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE);
This works for me!!
With the help of #RemyLebeau, I did some tests in my code. Finally, I found the working solution for me:
I copied the code from MSDN for IFileDialog: https://msdn.microsoft.com/en-us/library/windows/desktop/bb776913.aspx#file_types
and then revise it a little bit:
HRESULT BasicFileOpen()
{
// CoCreate the File Open Dialog object.
IFileDialog *pfd = NULL;
HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&pfd));
if (SUCCEEDED(hr))
{
// Create an event handling object, and hook it up to the dialog.
IFileDialogEvents *pfde = NULL;
hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
if (SUCCEEDED(hr))
{
// Hook up the event handler.
DWORD dwCookie;
hr = pfd->Advise(pfde, &dwCookie);
if (SUCCEEDED(hr))
{
// Set the options on the dialog.
DWORD dwFlags = 0;
if (SUCCEEDED(hr))
{
// the default flag is FOS_PATHMUSTEXIST and FOS_FILEMUSTEXIST, so I set overwrite it with these two flags.
hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE);
if (SUCCEEDED(hr))
{
// Show the dialog
hr = pfd->Show(NULL);
if (SUCCEEDED(hr))
{
// Obtain the result once the user clicks
// the 'Open' button.
// The result is an IShellItem object.
IShellItem *psiResult;
hr = pfd->GetResult(&psiResult);
if (SUCCEEDED(hr))
{
// We are just going to print out the
// name of the file for sample sake.
PWSTR pszFilePath = NULL;
hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH,
&pszFilePath);
if (SUCCEEDED(hr))
{
TaskDialog(NULL,
NULL,
L"CommonFileDialogApp",
pszFilePath,
NULL,
TDCBF_OK_BUTTON,
TD_INFORMATION_ICON,
NULL);
CoTaskMemFree(pszFilePath);
}
psiResult->Release();
}
}
}
}
// Unhook the event handler.
pfd->Unadvise(dwCookie);
}
pfde->Release();
}
pfd->Release();
}
return hr;
}
The key point is to overwrite the options by SetOptions. Based on the MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/dn457282(v=vs.85).aspx ,
FOS_PATHMUSTEXIST
The item returned must be in an existing folder. This is a default value.
FOS_FILEMUSTEXIST
The item returned must exist. This is a default value for the Open dialog.
These flags are default values which prevent it returns.
So I set it to :
hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE);
These flags mean:
FOS_NOVALIDATE
Do not check for situations that would prevent an application from opening the selected file, such as sharing violations or access denied errors.
and
FOS_ALLNONSTORAGEITEMS
Enables the user to choose any item in the Shell namespace, not just those with SFGAO_STREAM or SFAGO_FILESYSTEM attributes. This flag cannot be combined with FOS_FORCEFILESYSTEM.
Then it finally works!

Set WMP volume level

What i want to do is set the Windows Media Player's volume level. By default the volume is in-/decreased by 10% when e.g. clicking the down or up menu item (Play -> Volume -> Up), but this is, in my opinion, not fine enough (especially when e.g. skypeing with someone while listening to music).
The media player should stay an independent application.
Currently i'm using a little tool that sends app commands via SendMessage to the player with parameters as seen in spy++.
I thought of three ways to achieve my goal:
using WASAPI to get the media player's audio session and dynamically set the volume level
sending mouse down/up events to the volume slider of the media player host control by point
getting an instance of the media player control via IWMPPlayer4
including a media player control in my WPF application within a windows forms host (not preferred due to loss of independence)
Point 2 seems rather ugly due to the fact that the media player control is a COM element and has as far spy++ displays only one handle, meaning i would have to determine the exact position of the volume slider and send very precise mouse events. Additional i don't know whether this would work at all.
Point 3 has the presupposition that one can get an instance of a COM element by a handle. Since i have yet not worked with COM elements i don't know if this is possible.
Update: One can get an instance of a remote mediay player using the IWMPPlayer4 interface. Though i have to see whether one can change settings.
Point 1 has the impression on me that it would be possible without much effort.
Though i'd be facing the next problem: identifying the media players audio session. Enumerating them using IAudioSessionManager2 and displaying the name using
IAudioSessionControl2 ctrl2 = NULL;
// ...
hr = ctrl2->GetDisplayName(&name);
if (FAILED(hr))
{
SafeRelease(ctrl);
SafeRelease(ctrl2);
continue;
}
String ^sessionName = gcnew String(name);
Console::WriteLine("Session name: '" + sessionName + "'");
prints most the times an emtpy string except for Mozilla Firefox and System Sounds (the other processes might not have set a session name themselfes => a default name is chosen and GetDisplayName returns an empty string).
Update 2:
As Simon Mourier pointed out one can compare the process ids to get the right ISimpleAudioVolume instance and it works as far as it comes to WMP to adopt the changes. The said instance is aquired the following way:
IMMDeviceEnumerator *pEnumerator = NULL;
ISimpleAudioVolume *pVolume = NULL;
IMMDevice *pDevice = NULL;
IAudioSessionManager2 *pManager = NULL;
IAudioSessionEnumerator *pSessionEnumerator = NULL;
int sessionCount = 0;
CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL,
CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);
pEnumerator->GetDefaultAudioEndpoint(EDataFlow::eRender, ERole::eMultimedia, &pDevice);
pDevice->GetState(&deviceState);
pDevice->Activate(__uuidof(IAudioSessionManager2), CLSCTX_ALL, NULL, (void**)&pManager);
pManager->GetSessionEnumerator(&pSessionEnumerator);
pSessionEnumerator->GetCount(&sessionCount);
for (int i = 0; i < sessionCount; i++)
{
IAudioSessionControl *ctrl = NULL;
IAudioSessionControl2 *ctrl2 = NULL;
DWORD processId = 0;
hr = pSessionEnumerator->GetSession(i, &ctrl);
if (FAILED(hr))
{
continue;
}
hr = ctrl->QueryInterface(__uuidof(IAudioSessionControl2), (void**)&ctrl2);
if (FAILED(hr))
{
SafeRelease(ctrl);
continue;
}
hr = ctrl2->GetProcessId(&processId);
if (FAILED(hr))
{
SafeRelease(ctrl);
SafeRelease(ctrl2);
continue;
}
if (processId == wmpProcessId)
{
hr = ctrl2->QueryInterface(__uuidof(ISimpleAudioVolume), (void**)&pVolume);
SafeRelease(ctrl);
SafeRelease(ctrl2);
break;
}
SafeRelease(ctrl);
SafeRelease(ctrl2);
}
When aquiering an ISimpleAudioVolume instance via a IAudioClient one has to provide a session id to have volume changes reported to event subscribers. Is this possible using this approach?
Though i know that adding a media player control to my application would be the easiest way, i'd like to not use this option if possible.
I don't know what may happened during my initial try to set the media player's volume level, but the following code works (most exception handling excluded):
HRESULT hr;
IMMDeviceEnumerator *pEnumerator = NULL;
ISimpleAudioVolume *pVolume = NULL;
IMMDevice *pDevice = NULL;
IAudioSessionManager2 *pManager = NULL;
IAudioSessionEnumerator *pSessionEnumerator = NULL;
int sessionCount = 0;
int wmpProcess = GetWmpProcessId(); // Aquire WMPs process id
// Get the device enumerator and initialize the application for COM
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL,
__uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);
// Get the default device
hr = pEnumerator->GetDefaultAudioEndpoint(EDataFlow::eRender,
ERole::eMultimedia, &pDevice);
// Get the session 2 manager
hr = pDevice->Activate(__uuidof(IAudioSessionManager2), CLSCTX_ALL,
NULL, (void**)&pManager);
// Get the session enumerator
hr = pManager->GetSessionEnumerator(&pSessionEnumerator);
// Get the session count
hr = pSessionEnumerator->GetCount(&sessionCount);
// Loop through all sessions
for (int i = 0; i < sessionCount; i++)
{
IAudioSessionControl *ctrl = NULL;
IAudioSessionControl2 *ctrl2 = NULL;
DWORD processId = 0;
hr = pSessionEnumerator->GetSession(i, &ctrl);
if (FAILED(hr))
{
continue;
}
hr = ctrl->QueryInterface(__uuidof(IAudioSessionControl2), (void**)&ctrl2);
if (FAILED(hr))
{
SafeRelease(ctrl);
continue;
}
//Identify WMP process
hr = ctrl2->GetProcessId(&processId);
if (FAILED(hr))
{
SafeRelease(ctrl);
SafeRelease(ctrl2);
continue;
}
if (processId != wmpProcess)
{
SafeRelease(ctrl);
SafeRelease(ctrl2);
continue;
}
hr = ctrl2->QueryInterface(__uuidof(ISimpleAudioVolume), (void**)&pVolume);
if (FAILED(hr))
{
Error(hr, "Failed to get ISimpleAudioVolume.");
SafeRelease(ctrl);
SafeRelease(ctrl2);
continue;
}
// Set the master volume
hr = pVolume->SetMasterVolume(1.0, NULL);
if (FAILED(hr))
{
Error(hr, "Failed to set the master volume.");
SafeRelease(ctrl);
SafeRelease(ctrl2);
SafeRelease(pVolume);
continue;
}
SafeRelease(ctrl);
SafeRelease(ctrl2);
SafeRelease(pVolume);
}

2nd parameter "Arguments" of IApplicationActivationManager::ActivateApplication() syntax

I'm using IApplicationActivationManager::ActivateApplication() from MSDN ActivateApplication API
to write a console app EXE (VC++) which launches a "Photos metro app & displays a PNG image". Here is teh code snippet. It's activating the "Photos metro application" but not able to display the image using the "Photos app".
CoInitializeEx(NULL, COINIT_MULTITHREADED);
LPCWSTR appId = L"Microsoft.Windows.Photos_8wekyb3d8bbwe!App";
LPCWSTR imageArg = L" C:\\data\\Users\\Public\\Pictures\\image123.png";
IApplicationActivationManager* paam = NULL;
HRESULT hr = E_FAIL;
__try
{
hr = CoCreateInstance(CLSID_ApplicationActivationManager, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&paam));
if (FAILED(hr))
{
cout << "Error creating CoCreateINstance & HR is" <<hr<< endl;
return 0;
}
DWORD pid = 0;
hr = paam->ActivateApplication(appId, imageArg, AO_NONE, &pid);
if (FAILED(hr))
{
cout << "Error in ActivateApplication call & HR is " <<hr<< endl;
return 0;
}
cout << hex << hr;
if (hr == 0)
wprintf(L"Activated %s with pid %d\r\n", appId, pid);
}
__finally
{
if (paam) paam->Release();
}
CoUninitialize();
I'm sure the error is in the 2nd argument of the "ActivateApplication()" function, where I'm giving the argument. I tried different ways of giving arguments like :
LPCWSTR imageArg = L"
C:\data\Users\Public\Pictures\image123.png"; OR
LPCWSTR imageArg = L"-
C:\data\Users\Public\Pictures\image123.png";
LPCWSTR
imageArg = L"C:\data\Users\Public\Pictures\image123.png";
To perform a file activation use the IApplicationActivationManager::ActivateForFile method.
You can create a ShellItem from a file path with SHCreateItemFromParsingName (the path is a parsing name) and can create a ShellItemArray from that with
SHCreateShellItemArrayFromShellItem
The Photos app won't listen for a file name on ActivateApplication's activation argument, and it wouldn't have access to the file by path if it did. The ActivateForFile method will convert the passed in ShellItems to StorageFiles which carry permissions to allow the app to open them.

Get email addresses of outlook profile, MAPI

How does one get the email addresses from an outlook profile, using MAPI, in C++ ?
The code for start(works ok):
HRESULT hRes = S_OK;
LPMAPISESSION lpSession = NULL;
LPMDB lpMDB = NULL;
LPMAPITABLE lptMsgStores = NULL;
LPMAPITABLE spTable = NULL;
std::wstring wProfileName;
std::wstring wUsername;
wUsername = L"user1#mymail.com";
wProfileName = L"TestProfile";
// Initiate MAPI.
hRes = MAPIInitialize(0);
// Logon to Extended MAPI session.
hRes = MAPILogonEx(NULL,
(LPTSTR)wProfileName.c_str(),
NULL,
MAPI_EXTENDED | MAPI_EXPLICIT_PROFILE | MAPI_NEW_SESSION | MAPI_UNICODE | MAPI_LOGON_UI, &lpSession);
if(FAILED(hRes))
{
MessageBox(NULL,L"logon error", L"",MB_OK);
}
LPOLKACCOUNTMANAGER lpAcctMgr = NULL;
hRes = CoCreateInstance(CLSID_OlkAccountManager,
NULL,
CLSCTX_INPROC_SERVER,
IID_IOlkAccountManager,
(LPVOID*)&lpAcctMgr);
if(SUCCEEDED(hRes) && lpAcctMgr)
{
CAccountHelper *pMyAcctHelper = new CAccountHelper((LPWSTR)wProfileName.c_str(), lpSession);
if(pMyAcctHelper)
{
LPOLKACCOUNTHELPER lpAcctHelper = NULL;
hRes = pMyAcctHelper->QueryInterface(IID_IOlkAccountHelper, (LPVOID*)&lpAcctHelper);
if(SUCCEEDED(hRes) && lpAcctHelper)
{
LPOLKENUM lpAcctEnum = NULL;
hRes = lpAcctMgr->EnumerateAccounts(&CLSID_OlkMail,
NULL,
OLK_ACCOUNT_NO_FLAGS,
&lpAcctEnum); //THIS FAILS HERE, hRes != S_OK!
_com_error err(hRes);
LPCTSTR errMsg = err.ErrorMessage();
wprintf(L"%s\n", errMsg);
if(SUCCEEDED(hRes) && lpAcctEnum)
{
DWORD cAccounts = 0 ;
hRes = lpAcctEnum->GetCount(&cAccounts);
if(SUCCEEDED(hRes))
{
hRes = lpAcctEnum->Reset();
if(SUCCEEDED(hRes))
{
DWORD i = 0;
for(i = 0 ; i< cAccounts; i++)
{
LPUNKNOWN lpUnk = NULL;
hRes = lpAcctEnum->GetNext(&lpUnk);
if(SUCCEEDED(hRes) &&lpUnk)
{
LPOLKACCOUNT lpAccount = NULL;
hRes = lpUnk->QueryInterface(IID_IOlkAccount, (LPVOID*)&lpAccount);
if(SUCCEEDED(hRes) && lpAccount)
{
ACCT_VARIANT pProp = {0};
HRESULT hRes = S_OK;
hRes = lpAccount->GetProp(PROP_ACCT_NAME, &pProp);
if(SUCCEEDED(hRes) && pProp.Val.pwsz)
{
wprintf(L"Found email:%s\n", pProp.Val.pwsz);
lpAccount->FreeMemory((LPBYTE)pProp.Val.pwsz);
}
}
if(lpAccount)
lpAccount->Release();
lpAccount = NULL;
}
if(lpUnk)
lpUnk->Release();
lpUnk = NULL;
}
///////////
}
}
}
if(lpAcctEnum)
lpAcctEnum->Release();
}
}
if(pMyAcctHelper)
pMyAcctHelper->Release();
}
if(lpAcctMgr)
lpAcctMgr->Release();
// Release the session.
lpSession->Logoff(0,MAPI_LOGOFF_UI,0);
lpSession->Release();
MAPIUninitialize();
_getch();
You don't add an email address to a profile, you add a service that may (POP3/IMAP4/SMTP) or may not (PST) expose or need an SMTP address. For POP3/IMAP4/SMTP addresses, use IOlkAccountManager API. You can play with it in OutlookSpy (I am its author - click IOlkAccountManager button).
Outlook Object Model exposes mail accounts (only mail, not store or address book) through the Namespace.Accounts collection.