Direct2d CreateBitmapfromWICBitmap giving assert error within ATL - c++

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.

Related

C++ Optimization breaking OLE Automation program (non-MFC)

I'm writing a program to parse a Word Document and export data out to an Excel Workbook using OLE Automation (the non-MFC way I guess). Works fine in Debug, not so in Release (specifically if optimization is enabled). The error is that the IDispatch::Invoke call failed, specifically:
0x80020004 DISP_E_PARAMNOTFOUND Parameter not found
I checked StackOverflow for some suggestions and the main one seems to be uninitialized variables. That might be what's going on, but I still don't understand this specific case. I've narrowed it down to a single function in my program Automation::Dispatch::Invoke which is responsible for finally calling IDispatch::Invoke. The arguments being passed into Automation::Dispatch::Invoke are correct so the problem is somewhere in its code.
Looking at the base code (from MSDN) that I adapted this from, I was able to get it working and narrow down the exact problem line. Below shows code that does not work, but the comments indicate the line that I moved to get it working (look for the 2 lines with a <--- Problem line comment). In Debug mode, the location of this line does not matter and it works in either spot.
My question is what does this fix, and why is it an issue to start with? Thank you and let me know if I can make the question more clear.
HRESULT Automation::Dispatch::Invoke(int cmd, std::string name, std::vector<VARIANT> values)
{
USES_CONVERSION;
HRESULT result;
/* Get DISPID for name passed */
DISPID dispID;
LPOLESTR nameOle=A2OLE(name.c_str());
result=pObjectInt->GetIDsOfNames(IID_NULL, &nameOle, 1, LOCALE_USER_DEFAULT, &dispID);
if (FAILED(result)) {
return result;
}
/* Reverse elements in values vector so they are invoked in the correct order */
std::reverse(values.begin(), values.end());
/* Allocate memory for object values */
VARIANT *pValues=new VARIANT[values.size() + 1];
for (unsigned int i=0; i < values.size(); ++i) {
pValues[i]=values[i];
}
/* Build DISPPARAMS */
DISPPARAMS dispParams= {NULL, NULL, 0, 0};
/* DISPID dispidNamed=DISPID_PROPERTYPUT; <--- PROBLEM LINE moved here makes it work */
dispParams.cArgs=values.size();
dispParams.rgvarg=pValues;
/* Handle special-case for property-puts */
if (cmd==DISPATCH_PROPERTYPUT) {
DISPID dispidNamed=DISPID_PROPERTYPUT; /* <--- PROBLEM LINE here */
dispParams.cNamedArgs=1;
dispParams.rgdispidNamedArgs=&dispidNamed;
}
/* Make the call */
if (cmd==DISPATCH_METHOD || cmd==DISPATCH_PROPERTYPUT) {
result=pObjectInt->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, cmd, &dispParams, NULL, NULL, NULL);
}
else {
VariantInit(&objectData);
result=pObjectInt->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, cmd, &dispParams, &objectData, NULL, NULL);
}
delete[] pValues;
return result;
}
In this code:
if (cmd==DISPATCH_PROPERTYPUT) {
DISPID dispidNamed=DISPID_PROPERTYPUT; /* <--- PROBLEM LINE here */
dispParams.cNamedArgs=1;
dispParams.rgdispidNamedArgs=&dispidNamed;
}
dispidNamed is a local variable to the code block it is in (i.e. the area delimited by { }).
After the } is reached it ceases to exist. Then rgdispidNamedArgs is a dangling pointer because it no longer points to a variable that exists.
You got unlucky in Debug mode that it didn't trigger an error sooner.

Calling GetDisplayName returns same result as GetIconPath

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.

What is the different between system and Administrator account when call SHGetSpecialFolderLocation() function?

I write two program, one is windows service run in system account(named xxService) and the other one is common application run in Administrator account(named xx);
They use the same code to get CSIDL_COMMON_DOCUMENTS directory. In most machine , they run well.
But some machine, the xxService can get the correct directory, the xx have failure in SHGetSpecialFolderLocation();
edit:
the program only run on Windows XP(sp3).
edit2:
Use SHGetFolderPathA() function to solve this problem.
My english is poor, everybody excuse me!
log:
[2964] [db](tid=1108)(pid=2964): SHGetSpecialFolderLocation() fail.hr=0x80070057, ierr=122
the detail error info:
//
// MessageId: E_INVALIDARG
//
// MessageText:
//
// One or more arguments are invalid
//
#define E_INVALIDARG _HRESULT_TYPEDEF_(0x80070057L)
ERROR_INSUFFICIENT_BUFFER
122 (0x7A)
The data area passed to a system call is too small.
code:
//C:\Users\Public\Documents
LPITEMIDLIST pidl;
LPMALLOC pShellMalloc;
HRESULT hr = S_FALSE;
hr = SHGetMalloc(&pShellMalloc);
if(SUCCEEDED(hr))
{
hr = SHGetSpecialFolderLocation(NULL,CSIDL_COMMON_DOCUMENTS,&pidl);
if(SUCCEEDED(hr))
{
if(!SHGetPathFromIDListW(pidl, strDbFilePath))
{
int ierr=GetLastError();
DebugMsgW((L"SHGetPathFromIDListW() fail., ierr=%d"), ierr);
}
DebugMsgW(L"DBpath=%s",strDbFilePath);
pShellMalloc->Free(pidl);
}
else
{
int ierr=GetLastError();
DebugMsgW((L"SHGetSpecialFolderLocation() fail.hr=0x%x, ierr=%d"), hr, ierr);
}
pShellMalloc->Release();
}
else
{
int ierr=GetLastError();
DebugMsgW((L"SHGetMalloc() fail.hr=0x%x, ierr=%d"), hr, ierr);
}
SHGetSpecialFolderLocation() (and any other function that returns an HRESULT) does not use GetLastError() to report error codes, since the HRESULT is the error code. Even SHGetPathFromIDList() is not documented as using GetLastError(), either. So the return value of GetLastError() is irrelevant in your example and needs to be removed to avoid confusion.
As for the E_INVALIDARG error, you are using a legacy function. CSIDL_COMMON_DOCUMENTS is known to fail in SHGetSpecialFolderLocation() on some systems. You need to use a newer function, such as SHGetFolderPath(), or SHGetKnownFolderPath() on Vista+.

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.

E_NOINTERFACE when calling CreateDXGIFactory1

I am relatively new to C++ in general, and very new to Windows development.
I am writing a program that uses the DXGI library - it compiles just fine, but when I run the executable, the HRESULT from the CreateDXGIFactory1 comes out as 0x80004002, or E_NOINTERFACE.
Am I missing some sort of library, or is there a deeper issue at play here?
The code I am using follows:
Output is "Error: 0x80004002".
//Initialize a UUID
GUID uuid;
HRESULT hCreateUUID = CoCreateGuid(&uuid);
//Convert the UUID to string
LPOLESTR stringUUID;
HRESULT hStringToUUID = StringFromCLSID(uuid, &stringUUID);
//Initialize the factory pointer
IDXGIFactory1* pFactory;
//Actually create it
HRESULT hCreateFactory = CreateDXGIFactory1(uuid, (void**)(&pFactory));
if (hCreateFactory == S_OK) {
printf("Factory creation was a success\n");
} else {
printf("ERROR: 0x%X\n", hCreateFactory);
}
You are passing a random, freshly created GUID. This makes no sense. You are supposed to pass the IID of the interface you wish to obtain - namely, __uuidof(IDXGIFactory1). The example in the documentation shows just that.