This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| DirectShow Test Submitted by

I've made a simple DirectShow test program, with which you can view and test installed DirectX audio plug-ins. Also program shows how can you use non-resource based dialogs from Win32 Application (console/windowed). Another thing here is how to show property pages from COM object without OlePropertyCreateFrame, and how to show them in your dialog with automatic sizing.
In order to compile, one must click one the CPP file, then press F7 - and MSVC will ask you to create project automatically for him/her. DirectX8 must be installed on the system, and his path accessible from MSVC.
The program/source can be useful to audio-tool developers, who need to make some tools for converting audio waves or test installed plugins.
There are known bugs into program, so flaming will be useless. The program and source are given just for tutorial how to make the things.
I've started COM/DirectShow 3 weeks ago, and this is one of the programs I've got till now. I have one more for converting wave data from memory and putting it again to memory - by using my own filter source and filter renderer.
Thanx,
malkia

Download Associated File: dxPluginViewer.cpp (11,553 bytes)

    #define WIN32_LEAN_AND_MEAN 1
    #define WIN32_EXTRA_LEAN 1
    #include <objbase.h>
    #include <commdlg.h>
    #include <ocidl.h>
    #include <stdio.h>
    #pragma comment(linker,"/ENTRY:mainCRTStartup")
    #pragma comment(linker,"/SUBSYSTEM:CONSOLE")
    #pragma comment(lib,"rpcrt4") // UUIDFromString()

    // This was compiled with DirectX8 (DirectShow8)
    // and Microsoft Visual C/C++ 6.00

    #define PLAYWAVE 1

    #if PLAYWAVE
    #include <dshow.h>
    #include <uuids.h>

    #pragma comment(lib,"strmiids")

    static IGraphBuilder* waveGraph = 0;
    static char waveName[1024];

    void LoadWave( void )
    {
    	OPENFILENAME ofn = {sizeof(ofn)};
    	ofn.lpstrFile = waveName;
    	ofn.nMaxFile = sizeof(waveName);
    	GetOpenFileName( &ofn );
    }

    void PlayStop( void )
    {
    	if( waveGraph )
    	{
    		IMediaControl *mc = 0;
    		if( waveGraph->QueryInterface( IID_IMediaControl, (void **)&mc ) == S_OK && mc )
    		{
    			mc->Stop();
    			mc->Release();
    		}
    		waveGraph->Release();
    		waveGraph = 0;
    	}
    }

    void PlayWave( IUnknown *filter )
    {
    	WCHAR wPath[1024];
    	HRESULT hr;

    	PlayStop();

    	waveGraph = 0;
        hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (LPVOID *)&waveGraph);
        MultiByteToWideChar(CP_ACP, 0, waveName, -1, wPath, sizeof(wPath)/sizeof(wPath[0]));
    	if( filter )
    	{
    		IBaseFilter *baseFilter;
    		hr = filter->QueryInterface( IID_IBaseFilter, (void **)&baseFilter);
    		hr = waveGraph->AddFilter( (IBaseFilter *) baseFilter, L"Filter" );
    		baseFilter->Release();
    	}
        hr = waveGraph->RenderFile(wPath, NULL);

    	if( waveGraph )
    	{
    		IMediaControl *mc = 0;
    		if( waveGraph->QueryInterface(IID_IMediaControl, (void **)&mc) == S_OK && mc )
    		{
    			mc->Run();
    			mc->Release();
    		}
    	}
    }

    #endif

    /* code - malkia@mindless.com */

    static struct FILTER {
    	char *name;
    	UUID uuid;
    } filters[ 1024 ];
    static int n_filters;

    static int FilterNameSortFunc( const void *a, const void *b )
    {
    	return strcmp( ((FILTER *)a)->name, ((FILTER *)b)->name );
    }

    static void EnumFilters( void )
    {
    	HKEY hKeyFilter;
    	HKEY hKeyCLSID;
    	char keyVal[1024];
    	DWORD keySize;
    	DWORD keyType;
    	FILETIME keyTime;
    	int index;

    	if( RegOpenKeyEx(HKEY_CLASSES_ROOT,"filter",0,KEY_READ,&hKeyFilter)==S_OK )
    	{
    		for( index=0; RegEnumKeyEx(hKeyFilter,index,keyVal,&(keySize=sizeof(keyVal)),0,NULL,NULL,&keyTime)==S_OK; index++ )
    		{
    			char clsidKey[1024];
    			char name[1024];

    			sprintf( (char*)clsidKey, "CLSID\\%s", keyVal );
    			if( RegOpenKeyEx(HKEY_CLASSES_ROOT, (char*)clsidKey, 0, KEY_READ, &hKeyCLSID) == S_OK )
    			{
    				if(RegQueryValueEx(hKeyCLSID,"",0,&(keyType=REG_SZ),(LPBYTE)name,&(keySize=sizeof(name)))==S_OK)
    				{
    					if(keyVal[0]=='{') strcpy( keyVal, keyVal + 1 );
    					if(keyVal[strlen(keyVal)-1]=='}') keyVal[strlen(keyVal)-1]=0;
    					if(UuidFromString( (LPBYTE)keyVal, &filters[n_filters].uuid )==S_OK)
    					{
    						filters[n_filters].name = strdup( name );
    						if(++n_filters == sizeof(filters)/sizeof(filters[0]))
    							break;
    					}
    				}
    				RegCloseKey(hKeyCLSID);
    			}
    		}
    	}
    	qsort(filters,n_filters,sizeof(filters[0]),FilterNameSortFunc);
    }

    enum { // These are our ids inside the dialog
    	ID_Null,
    	ID_FiltersListBox,
    	ID_OkButton,
    	ID_CancelButton,
    	ID_PlayButton,
    	ID_LoadButton,
    };

    // Resizes a window to fit a client area size(width,height)
    static void windowSize( HWND wnd, int width, int height )
    {
    	RECT crect, wrect;
    	int screenWidth, screenHeight;
    	int windowWidth, windowHeight;
    	GetWindowRect( wnd, &wrect );
    	GetClientRect( wnd, &crect );
    	screenWidth = GetSystemMetrics( SM_CXSCREEN );
    	screenHeight = GetSystemMetrics( SM_CYSCREEN );
    	windowWidth = wrect.right - wrect.left - crect.right + width,
    	windowHeight = wrect.bottom - wrect.top - crect.bottom + height;
    	MoveWindow( wnd, (screenWidth - windowWidth)/2,	(screenHeight - windowHeight)/2, windowWidth, windowHeight, TRUE );
    }

    static void dialogFit( HWND dlg, int propPageWidth, int propPageHeight, RECT *rect )
    {
    	enum {
    		MinDialogHeight = 50, //400,
    		ListBoxWidth = 200,
    		ButtonWidth = 60,
    		ButtonHeight = 20,
    		ButtonOffset = 4,
    		MinDialogWidth = ListBoxWidth + ButtonOffset + 4*(ButtonOffset + ButtonWidth),
    	};

    	HWND listBox, button1, button2, button3, button4;
    	int screenWidth, screenHeight;
    	int dialogWidth, dialogHeight;
    	screenWidth = GetSystemMetrics( SM_CXSCREEN );
    	screenHeight = GetSystemMetrics( SM_CYSCREEN );

    	listBox = GetDlgItem( dlg, ID_FiltersListBox );
    	button1 = GetDlgItem( dlg, ID_CancelButton );
    	button2 = GetDlgItem( dlg, ID_OkButton );
    	button3 = GetDlgItem( dlg, ID_LoadButton );
    	button4 = GetDlgItem( dlg, ID_PlayButton );

    	dialogWidth  = ListBoxWidth + propPageWidth;
    	dialogHeight = propPageHeight + ButtonOffset*2 + ButtonHeight;

    	if( dialogWidth < MinDialogWidth )
    		dialogWidth = MinDialogWidth;

    	if( dialogHeight < MinDialogHeight )
    		dialogHeight = MinDialogHeight;

    	windowSize( dlg, dialogWidth, dialogHeight );
    	MoveWindow( listBox, 0, 0, ListBoxWidth, dialogHeight, TRUE );
    	MoveWindow( button1, dialogWidth - 1*(ButtonOffset + ButtonWidth), dialogHeight - ButtonOffset - ButtonHeight, ButtonWidth, ButtonHeight, TRUE );
    	MoveWindow( button2, dialogWidth - 2*(ButtonOffset + ButtonWidth), dialogHeight - ButtonOffset - ButtonHeight, ButtonWidth, ButtonHeight, TRUE );
    	MoveWindow( button3, dialogWidth - 3*(ButtonOffset + ButtonWidth), dialogHeight - ButtonOffset - ButtonHeight, ButtonWidth, ButtonHeight, TRUE );
    	MoveWindow( button4, dialogWidth - 4*(ButtonOffset + ButtonWidth), dialogHeight - ButtonOffset - ButtonHeight, ButtonWidth, ButtonHeight, TRUE );

    	if( rect )
    	{
    		rect->left   = ListBoxWidth;
    		rect->top    = 0;
    		rect->right  = rect->left + propPageWidth;
    		rect->bottom = rect->top + propPageHeight;
    	}
    }

    static struct {
    	IUnknown *filter;
    	IPropertyPage *propPage;
    	int propWidth, propHeight;
    } activeFilter;

    static void SetActiveFilter( HWND wnd, int item )
    {
    	CAUUID caGUID={0};
    	ISpecifyPropertyPages *pSpecProp=0;
    	try
    	{
    		HRESULT hr;
    		PROPPAGEINFO pPageInfo;

    		if( activeFilter.propPage )
    		{
    			activeFilter.propPage->Deactivate();
    			activeFilter.propPage->Release();
    			activeFilter.propPage=0;
    		}

    		if( activeFilter.filter )
    		{
    			activeFilter.filter->Release();
    			activeFilter.filter = 0;
    		}

    		if(	(hr=CoCreateInstance(filters[item].uuid,NULL,CLSCTX_INPROC_SERVER,IID_IUnknown,(void**)&activeFilter.filter))==S_OK
    		&&	(hr=activeFilter.filter->QueryInterface(IID_ISpecifyPropertyPages,(void**)&pSpecProp))==S_OK
    		&&	(hr=pSpecProp->GetPages(&caGUID))==S_OK
    		&&	(caGUID.cElems >= 1) // but actually we are showing only the first page
    		&&	(hr=CoCreateInstance(caGUID.pElems[0],NULL,CLSCTX_INPROC_SERVER,IID_IPropertyPage,(void**)&activeFilter.propPage))==S_OK
    		&&	(hr=activeFilter.propPage->SetObjects(1,(IUnknown **)&activeFilter.filter))==S_OK
    		&&	(hr=activeFilter.propPage->GetPageInfo(&pPageInfo))==S_OK)
    		{
    			RECT rect;
    			dialogFit( wnd, pPageInfo.size.cx, pPageInfo.size.cy, &rect );
    			activeFilter.propWidth = pPageInfo.size.cx;
    			activeFilter.propHeight = pPageInfo.size.cy;
    			activeFilter.propPage->Activate( wnd, &rect, FALSE );
    			activeFilter.propPage->Show( SW_SHOW );
    		}
    		else
    		{
    			dialogFit( wnd, 0, 400, NULL );
    		}
    	}
    	catch( ... )
    	{
    	}
    	if( pSpecProp ) pSpecProp->Release();
    	if( caGUID.pElems ) CoTaskMemFree(caGUID.pElems);
    }

    static INT_PTR CALLBACK dialogProc( HWND dlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
    {
    	switch( uMsg )
    	{
    		HGDIOBJ font;
    		int i;

    		case WM_INITDIALOG:
    			SetWindowText( dlg, "DirectX audio plug-ins viewer 0.10 - " __DATE__ "/" __TIME__ " malkia@mindless.com");
    			font = GetStockObject( DEFAULT_GUI_FONT );
    			SendDlgItemMessage( dlg, ID_FiltersListBox,	WM_SETFONT, (WPARAM)font, FALSE );
    			SendDlgItemMessage( dlg, ID_OkButton,		WM_SETFONT, (WPARAM)font, FALSE );
    			SendDlgItemMessage( dlg, ID_CancelButton,	WM_SETFONT, (WPARAM)font, FALSE );
    			SendDlgItemMessage( dlg, ID_PlayButton,		WM_SETFONT, (WPARAM)font, FALSE );
    			SendDlgItemMessage( dlg, ID_LoadButton,		WM_SETFONT, (WPARAM)font, FALSE );

    			SetDlgItemText( dlg, ID_OkButton,		"Ok" );
    			SetDlgItemText( dlg, ID_CancelButton,	"Cancel" );
    			SetDlgItemText( dlg, ID_PlayButton,		"Play" );
    			SetDlgItemText( dlg, ID_LoadButton,		"Load" );

    			for( i=0; i<n_filters; i++ )
    				SendDlgItemMessage( dlg, ID_FiltersListBox, LB_ADDSTRING, 0, (LPARAM)filters[i].name);

    			dialogFit( dlg, 0, 400, NULL );
    			return FALSE;

    		case WM_COMMAND:
    			switch(LOWORD(wParam))
    			{
    				case ID_LoadButton:
    					#if PLAYWAVE
    					EnableWindow(dlg,FALSE);
    					LoadWave();
    					EnableWindow(dlg,TRUE);
    					SetForegroundWindow( dlg );
    					#endif
    					break;

    				case ID_PlayButton:
    					#if PLAYWAVE
    					EnableWindow(dlg,FALSE);
    					PlayWave(activeFilter.filter);
    					EnableWindow(dlg,TRUE);
    					#endif
    					break;

    				case ID_OkButton:
    					EndDialog( dlg, 1 );
    					break;

    				case ID_CancelButton:
    					EndDialog( dlg, 0 );
    					break;

    				case ID_FiltersListBox:
    					switch(HIWORD(wParam))
    					{
    						case LBN_DBLCLK:
    							i = SendDlgItemMessage(dlg, ID_FiltersListBox,LB_GETCURSEL,0,0);
    							if( i != LB_ERR )
    							{
    								// Some DEMO versions of various plugin are displaying a MessageBox before
    								// inializing the object - Enable/DisableWindow is for them.
    								// Example: FASOFT.COM n-Track trial version plug-ins
    								EnableWindow( dlg, FALSE );
    								SetActiveFilter(dlg, i );
    								EnableWindow( dlg, TRUE );
    								SetForegroundWindow( dlg );
    							}
    							break;
    					}
    					break;
    			}
    			return TRUE;
    	}
    	return FALSE;
    }

    #define	DLG_ITEM(type,id,style,styleEx,x,y,cx,cy) style,styleEx,x,y,cx,cy,id,0xFFFF,type,0,0,0
    #define	DLG_BUTTON(   id,style,styleEx,x,y,cx,cy) DLG_ITEM(0x0080,id,style,styleEx,x,y,cx,cy)
    #define	DLG_EDIT(     id,style,styleEx,x,y,cx,cy) DLG_ITEM(0x0081,id,style,styleEx,x,y,cx,cy)
    #define	DLG_STATIC(   id,style,styleEx,x,y,cx,cy) DLG_ITEM(0x0082,id,style,styleEx,x,y,cx,cy)
    #define	DLG_LISTBOX(  id,style,styleEx,x,y,cx,cy) DLG_ITEM(0x0083,id,style,styleEx,x,y,cx,cy)
    #define DLG_SCROLLBAR(id,style,styleEx,x,y,cx,cy) DLG_ITEM(0x0084,id,style,styleEx,x,y,cx,cy)
    #define DLG_COMBOBOX( id,style,styleEx,x,y,cx,cy) DLG_ITEM(0x0085,id,style,styleEx,x,y,cx,cy)

    typedef struct {
    	DLGITEMTEMPLATE item;
    	WORD  _0xFFFF;
    	WORD  type;
    	WORD  _zero0;
    	WORD  _zero1;
    	WORD  _zero2;
    } DIALOG_ITEM;

    typedef struct {
    	DLGTEMPLATE dialogTemplate;
    	WORD _zer0,_zero1, zero2;
    	DIALOG_ITEM items[5];
    } DIALOG;

    static DIALOG dialogRes =
    {
    	{ WS_CAPTION|DS_CENTER,0,sizeof(dialogRes.items)/sizeof(dialogRes.items[0]),0,0,0,0 }, 0,0, 0,
    	{
    		DLG_LISTBOX(ID_FiltersListBox,	WS_BORDER|WS_CHILD|WS_VISIBLE|WS_VSCROLL|LBS_NOINTEGRALHEIGHT|LBS_NOTIFY,0,0,0,0,0),
    		DLG_BUTTON(	ID_OkButton,		WS_CHILD|WS_VISIBLE|BS_TEXT|BS_CENTER|BS_DEFPUSHBUTTON,0,0,0,0,0),
    		DLG_BUTTON(	ID_CancelButton,	WS_CHILD|WS_VISIBLE|BS_TEXT|BS_CENTER|BS_PUSHBUTTON,0,0,0,0,0),
    		DLG_BUTTON(	ID_LoadButton,		WS_CHILD|WS_VISIBLE|BS_TEXT|BS_CENTER|BS_PUSHBUTTON,0,0,0,0,0),
    		DLG_BUTTON(	ID_PlayButton,		WS_CHILD|WS_VISIBLE|BS_TEXT|BS_CENTER|BS_PUSHBUTTON,0,0,0,0,0),
    	}
    };

    void main( int argc, char *argv[])
    {
    	CoInitialize(NULL);
    	EnumFilters();
    	DialogBoxIndirect( NULL, &dialogRes.dialogTemplate, NULL, dialogProc );
    	CoUninitialize();
    }

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.