• Welcome to Jose's Read Only Forum 2023.

ShowFilterPropertyPages Problem

Started by Jon Eskdale, July 16, 2014, 02:19:48 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Jon Eskdale

I'm trying to show the property pages of a Direct Show Filter

What I have at the moment is as below - This is not finished working code and does not work but shows what I'm trying

I have a couple of issues at the moment.

a) Is the declaration for OleCreatePropertyFrame correct I'm using the latest WINAPI_III_106. This code does not compile because
caGUID.pElems is a GUID PTR but the definition is BYREF lpPageClsID AS GUID if I edit the definition to what I think it should be BYVAL lpPageClsID AS GUID PTR it then compiles
Is there an error in the definition or is it my coding thats wrong (probably the latter)

b) The two MSGBOX's display the correct details
      msgbox FilterInfo.achName     'This displays the Filter Name
      MSGBOX str$(caGUID.cElems) 'This displays 1 which is correct for the filter I'm using

      BUT the call to OleCreatePropertyFrame crashes the program  I'm not sure if the definition is wrong or I'm passing the wrong parameters

Any assistance gratefully received


function ShowFilterPropertyPages(pFilter as IBaseFilter) as long
   local pProp as ISpecifyPropertyPages
   local FilterInfo as FILTER_INFO
   local pFilterUnk as IUnknown
   local caGUID as CAUUID
   local hr as long
   pProp = pFilter
   if isobject(pProp) THEN
      hr = pFilter.QueryFilterInfo(FilterInfo)
      pFilterUnk = pFilter
      pProp = Nothing
      msgbox FilterInfo.achName
      MSGBOX str$(caGUID.cElems)
      OleCreatePropertyFrame( _
      %NULL, _
      0, 0, _
      FilterInfo.achName, _
      1, _
      pFilterUnk, _
      caGUID.cElems, _
      caGUID.pElems, _
      0, _
      0, %Null)
      msgbox "Done"
      pFilterUnk = Nothing
      'FilterInfo = Nothing

José Roca

The declaration is correct, following the PB rules. This parameter expects a GUID or an array of GUIDs.

The member pElems of the CAUUID strcuture is a pointer to an allocated array of GUIDs, so you must no pass it, but to use it to extract the GUID or GUIDs and pass the extracted GUIDs. You then have to call CoTaskMemFree passing that pointer to free the array.

Jon Eskdale

Thanks Jose

One day perhaps I'll find something simple to do!!  This is really testing my skills at the moment. 
According to the parameter its expecting a GUID passed in which it will pass by reference correct?
You suggest extracting the GUID's do I understand correctly?
In the C sample code they somehow manage to just pass the parameter - But my C is very limited.  Any chance someone could give me a pointer on this one how do I pass this caGUID.pElems

The C sample is below

NULL, // Parent window
0, 0, // Reserved
FilterInfo.achName, // Caption for the dialog box
1, // Number of objects (just the filter)
&pFilterUnk, // Array of object pointers.
caGUID.cElems, // Number of property pages
caGUID.pElems, // Array of property page CLSIDs
0, // Locale identifier
0, NULL // Reserved

Thanks Jon

José Roca

Something like this:

REDIM rgElems(caGUID.cElems - 1) AS GUID
FOR i = 0 TO caGUID.cElems - 1
   rgElems(i) = caGUID.@pElems[i]

and then pass rgElems(0) to the OleCreatePropertyFrame function instead of caGUID.pElems, and NOTHING instead of pFilterUnk.

Jon Eskdale

Thanks Jose,

I gave that a try - the NOTHING instead of pFilterUnk stops it crashing but nothing is displayed it does return though as I get the Done Msgbox


Jon Eskdale

A Miracle just happened I used this code
and it Worked !!

     OleCreatePropertyFrame( _
         %NULL, _
         0, 0, _
         FilterInfo.achName, _
         1, _
         pFilterUnk, _
         caGUID.cElems, _
         caGUID.pElems, _
         0, _
         0, %Null)
      msgbox "Done"

But I changed the Declare in OleCtl.inc to

DECLARE FUNCTION OleCreatePropertyFrame IMPORT "OLEAUT32.DLL" ALIAS "OleCreatePropertyFrame" ( _
   BYVAL hwndOwner AS DWORD _                           ' __in HWND hwndOwner
, BYVAL x AS DWORD _                                   ' __in UINT x
, BYVAL y AS DWORD _                                   ' __in UINT y
, BYREF lpszCaption AS WSTRINGZ _                      ' __in LPCOLESTR lpszCaption
, BYVAL cObjects AS DWORD _                            ' __in ULONG cObjects
, BYREF lplpUnk AS IUnknown _                          ' __in LPUNKNOWN FAR* lplpUnk
, BYVAL cPages AS DWORD _                              ' __in ULONG cPages
, BYVAL lpPageClsID AS GUID PTR _                      ' __in LPCLSID lpPageClsID [array]
, BYVAL lcid AS DWORD _                                ' __in LCID lcid
, BYVAL dwReserved AS DWORD _                          ' __in DWORD dwReserved
, BYVAL lpvReserved AS DWORD _                         ' __in LPVOID lpvReserved
) AS LONG                                              ' HRESULT

so I change BYVAL lplpUnk AS IUnknown  to be BYREF lplpUnk AS IUnknown

The only trouble is I don't like changing definitions
Should I leave the BYVAL lplpUnk AS IUnknown and pass in OBJPTR(pFilterUnk) would that work?

José Roca

If it works, leave it as is and I will change the declare in the headers.

BYVAL lplpUnk is a mistake of mine. Since it is an array, it must be BYREF.

The other mistake has been caused because the documentation says "Array of size cPages containing the CLSIDs of each property page to display in the property sheet.", not a pointer to an array...

But the important is that you have got it to work.

José Roca

Remember to free the array with CoTaskMemFree(caGUID.pElems) or you will get a memory leak.

Jon Eskdale

Thanks Jose

Yes I did have that in my full version of the program - left it out of my test program because it was after my problem as was only another complication.

Now although it works I have one area which still worries me with this function which is in the Clean up

Below in the C code near the end is


Now I can't do FilterInfo.pGraph = Nothing  because pGraph is defined as DWORD PTR so that leaves the question as to how do I release  FilterInfo.pGraph ?
I presume I need to?  It works but will it get cleaned up on its own or will it cause a memory leak?

IBaseFilter *pFilter;
/* Obtain the filter's IBaseFilter interface. (Not shown) */
ISpecifyPropertyPages *pProp;
HRESULT hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pProp);
if (SUCCEEDED(hr))
    // Get the filter's name and IUnknown pointer.
    FILTER_INFO FilterInfo;
    hr = pFilter->QueryFilterInfo(&FilterInfo);
    IUnknown *pFilterUnk;
    pFilter->QueryInterface(IID_IUnknown, (void **)&pFilterUnk);

    // Show the page.
        hWnd,                   // Parent window
        0, 0,                   // Reserved
        FilterInfo.achName,     // Caption for the dialog box
        1,                      // Number of objects (just the filter)
        &pFilterUnk,            // Array of object pointers.
        caGUID.cElems,          // Number of property pages
        caGUID.pElems,          // Array of property page CLSIDs
        0,                      // Locale identifier
        0, NULL                 // Reserved

    // Clean up.

José Roca

It isdefined as DWORD PTR because the PB compiler does not support objects as members of an structures, but it is needed to release it to avoid memory leaks.

You can use my wrapper function IUnknown_Release, that is located in the file Ole2Utils.inc.