get application name from IAudioSessionControl2 - c++

How can I get the simple application name from following code of IAudioSessionControl2 ? Should I substring or use other method such as using GUID, although I dont know how to get app name from GUID. My target is to know the app name that is using a audio session.
Code:
LPWSTR instId = NULL;
hr = pSessionControl2->GetSessionInstanceIdentifier(&instId);
if (S_OK == hr)
{
wprintf_s(L"SessionInstanceIdentifier: %s\n", instId);
}
GUID guid;
HRESULT hr1 = CLSIDFromString(instId, (LPCLSID)&guid);
if (hr1 != S_OK) {
// bad GUID string...
//std::cout << "\nHi___\n" << guid.Data1 << "\n";
}
// out:
// SessionInstanceIdentifier: {0.0.0.00000000}.{db6e6565-391a-45a1-970d-41d8389b71ae}|\Device\HarddiskVolume4\Program Files\WindowsApps\App_15.83.3408.0_x86__kzf8qxf38zg5a\App\App.exe%b{00000000-...}|1%b9532

Related

How to get audio session GUID with Windows API

I'm trying to make a simple mixer app using Windows audio API. I've already figured out how to get IAudioSessionEnumerator and IAudioSessionControl which allows me to retrieve the DisplayName of each session. And now I want to get/set volumes of these sessions. From winApi docs I think I first need to use GetSimpleAudioVolume method but it requires session GUID as a parameter. So how do I get a GUID of an existing session? I couldn't find any answers for that in docs or google. Or maybe I missunderstood something?
//code prints DisplayNames of all sessions
void getSessions() {
CoInitialize(NULL);
IMMDeviceEnumerator *pDEnumerator = NULL;
CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pDEnumerator);
IMMDevice *pDevice = NULL;
pDEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &pDevice);
IAudioSessionManager2 *pSManager2 = NULL;
pDevice->Activate(IID_IAudioSessionManager2, CLSCTX_ALL, NULL, (void**)&pSManager2);
IAudioSessionEnumerator *pSEnumerator = NULL;
pSManager2->GetSessionEnumerator(&pSEnumerator);
int audioSessionCount;
pSEnumerator->GetCount(&audioSessionCount);
std::cout << audioSessionCount << '\n';
for (int i = 0; i < audioSessionCount; ++i) {
IAudioSessionControl *controls;
pSEnumerator->GetSession(i, &controls);
LPWSTR name;
controls->GetDisplayName(&name);
while (*name != 0) {
std::wcout << *name;
++name;
}
std::cout << '\n';
}
}
Each audio session is uniquely identified with a GUID—session instance
identifier.
You can IAudioSessionControl2::GetSessionInstanceIdentifier and retrieve a string that contains the session identifier.
Or you can query ISimpleAudioVolume interface on IAudioSessionControl interface like this:
ISimpleAudioVolume *simpleAudioVol = NULL;
controls->QueryInterface(IID_PPV_ARGS(&simpleAudioVol));

Windows application volume mixer

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.

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.

Problems accessing a COM interface in C++

What I want to do is access a COM interface and then call the "Open" method of that interface.
I have a sample code in Visual Basic which works fine, but I need to write it in C++ and I can't seem to get it to work.
First of all, this is the working VB code:
Dim CANapeApplication As CANAPELib.Application
CANapeApplication = CreateObject("CANape.Application")
Call CANapeApplication.Open("C:\Users\Public\Documents\Vector\CANape\12\Project", 0)
CANape.Application is the ProgID which selects the interface I need.
After reading some docs at msdn.microsoft.com and this question, I wrote this code:
void ErrorDescription(HRESULT hr); //Function to output a readable hr error
int InitCOM();
int OpenCANape();
// Declarations of variables used.
HRESULT hresult;
void **canApeAppPtr;
IDispatch *pdisp;
CLSID ClassID;
DISPID FAR dispid;
UINT nArgErr;
OLECHAR FAR* canApeWorkingDirectory = L"C:\\Users\\Public\\Documents\\Vector\\CANape\\12\\Project";
int main(){
// Instantiate CANape COM interface
if (InitCOM() != 0) {
std::cout << "init error";
return 1;
}
// Open CANape
if (OpenCANape() != 0) {
std::cout << "Failed to open CANape Project" << std::endl;
return 1;
}
CoUninitialize();
return 0;
}
void ErrorDescription(HRESULT hr) {
if(FACILITY_WINDOWS == HRESULT_FACILITY(hr))
hr = HRESULT_CODE(hr);
TCHAR* szErrMsg;
if(FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&szErrMsg, 0, NULL) != 0)
{
_tprintf(TEXT("%s"), szErrMsg);
LocalFree(szErrMsg);
} else
_tprintf( TEXT("[Could not find a description for error # %#x.]\n"), hr);
}
int InitCOM() {
// Initialize OLE DLLs.
hresult = OleInitialize(NULL);
if (!SUCCEEDED(hresult)) {
ErrorDescription(hresult);
return 1;
}
// Get CLSID from ProgID
//hresult = CLSIDFromProgID(OLESTR("CANape.Application"), &ClassID);
hresult = CLSIDFromProgID(OLESTR("CanapeCom.CanapeCom"), &ClassID);
if (!SUCCEEDED(hresult)) {
ErrorDescription(hresult);
return 1;
}
// OLE function CoCreateInstance starts application using GUID/CLSID
hresult = CoCreateInstance(ClassID, NULL, CLSCTX_LOCAL_SERVER,
IID_IDispatch, (void **)&pdisp);
if (!SUCCEEDED(hresult)) {
ErrorDescription(hresult);
return 1;
}
// Call QueryInterface to see if object supports IDispatch
hresult = pdisp->QueryInterface(IID_IDispatch, (void **)&pdisp);
if (!SUCCEEDED(hresult)) {
ErrorDescription(hresult);
return 1;
}
std::cout << "success" << std::endl;
return 0;
}
int OpenCANape() {
//Method name
OLECHAR *szMember = L"Open";
// Retrieve the dispatch identifier for the Open method
// Use defaults where possible
DISPID idFileExists;
hresult = pdisp->GetIDsOfNames(
IID_NULL,
&szMember,
1,
LOCALE_SYSTEM_DEFAULT,
&idFileExists);
if (!SUCCEEDED(hresult)) {
std::cout << "GetIDsOfNames: ";
ErrorDescription(hresult);
return 1;
}
unsigned int puArgErr = 0;
VARIANT VarResult;
VariantInit(&VarResult);
DISPPARAMS pParams;
memset(&pParams, 0, sizeof(DISPPARAMS));
pParams.cArgs = 2;
VARIANT Arguments[2];
VariantInit(&Arguments[0]);
pParams.rgvarg = Arguments;
pParams.cNamedArgs = 0;
pParams.rgvarg[0].vt = VT_BSTR;
pParams.rgvarg[0].bstrVal = SysAllocString(canApeWorkingDirectory);
pParams.rgvarg[1].vt = VT_INT;
pParams.rgvarg[1].intVal = 0; // debug mode
// Invoke the method. Use defaults where possible.
hresult = pdisp->Invoke(
dispid,
IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD,
&pParams,
&VarResult,
NULL,
&puArgErr
);
SysFreeString(pParams.rgvarg[0].bstrVal);
if (!SUCCEEDED(hresult)) {
ErrorDescription(hresult);
return 1;
}
return 0;
}
There are several problems with this.
Using the ClassID received from CLSIDFromProgID as the first parameter of CoCreateInstance does not work, it returns the error: class not registered
If i use the ProgID CanapeCom.CanapeCom (I found it by looking in the Registry), CoCreateInstance works. However, when I use pdisp->GetIDsOfNames I get the error message: Unkown name. Which I think means that the method was not found. That seems logical because I've used a different ProgID, but I just can't figure out how to get to the interface I'm looking for.
I have also tried to use the resulting CLSID from CLSIDFromProgID(OLESTR("CANape.Application"), &ClassID); as the 4th argument of CoCreateInstance but that resulted in a "No such interface supported" error.
Do I need the dll file of the software? In the VB example the dll file is used to get the interface and then create a new object using the ProgID. I'm not sure if I need to do the same in C++ or how this should work.
I'm really stuck here and hope that someone can help me.
Thanks for your comments.
I've fixed the problem, although the solution is kind of embarrassing...
In my defense, I'm still a student and new to this kind of stuff.
I've used the Process Monitor to check what happens when I execute the VB script.
I saw that the CLSID used there is the ID returned by CLSIDFromProgID(OLESTR("CANape.Application"), &ClassID);, which meant that this had to be the right one and the problem had to be somewhere else. I've looked again at the CoCreateInstance and then took a look at the other parameters. Turns out that the context CLSCTX_LOCAL_SERVER was wrong, it has to be CLSCTX_INPROC_SERVER. I don't know why I've set it to local_server in the first place or why I've never questioned it. I wrote that part of the code a few days ago and then focused too much on the CLSID and IID rather than on the other parameters.
I've also taken the first comment from Alex into account and created a tlb file.
This is a simplified version of the code that works:
#import "CANape.tlb"
int _tmain(int argc, _TCHAR* argv[])
{
_bstr_t path = "C:\\Users\\Public\\Documents\\Vector\\CANape\\12\\Project";
CLSID idbpnt;
CoInitialize(NULL);
HRESULT hr = CLSIDFromProgID (L"CANape.Application", &idbpnt);
CANAPELib::IApplication *app;
hr = CoCreateInstance(idbpnt,NULL,CLSCTX_INPROC_SERVER,__uuidof(CANAPELib::IApplication),(LPVOID*)&app );
app->Open(path,0);
CoUninitialize();
return 0;
}

Retrieve HTML source from CHtmlView (visual studio 6)

Im working on an application that uses a CHtmlView. New requirements mean I would like to be able to get the HTML source from the class to parse for a specific tag (or if possible just get the information in the tag). This would be fine if we were using a newer system and I could use CHtmlView::GetSource but it doesn't exist.
I've had a pretty extensive search online but am pretty new to most of Windows programming and haven't been able to achieve anything useful yet.
So if anyone has an example of how to extract the HTML from a CHtmlView without using GetSource I would appreciate seeing it. I've tried
BSTR bstr;
_bstr_t * bstrContainer;
HRESULT hr;
IHTMLDocument2 * pDoc;
IDispatch * pDocDisp = NULL;
pDocDisp = this->GetHtmlDocument();
if (pDocDisp != NULL) {
hr = pDocDisp->QueryInterface (IID_IHTMLDocument2, (void**)&pDoc);
if (SUCCEEDED(hr)) {
if (pDoc->toString(&bstr) != S_OK) {
//error...
} else {
bstrContainer = new _bstr_t(bstr);
size = (bstrContainer->length()+1)*2;
realString = new char[size];
strncpy(realString, (char*)(*bstrContainer), size);
}
} else {
//error
}
pDocDisp->Release();
}
but it mostly just gives me "[object]" in realString. Like I said, new to Windows.
Any help appreciated.
Add this helper function into your CHtmlView-derived class to retrieve the html source. Remember to check the returned boolean state from this function as com-interface can be quite unreliable when system resources are low.
/* ============================================== */
BOOL CTest1View::GetHtmlText(CString &strHtmlText)
{
BOOL bState = FALSE;
// get IDispatch interface of the active document object
IDispatch *pDisp = this->GetHtmlDocument();
if (pDisp != NULL)
{ // get the IHTMLDocument3 interface
IHTMLDocument3 *pDoc = NULL;
HRESULT hr = pDisp->QueryInterface(IID_IHTMLDocument3, (void**) &pDoc);
if (SUCCEEDED(hr))
{ // get root element
IHTMLElement *pRootElement = NULL;
hr = pDoc->get_documentElement(&pRootElement);
if (SUCCEEDED(hr))
{ // get html text into bstr
BSTR bstrHtmlText;
hr = pRootElement->get_outerHTML(&bstrHtmlText);
if (SUCCEEDED(hr))
{ // convert bstr to CString
strHtmlText = bstrHtmlText;
bState = TRUE;
SysFreeString(bstrHtmlText);
}
pRootElement->Release();
}
pDoc->Release();
}
pDisp->Release();
}
return bState;
}