Calling GetDisplayName returns same result as GetIconPath - c++

I currently have this code, iterating over the audio session controls of the default device (not shown):
int sessionCount;
hr = audioSessionEnumerator->GetCount(&sessionCount);
if (FAILED(hr)) {
throw HRESULTException("audioSessionEnumerator->GetCount", hr);
}
IAudioSessionControl *audioSessionControl;
for (int i = 0; i < sessionCount; ++i) {
hr = audioSessionEnumerator->GetSession(i, &audioSessionControl);
if (FAILED(hr)) {
throw HRESULTException("audioSessionEnumerator->GetSession", hr);
}
LPWSTR displayName;
hr = audioSessionControl->GetDisplayName(&displayName);
if (FAILED(hr)) {
throw HRESULTException("audioSessionControl->GetDisplayName", hr);
}
std::wcout << displayName << std::endl;
CoTaskMemFree(displayName);
audioSessionControl->Release();
}
audioSessionEnumerator->Release();
My mixer currently looks like this:
The expected output is:
Steam Client Bootstrapper
melodysheep - The Face of Creation
System Sounds
However, the output seen is:
(blank line)
(blank line)
#%SystemRoot%\System32\AudioSrv.Dll,-202
Which is the same as the output when GetDisplayName is replaced with GetIconPath.
What problem occurs in the code above to cause this issue? If more code must be shown, please inform me.

If you read the remarks for both GetDisplayName and GetIconName in MSDN you'll see that the functions can return NULL if no-one has set them. The GetIconName page also then remarks that the sndvol application (which you've got a screenshot of) will actually look up the icon of the main window if it's NULL, and therefore by induction will lookup the main window title for the display name if it doesn't exist.
You probably want to query for the IAudioSessionControl2 interface which has a GetProcessId method which might return you the client process id. At which point you can use things like this and this to try and extract the values from the main window to be consistent.

Related

How do you identify "File Explorer" instances in an `IShellWindows` collection?

I'm trying to get a list of all "File Explorer" instances currently running. It's fairly straight forward getting a list that includes all instances, but I find myself running into a brick wall filtering that list to only "File Explorer" instances.
The following piece of code retrieves all Explorer instances, meaning both "File Explorer" and "Internet Explorer":
#include <comdef.h>
#include <ExDisp.h>
#include <ShlGuid.h>
#include <Windows.h>
#include <cstdio>
using _com_util::CheckError;
using std::puts;
_COM_SMARTPTR_TYPEDEF(IShellWindows, __uuidof(IShellWindows));
int main()
{
CheckError(::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));
// Acquire IShellWindows interface
IShellWindowsPtr spShellWindows{};
CheckError(spShellWindows.CreateInstance(CLSID_ShellWindows, nullptr, CLSCTX_LOCAL_SERVER));
// Request iterator
IUnknownPtr spEnum{};
CheckError(spShellWindows->_NewEnum(&spEnum));
IEnumVARIANTPtr spEnumVariant{};
CheckError(spEnum.QueryInterface(__uuidof(spEnumVariant), &spEnumVariant));
// Iterate over shell windows ...
while (true) {
variant_t var{};
// ... one element at a time
HRESULT hr = spEnumVariant->Next(1, &var, nullptr);
CheckError(hr);
// Iterator depleted?
if (hr == S_FALSE) break;
// Did we get the expected `IDispatch` interface?
if (var.vt != VT_DISPATCH) continue;
IDispatchPtr spDisp{};
spDisp.Attach(var.pdispVal, true);
puts("Got suspect; need ID");
// That was easy; now on to some real challenges
}
}
The obvious attempt
My first take at the problem was to just get rid of everything that isn't "File Explorer". Asking for the IWebBrowser2 interface would certainly only get an affirmative response from objects that actually are web browsers. Adding the following to the code above:
_COM_SMARTPTR_TYPEDEF(IWebBrowser2, __uuidof(IWebBrowser2));
// ...
int main()
{
// ...
IWebBrowser2Ptr spWebBrowser{};
hr = spDisp.QueryInterface(__uuidof(spWebBrowser), &spWebBrowser);
if (SUCCEEDED(hr)) puts("Implements IWebBrowser2");
// ...
After making the changes and running the code while an "Internet Explorer" instance is running produces the desired output. However, running the code while a "File Explorer" instance is running produces the same output! That's a surprise and a disappointment, all at the same time.
More robust, less useful
Exluding objects that can be identified as "not File Explorer" didn't work out. Let's try to only include objects that can be identified as "File Explorer" instead. That sounds even more obvious, but as we've learned, "obvious" and "not" go hand in hand when it comes to the Windows Shell.
I haven't actually implemented this, but the IShellWindows interface provides an Item method that can return only objects that match a particular ShellWindowTypeConstants (e.g. SWC_EXPLORER or SWC_BROWSER). Or return an object at a particular index in the window collection. But not BOTH!
So, yes, (potentially) more robust, but also less useful as it doesn't meet my requirements as soon as more than one instances of "File Explorer" are running. Bummer.
Circumstantial evidence
While neither of the above led anywhere, I started over and went on a full-blown investigation looking for hints. Since "File Explorer" browses the Shell namespace, there may be something to that account. The following outlines the approach, based on an article by Raymond Chen titled A big little program: Monitoring Internet Explorer and Explorer windows, part 1: Enumeration:
Starting from the IDispatch interface above, ask for a service with ID SID_STopLevelBrowser to get an IShellBrowser interface.
Call IShellBrowser::QueryActiveShellView to get an IShellView interface.
Ask the IShellView whether it implements something Shell-namespace-y, e.g. IPersistIDList.
If it does, conclude that we're holding a reference to a "File Explorer" instance.
This appears to produce the desired result, though it's not clear to me future-proof this is or when it stops working. Leaving aside how overly convoluted this appears, I'm concerned about its reliability.
Question
What's the recommended/robust/reliable way to identify all "File Explorer" instances in an IShellWindows collection? I will favor solutions based on official documentation, though I understand that this is the Windows Shell and there's next to no documentation at all.
Here's a possibility ...
#include <comdef.h>
#include <ExDisp.h>
#include <ShlGuid.h>
#include <Windows.h>
#include <cstdio>
#include <atlbase.h>
#include <string>
using _com_util::CheckError;
using std::puts;
using std::string;
_COM_SMARTPTR_TYPEDEF(IShellWindows, __uuidof(IShellWindows));
//nicked from StackOverflow
std::string ProcessIdToName(DWORD_PTR processId)
{
std::string ret;
HANDLE handle = OpenProcess(
PROCESS_QUERY_LIMITED_INFORMATION,
FALSE,
processId /* This is the PID, you can find one from windows task manager */
);
if (handle)
{
DWORD buffSize = 1024;
CHAR buffer[1024];
if (QueryFullProcessImageNameA(handle, 0, buffer, &buffSize))
{
ret = buffer;
}
else
{
printf("Error GetModuleBaseNameA : %lu", GetLastError());
}
CloseHandle(handle);
}
else
{
printf("Error OpenProcess : %lu", GetLastError());
}
return ret;
}
int main()
{
CheckError(::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));
// Acquire IShellWindows interface
IShellWindowsPtr spShellWindows{};
CheckError(spShellWindows.CreateInstance(CLSID_ShellWindows, nullptr, CLSCTX_LOCAL_SERVER));
// Request iterator
IUnknownPtr spEnum{};
CheckError(spShellWindows->_NewEnum(&spEnum));
IEnumVARIANTPtr spEnumVariant{};
CheckError(spEnum.QueryInterface(__uuidof(spEnumVariant), &spEnumVariant));
// Iterate over shell windows ...
while (true) {
variant_t var{};
// ... one element at a time
HRESULT hr = spEnumVariant->Next(1, &var, nullptr);
CheckError(hr);
// Iterator depleted?
if (hr == S_FALSE) break;
// Did we get the expected `IDispatch` interface?
if (var.vt != VT_DISPATCH) continue;
IDispatchPtr spDisp{};
spDisp.Attach(var.pdispVal, true);
puts("Got suspect; need ID");
// That was easy; now on to some real challenges
CComPtr<IWebBrowser2> lpWB;
spDisp->QueryInterface(&lpWB);
SHANDLE_PTR hWnd{ 0 };
lpWB->get_HWND(&hWnd);
if (hWnd)
{
DWORD pid = 0;
GetWindowThreadProcessId((HWND)hWnd, &pid);
if (pid != 0)
{
puts("pid");
auto s = ProcessIdToName((DWORD_PTR)pid);
puts(s.c_str());
}
}
}
}

SystemParametersInfo sets background to solid color rather than actually setting the picture

I have tried all of the solution specified on these posts:
How to change the windows 10 wallpaper with C++?
How to change desktop background using VC++
SystemParametersInfo sets wallpaper completly black (using SPI_SETDESKWALLPAPER)
And i still cant seem to be able to get it working.... heres my code:
const wchar_t* path = L"C:\\imagge.png";
bool result = SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, (void*)path, SPIF_UPDATEINIFILE);
std::cout << result;
Also if i specify a path that aint valid it still prints 1(true) when it clearly states on docs SPI_SETDESKWALLPAPER bit that it should return 0(false) if theirs a problem
Also i have tried calling printing out GetLastError(); and it returns 0....
Note When the SPI_SETDESKWALLPAPER flag is used, SystemParametersInfo
returns TRUE unless there is an error (like when the specified file
doesn't exist).
IInspectable suggested using IDesktopWallpaper interface
And i got it working!
Heres my code:
int main() {
std::wstring x = L"C:\\Users\\danie\\OneDrive\\Pictures\\pixelArt\\Sample.png";
HRESULT ad;
CoInitialize(NULL);
IDesktopWallpaper* p;
if(SUCCEEDED(CoCreateInstance(__uuidof(DesktopWallpaper), 0, CLSCTX_LOCAL_SERVER, __uuidof(IDesktopWallpaper), (void**)&p))) {
ad = p->SetWallpaper(NULL, x.c_str());
p->Release();
}
CoUninitialize();
return 0;
}

Video Renderer Filter rejects sample

Currently my filter just forwards data from one input pin to a renderer-filter. I am testing it in graphstudio.
Now, everything seems to work just fine except that in the Deliver method of my output pin the call to
the connected input pin returns a sample-rejected error code. (
VFW_E_SAMPLE_REJECTED
0x8004022B )
According to MSDN this can happen if one the following is true:
The pin is flushing (see Flushing).
The pin is not connected.
The filter is stopped.
Some other error occurred
I don't think the first one is true. It can't be flushing for all input samples
The second one cannot be true because the filters have been conncected.
Third one is unlikely. Why should the filter be stopped.
So I think it must be some other error, but I couldn't find much helpful information.
HRESULT MCMyOutputPin::Deliver(IMediaSample* sample)
{
HRESULT hr = NO_ERROR;
myLogger->LogDebug("In Outputpin Deliver", L"D:\\TEMP\\yc.log");
if (sample->GetActualDataLength() > 0)
{
hr = m_pInputPin->Receive(sample);
sample->AddRef();
}
return hr;
//Forward to filter
}
As you can see i made sure to use the IMemAllocator provided by the input pin
HRESULT MCMyOutputPin::DecideAllocator(IMemInputPin *pPin, IMemAllocator **ppAlloc)
{
ALLOCATOR_PROPERTIES *pprops = new ALLOCATOR_PROPERTIES;
/*HRESULT hr = pPin->GetAllocatorRequirements(pprops);
if (FAILED(hr))*/
//return hr;
HRESULT hr = pPin->GetAllocator(ppAlloc);
if (hr == VFW_E_NO_ALLOCATOR)
{
hr = InitAllocator(ppAlloc);
if (FAILED(hr))
return hr;
}
hr = DecideBufferSize(*ppAlloc, pprops);
if (FAILED(hr))
return hr;
hr = pPin->NotifyAllocator(*ppAlloc, TRUE);
if (FAILED(hr))
{
return hr;
}
*ppAlloc = m_pAllocator;
m_pAllocator->AddRef();
return hr;
}
Here is where i get sample in my inputpin from the precdeing filter:
HRESULT CMyInputPin::Receive(IMediaSample *pSample)
{
mylogger->LogDebug("In Inputpin Receive", L"D:\\TEMP\\yc.log");
//Forward to filter
filter->acceptFilterInput(pinname, pSample);
return S_OK;
}
This calls acceptFilterInput in my filter:
void MyFilter::acceptFilterInput(LPCWSTR pinname, IMediaSample* sample)
{
//samplesPin0.insert(samplesPin0.end(), sample);
mylogger->LogDebug("In acceptFIlterInput", L"D:\\TEMP\\yc.log");
outpin->Deliver(sample);
}
the deliver method is already posted above
So many question asked recently, and you still don't ask them the right way. Here is the checklist to check your questions against before posting.
You have a rejection? What is the error code then.
Video renders are picky for input, for performance reasons. So if you are connecting to video renderer, you have to do everything correctly. Even if you can cut corners with other filters, it does not work out with video renderers.
My guess is that you ignore the rule that media samples on pin connection have to belong to the agreed allocator. VMR will only accept samples from its own allocator (effectively backed by video surfaces). One does not simply "forward" a media sample from input pin, which belongs to another allocator, to VMR's input. My best best it is the problem you are having. You have to copy data instead of passing media sample pointer between pins (or you have to propagate VMR's allocator, which is a pretty advanced task).
Additionally, VMR/EVR have specific requirements for video stride. As long as I see direct connection between VMR and your filter, I suspect you might be ignoring it, in which case you will face this problem later, but you can start reading MSDN right away: Handling Format Changes from the Video Renderer.

0x80070002 when trying to set default browser

I'm trying to set the default browser on Windows. I did have it working, and then for some reason it stopped when I refactored my code and I can't work out why (and I can't get the old code back unfortunately).
Here is a test I wrote which I believe should work:
#include <windows.h>
#include <Shobjidl.h>
void test()
{
// Included because they aren't defined in mingw for some reason.
const GUID CLSID_ApplicationAssociationRegistration =
{ 0x591209c7, 0x767b, 0x42b2, {0x9f,0xba,0x44,0xee,0x46,0x15,0xf2,0xc7} };
const IID IID_ApplicationAssociationRegistration =
{ 0x4e530b0a, 0xe611, 0x4c77, {0xa3,0xac,0x90,0x31,0xd0,0x22,0x28,0x1b} };
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
IApplicationAssociationRegistration* pAAR;
HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
NULL,
CLSCTX_INPROC,
IID_ApplicationAssociationRegistration,
(void**)&pAAR);
if (FAILED(hr))
{
qDebug() << "CoCreateInstance failed: " << hr;
return;
}
hr = pAAR->SetAppAsDefault(L"IE.HTTP", L"http", AT_URLPROTOCOL);
if (FAILED(hr))
{
qDebug() << "SetAppAsDefault failed: " << hr;
pAAR->Release();
return;
}
pAAR->Release();
qDebug() << "Success";
return;
}
I get "SetAppAsDefault failed: -2147024894" (0x80070002). Note that CoCreateInstance does work (or at least claims to).
Any ideas? I've tried changing COINT_APARTMENTTHREADED to various other values, and CLSCTX_INPROC too. None of them work. Please explain your answer as if I have never used COM before and have no desire to fill my brain with it! I.e. I have no idea what marshalling, apartments, etc. are.
I'm 80% sure something very similar to this did work...
Update: Sorry I previously said it was giving E_NOINTERFACE which was totally wrong - not sure why I thought that. 0x80070002 doesn't appear to be anything though...
Update 2: 0x80070002 means "The system cannot find the file specified." according to FormatMessage. I have no idea how that makes sense in this context though.
Follow Microsoft's guidelines when working with the default browser as you will encounter many issues on many os versions.
http://msdn.microsoft.com/en-us/library/windows/desktop/cc144154(v=vs.85).aspx#browser

Direct2d CreateBitmapfromWICBitmap giving assert error within ATL

I have a simple function that loads a Png file and returns it as a ID2D1Bitmap. But when it tries to call the CreateBitmapfromWicBitmap function, it gives a debug assert error. The funny thing is that I first made an imageload function in a seperate project, and it works fine in there. Both of these functions have the same code, while the second one is giving errors.
Here's the erroring code:
ID2D1Bitmap* Wnd::LoadPng(LPCWSTR Path) {
CComPtr<IWICBitmapDecoder> pDecoder;
CComPtr<IWICBitmapFrameDecode> pFrame;
CComPtr<ID2D1Bitmap> pBit;
CComPtr<IWICFormatConverter> pConv;
HRESULT Hr;
Hr = m_pWICFactory->CreateDecoderFromFilename(Path,NULL,GENERIC_READ,WICDecodeMetadataCacheOnDemand,&pDecoder);
if (SUCCEEDED(Hr)) {
Hr = m_pWICFactory->CreateFormatConverter(&pConv);
}
if (SUCCEEDED(Hr)) {
Hr = pDecoder->GetFrame(0,&pFrame);
}
if (SUCCEEDED(Hr)) {
Hr = pConv->Initialize(pFrame,GUID_WICPixelFormat32bppPBGRA,WICBitmapDitherTypeNone,0,0.f,WICBitmapPaletteTypeCustom);
}
if (SUCCEEDED(Hr)) {
Hr = m_pRT->CreateBitmapFromWicBitmap(pConv,0,&pBit);
}
return pBit;
}
The error happens in atlcomcli.h at line 182 in function _NoAddRefReleaseOnCComPtr.
I double-checked all headers and libraries and they're the same in both projects (With some extra headers in the second project).
Here's the code that WORKS:
CComPtr<IWICFormatConverter> Conv;
m_pWICFactory->CreateFormatConverter(&Conv);
CComPtr<IWICBitmapFrameDecode> Frame;
m_pDecoder->GetFrame(0,&Frame);
Frame->GetSize(&W,&H);
Conv->Initialize(Frame,GUID_WICPixelFormat32bppPBGRA,WICBitmapDitherTypeNone,0,0.f,WICBitmapPaletteTypeCustom);
CComPtr<ID2D1Bitmap> Bit;
Hr = m_pRT->CreateBitmapFromWicBitmap(Conv,0,&Bit);
m_pBitmap.push_back(Bit);
BitmapDecoder is predefined here, but it's exactly the same as in the first snippet.
------------------------------- FIXED ----------------------------
Third time I forgot to call the init function for my rendertarget.
The assertion failure warns you that you are trying to "use" a NULL interface pointer through CComPtr template. You should look up on the call stack which exactly line of your code you are at, and what variable holds NULL pointer which you expect to be non-NULL. Or otherwise just step through your code with debugger.