|
|
|
date: Sun, 16 Oct 2005 02:52:01 -0700,
group: microsoft.public.win32.programmer.directx.misc
back
Re: Creating a custom DirectShow renderer filter.
On Sun, 16 Oct 2005 02:52:01 -0700, "Andrew Garrett"
wrote:
>Hi,
>
>I need to create a filter which is an alternative to the "File Writer"
>DirectShow Filter, specifically one which sends whatever it receives straight
>over the network. I am familiar with DirectShow, but not filter writing, and
>relatively familiar with C++. I have tried various tutorials and wizards and
>templates, but haven't really had much success at all in understanding the
>process. Could somebody please enlighten me as to how the filter-writing
>process works?
The documentation does a fairly good job of explaining what needs to be
done. Look at the documentation for CBaseRenderer, for instance. What,
specifically, are you having problems with?
--
Be seeing you.
date: Sun, 16 Oct 2005 10:56:36 -0500
author: Thore Karlsen [MVP DX]
Re: Creating a custom DirectShow renderer filter.
"Thore Karlsen [MVP DX]" wrote:
> On Sun, 16 Oct 2005 02:52:01 -0700, "Andrew Garrett"
> wrote:
>
> >Hi,
> >
> >I need to create a filter which is an alternative to the "File Writer"
> >DirectShow Filter, specifically one which sends whatever it receives straight
> >over the network. I am familiar with DirectShow, but not filter writing, and
> >relatively familiar with C++. I have tried various tutorials and wizards and
> >templates, but haven't really had much success at all in understanding the
> >process. Could somebody please enlighten me as to how the filter-writing
> >process works?
>
> The documentation does a fairly good job of explaining what needs to be
> done. Look at the documentation for CBaseRenderer, for instance. What,
> specifically, are you having problems with?
I'll take a look at that documentation - I was looking at basing it on the
CBaseFilter class - in accordance with the MSDN Documentation on writing a
transform filter (which was the only documentation i could find on writing a
filter. In any case, I'll have a look and get back to you. Thanks for your
help.
>
> --
> Be seeing you.
>
date: Sun, 16 Oct 2005 16:30:02 -0700
author: Andrew Garrett
Re: Creating a custom DirectShow renderer filter.
I've created the filter for myself, but I need to load it into GraphEdit to
test it. I've implemented all the stuff it says I should implement on the
MSDN website, and got it to appear in GraphEdit. My problem is that when I
try to create it in GraphEdit, it gives me the message:
"The filter could not be created. Resources used by this filter may already
be in use.
Error in the DLL (Return code 0x800401f9)".
The source code relevant to my implementation of registration follows:
//----------BEGIN-SOURCE-CODE--------//
//COM-DLL-Stuff.cpp
#include "stdafx.h"
#include "DirectShow Network Sender.h"
;
static WCHAR g_wszName[] = L"Epstone Network Sender Filter";
CUnknown * WINAPI CreateSenderInstance(LPUNKNOWN pUnk, HRESULT *pHr);
CFactoryTemplate g_Templates[] =
{
{
g_wszName,
&CLSID_NETWORKSENDERFILTER,
CreateSenderInstance,
NULL,
NULL
}
};
REGPINTYPES rptTypes[] = {{ &MEDIATYPE_Stream, &MEDIASUBTYPE_None }};
REGFILTERPINS sudPins = {
NULL,
true,
false,
false,
false,
NULL,
NULL,
1,
&rptTypes[0]
};
REGFILTER2 rf2FilterReg = {
1, // Version 1 (no pin mediums or pin category).
MERIT_DO_NOT_USE, // Merit.
1, // Number of pins.
&sudPins // Pointer to pin information.
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
CUnknown * WINAPI CreateSenderInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
CNetworkSenderFilter *pFilter = new CNetworkSenderFilter();
if (pFilter== NULL)
{
*pHr = E_OUTOFMEMORY;
}
return pFilter;
}
STDAPI DllRegisterServer()
{
HRESULT hr;
IFilterMapper2 *pFM2 = NULL;
hr = AMovieDllRegisterServer2(TRUE);
if (FAILED(hr))
return hr;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterMapper2, (void **)&pFM2);
if (FAILED(hr))
return hr;
hr = pFM2->RegisterFilter(
CLSID_NETWORKSENDERFILTER, // Filter CLSID.
g_wszName, // Filter name.
NULL, // Device moniker.
&CLSID_LegacyAmFilterCategory, // Video compressor category.
g_wszName, // Instance data.
&rf2FilterReg // Pointer to filter information.
);
pFM2->Release();
return hr;
}
STDAPI DllUnregisterServer()
{
HRESULT hr;
IFilterMapper2 *pFM2 = NULL;
hr = AMovieDllRegisterServer2(FALSE);
if (FAILED(hr))
return hr;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterMapper2, (void **)&pFM2);
if (FAILED(hr))
return hr;
hr = pFM2->UnregisterFilter(&CLSID_LegacyAmFilterCategory,
g_wszName, CLSID_NETWORKSENDERFILTER);
pFM2->Release();
return hr;
}
//DLLExport.def
LIBARY DirectShow Network Sender Filter.ax
EXPORTS
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
//----------END-SOURCE-CODE-----------//
--
Andrew Garrett
Epstone Networks
date: Mon, 17 Oct 2005 19:51:03 -0700
author: Andrew Garrett
Re: Creating a custom DirectShow renderer filter.
On Wed, 19 Oct 2005 19:36:05 -0700, "Andrew Garrett"
wrote:
>> >Okay, I resolved my previous issue (issue was not renaming .dll to .ax). I
>> >now have a bigger problem. When I create an instance of the filter, I end up
>> >with an exception trying to execute code at 0x0000. I believe the problem is
>> >that the pUnk pointer is NULL when it is passed to my CreateInstance
>> >function, and therefore is so when it is passed to the CBaseRenderer
>> >Constructor.
>> The best way to find out is to check the call stack in the debugger when
>> you get the crash. pUnk is normally NULL, though, and CBaseRenderer can
>> deal with that just fine, so that shouldn't be a problem.
>The call stack isn't helping at all. All it gives is 0x000000() - doesn't
>tell me where the problem came from. The only thing i can see is: "Unhandled
>exception at 0x00000000 in Webcam Capture Test.exe: 0xC0000005: Access
>violation reading location 0x00000000.". I had a look at 0xC0000005 and it
>seems blank. The size of my created renderer is 16 bytes. Is this normal. I
>can give you further output from my debugging output.
OK, how about stepping through your code until you get to the line that
causes the crash, and then posting the code around that point? From the
sound of it, your application is a relatively simple test application,
so it shouldn't be too hard to pinpoint the location that causes the
crash. I'll need to see some code to determine what the problem is.
--
Be seeing you.
date: Thu, 20 Oct 2005 10:00:32 -0500
author: Thore Karlsen [MVP DX]
Re: Creating a custom DirectShow renderer filter.
"Thore Karlsen [MVP DX]" wrote:
> On Wed, 19 Oct 2005 19:36:05 -0700, "Andrew Garrett"
> wrote:
>
> >> >Okay, I resolved my previous issue (issue was not renaming .dll to .ax). I
> >> >now have a bigger problem. When I create an instance of the filter, I end up
> >> >with an exception trying to execute code at 0x0000. I believe the problem is
> >> >that the pUnk pointer is NULL when it is passed to my CreateInstance
> >> >function, and therefore is so when it is passed to the CBaseRenderer
> >> >Constructor.
>
> >> The best way to find out is to check the call stack in the debugger when
> >> you get the crash. pUnk is normally NULL, though, and CBaseRenderer can
> >> deal with that just fine, so that shouldn't be a problem.
>
> >The call stack isn't helping at all. All it gives is 0x000000() - doesn't
> >tell me where the problem came from. The only thing i can see is: "Unhandled
> >exception at 0x00000000 in Webcam Capture Test.exe: 0xC0000005: Access
> >violation reading location 0x00000000.". I had a look at 0xC0000005 and it
> >seems blank. The size of my created renderer is 16 bytes. Is this normal. I
> >can give you further output from my debugging output.
>
> OK, how about stepping through your code until you get to the line that
> causes the crash, and then posting the code around that point? From the
> sound of it, your application is a relatively simple test application,
> so it shouldn't be too hard to pinpoint the location that causes the
> crash. I'll need to see some code to determine what the problem is.
The problem occurs in some ASM code - stepping through in the VS debugger I
have found a stack trace:
DSNetworkSender.ax!CClassFactory::CreateInstance() + 0xa9 C++
ole32.dll!775202e3()
ole32.dll!77520143()
ole32.dll!775203f2()
ole32.dll!77520369()
ole32.dll!7752112b()
ole32.dll!775210e2()
ole32.dll!77520453()
ole32.dll!77520143()
ole32.dll!775200de()
ntdll.dll!7c90fb6c()
ntdll.dll!7c90fb71()
kernel32.dll!7c809392()
ole32.dll!7750055e()
ole32.dll!7750067b()
ole32.dll!7750078e()
ole32.dll!775009b5()
ole32.dll!775017f3()
ole32.dll!775008df()
ole32.dll!775008fa()
ole32.dll!7751e53b()
ole32.dll!7751f4a2()
ole32.dll!77520143()
ole32.dll!7751f4ed()
ole32.dll!7751ff88()
ntdll.dll!7c96d886()
ntdll.dll!7c96d886()
ntdll.dll!7c949d18()
ntdll.dll!7c91b686()
ntdll.dll!7c91056d()
advapi32.dll!77dde0ae()
advapi32.dll!77dde32e()
advapi32.dll!77dde343()
advapi32.dll!77dde350()
and some asm code from that particular location:
10001E2A push 1
10001E2C mov ecx,esi
10001E2E call dword ptr [edx+0Ch]
10001E31 mov eax,dword ptr [esp+1Ch]
10001E35 pop esi
10001E36 pop ebx
10001E37 pop ebp
10001E38 ret 10h
10001E3B mov eax,dword ptr [esi]
10001E3D push esi
10001E3E call dword ptr [eax+4]
10001E41 mov ecx,dword ptr [esi]
10001E43 push ebp
10001E44 push ebx
10001E45 push esi
10001E46 call dword ptr [ecx]
10001E48 mov dword ptr [esp+1Ch],eax
10001E4C mov edx,dword ptr [esi]
10001E4E push esi
10001E4F call dword ptr [edx+8]
10001E52 mov eax,dword ptr [esp+1Ch]
10001E56 pop esi
10001E57 pop ebx
10001E58 pop ebp
10001E59 ret 10h
10001E5C int 3
10001E5D int 3
10001E5E int 3
10001E5F int 3
It appears to be having trouble creating an instance of the class factory,
having a quick squizz over the code. My code from the class factory part of
my dll follows:
//COM DLL Stuff.cpp
#include "stdafx.h"
#include "DirectShow Network Sender.h"
;
static WCHAR g_wszName[] = L"Epstone Network Sender Filter";
// Setup information
const AMOVIESETUP_MEDIATYPE sudPinTypes =
{
&MEDIATYPE_Video, // Major type
&MEDIASUBTYPE_NULL // Minor type
};
const AMOVIESETUP_PIN sudpPins[] =
{
{ L"Input", // Pins string name
FALSE, // Is it rendered
FALSE, // Is it an output
FALSE, // Are we allowed none
FALSE, // And allowed many
&CLSID_NULL, // Connects to filter
NULL, // Connects to pin
1, // Number of types
&sudPinTypes // Pin information
}
};
const AMOVIESETUP_FILTER sudSender =
{
&CLSID_NETWORKSENDERFILTER, // Filter CLSID
g_wszName, // String name
MERIT_DO_NOT_USE, // Filter merit
1, // Number of pins
sudpPins // Pin information
};
// List of class IDs and creator functions for the class factory. This
// provides the link between the OLE entry point in the DLL and an object
// being created. The class factory will call the static CreateInstance
CFactoryTemplate g_Templates[] = {
{ g_wszName
, &CLSID_NETWORKSENDERFILTER
, (LPFNNewCOMObject) CNetworkSenderFilter::CreateInstance
, NULL
, &sudSender }
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
CUnknown *CNetworkSenderFilter::CreateInstance(IN LPUNKNOWN pUnk, OUT
HRESULT *pHr)
{
char *message = new char[255];
char *hrstr = new char[20];
char *ptrstr = new char[20];
int pfsize;
char *szpfstr = new char[20];
char *pHrstr = new char[20];
char *pUnkstr = new char[20];
*pHr = S_OK;
CNetworkSenderFilter * pTheFilter;
TCHAR *tszName;
strcpy( (char*) tszName, "CNetworkSenderFilter" );
pTheFilter = new CNetworkSenderFilter( tszName, pUnk, pHr );
if (pTheFilter== NULL)
{
*pHr = E_OUTOFMEMORY;
}
//Display debugging message
strcpy( message, "Creating CNetworkSenderFilter, hr=" );
itoa( *pHr, hrstr, 16 );
strcat( message, hrstr );
ltoa( (long) pTheFilter, ptrstr, 16 );
strcat( message, ", pFilter=" );
strcat( message, ptrstr );
pfsize = sizeof( *pTheFilter );
itoa( pfsize, szpfstr, 16 );
strcat( message, ", sizeof(*pTheFilter)=" );
strcat( message, szpfstr );
ltoa( (long) pHr, pHrstr, 16 );
strcat( message, ", *pHr=" );
strcat( message, pHrstr );
ltoa( (long) pUnk, pUnkstr, 16 );
strcat( message, ", *pUnk=" );
strcat( message, pUnkstr );
MessageBox( NULL, message, "", MB_OK | MB_ICONINFORMATION );
delete message;
delete hrstr;
delete ptrstr;
delete szpfstr;
delete pHrstr;
delete pUnkstr;
return pTheFilter;
}
STDAPI DllRegisterServer()
{
return AMovieDllRegisterServer2(TRUE);
}
STDAPI DllUnregisterServer()
{
return AMovieDllRegisterServer2(FALSE);
}
// If we declare the correct C runtime entrypoint and then forward it to the
DShow base
// classes we will be sure that both the C/C++ runtimes and the base classes
are initialized
// correctly
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
BOOL WINAPI DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved)
{
return DllEntryPoint(reinterpret_cast<HINSTANCE>(hDllHandle), dwReason,
lpReserved);
}
>
> --
> Be seeing you.
>
date: Thu, 20 Oct 2005 15:55:02 -0700
author: Andrew Garrett
Re: Creating a custom DirectShow renderer filter.
On Thu, 20 Oct 2005 15:55:02 -0700, "Andrew Garrett"
wrote:
[...]
> TCHAR *tszName;
>
> strcpy( (char*) tszName, "CNetworkSenderFilter" );
Here you have two problems. First, you're copying to an uninitialized
string pointer. Second, if you're compiling for Unicode, the string will
be invalid. If you're never compiling for Unicode, you shouldn't be
using TCHAR.
Also, you really shouldn't be allocating C strings without a very good
reason. This is 2005, and we now have classes like std::string and
CString. :)
--
Be seeing you.
date: Thu, 20 Oct 2005 18:53:06 -0500
author: Thore Karlsen [MVP DX]
Re: Creating a custom DirectShow renderer filter.
"Thore Karlsen [MVP DX]" wrote:
> On Thu, 20 Oct 2005 15:55:02 -0700, "Andrew Garrett"
> wrote:
>
> [...]
>
> > TCHAR *tszName;
> >
> > strcpy( (char*) tszName, "CNetworkSenderFilter" );
>
> Here you have two problems. First, you're copying to an uninitialized
> string pointer. Second, if you're compiling for Unicode, the string will
> be invalid. If you're never compiling for Unicode, you shouldn't be
> using TCHAR.
I'm never compiling for unicode, but the CBaseRenderer argument expects a
TCHAR pointer, which I am providing it. Fixing up the NULL pointer issue
gives me this error instead - "Unhandled exception at 0x0012ffe0 in Webcam
Capture Test.exe: 0xC000001D: Illegal Instruction."
Stack Trace:
0012ffe0()
DSNetworkSender.ax!CClassFactory::CreateInstance() + 0x98 C++
Disassembly:
0012FFBB add byte ptr [eax],al
0012FFBD add byte ptr [eax],al
0012FFBF add al,dh
0012FFC1 call dword ptr [edx]
0012FFC3 add byte ptr [edi+6Dh],cl
0012FFC6 cmp dword ptr [edi+ecx*2+5Bh],407C91h
0012FFCE add byte ptr [eax],al
0012FFD0 add byte ptr [eax-3],ah
0012FFD3 jg 0012FFF2
0012FFD5 add byte ptr [eax],al
0012FFD7 ror al,0FFh
0012FFDA adc al,byte ptr [eax]
0012FFDC db b8h
0012FFDD in eax,dx
0012FFDE adc al,byte ptr [eax]
0012FFE0 db ffh
0012FFE1 db ffh
0012FFE2 db ffh
0012FFE3 push ebx
0012FFE5 cdq
0012FFE6 cmp dword ptr [eax+ebx*2+6Dh],0FFFFFF81h
0012FFEB jl 0012FFED
>
> Also, you really shouldn't be allocating C strings without a very good
> reason. This is 2005, and we now have classes like std::string and
> CString. :)
>
> --
> Be seeing you.
>
date: Thu, 20 Oct 2005 17:36:06 -0700
author: Andrew Garrett
Re: Creating a custom DirectShow renderer filter.
"Andrew Garrett" wrote:
> "Thore Karlsen [MVP DX]" wrote:
>
> > On Thu, 20 Oct 2005 15:55:02 -0700, "Andrew Garrett"
> > wrote:
> >
> > [...]
> >
> > > TCHAR *tszName;
> > >
> > > strcpy( (char*) tszName, "CNetworkSenderFilter" );
> >
> > Here you have two problems. First, you're copying to an uninitialized
> > string pointer. Second, if you're compiling for Unicode, the string will
> > be invalid. If you're never compiling for Unicode, you shouldn't be
> > using TCHAR.
> I'm never compiling for unicode, but the CBaseRenderer argument expects a
> TCHAR pointer, which I am providing it. Fixing up the NULL pointer issue
> gives me this error instead - "Unhandled exception at 0x0012ffe0 in Webcam
> Capture Test.exe: 0xC000001D: Illegal Instruction."
Okay, I've fixed this one up - it was some code I'd been testing out in the
constructor to try and fix my previous problem. I have (yet another) issue ,
"Unhandled exception at 0x10001e54 (DSNetworkSender.ax) in Webcam Capture
Test.exe: 0xC0000005: Access violation reading location 0xcc00890c.".
Stack Trace:
> DSNetworkSender.ax!_DllGetClassObject@12() + 0x14 C++
ole32.dll!7750206a()
ole32.dll!77520a03()
ole32.dll!7752071d()
ole32.dll!7752029f()
ole32.dll!77520143()
ole32.dll!775203f2()
ole32.dll!77520369()
ole32.dll!7752112b()
ole32.dll!775210e2()
ole32.dll!77520453()
ole32.dll!77520143()
ole32.dll!775200de()
ntdll.dll!7c90fb6c()
ntdll.dll!7c90fb71()
kernel32.dll!7c809392()
ole32.dll!7750055e()
ole32.dll!7750067b()
ole32.dll!7750078e()
ole32.dll!775009b5()
ole32.dll!775017f3()
ole32.dll!775008df()
ole32.dll!775008fa()
ole32.dll!7751e53b()
ole32.dll!7751f4a2()
ole32.dll!77520143()
ole32.dll!7751f4ed()
ole32.dll!7751ff88()
ntdll.dll!7c96d886()
ntdll.dll!7c96d886()
ntdll.dll!7c949d18()
ntdll.dll!7c91b686()
ntdll.dll!7c91056d()
advapi32.dll!77dde0ae()
advapi32.dll!77dde32e()
advapi32.dll!77dde343()
advapi32.dll!77dde350()
Code:
//Main.cpp
#include "DirectShow Network Sender.h"
;
CNetworkSenderFilter::CNetworkSenderFilter(TCHAR *tszName, LPUNKNOWN pUnk,
HRESULT *phr)
:CBaseRenderer( CLSID_NETWORKSENDERFILTER, tszName, pUnk, phr )
{
}
//Main.h
#pragma once
#include "stdafx.h"
//#define CLSID_NETWORKSENDERFILTER GUID_NULL
// GUID {6DBA0953-4108-4263-93D3-0C9241BD563E}
DEFINE_GUID( CLSID_NETWORKSENDERFILTER, 0x6dba0953, 0x4108, 0x4263, 0x93,
0xd3, 0xc, 0x92, 0x41, 0xbd, 0x56, 0x3e );
class CNetworkSenderFilter: public CBaseRenderer {
public:
DECLARE_IUNKNOWN;
char *pName;
IUnknown *r_pUnknown;
HRESULT NoHRESULT;
__stdcall CNetworkSenderFilter(IN TCHAR *tszName, IN LPUNKNOWN pUnk, OUT
HRESULT *phr);
__stdcall ~CNetworkSenderFilter( ) /*~CBaseRenderer()*/ {}
HRESULT CheckMediaType( const CMediaType *pmt );
HRESULT DoRenderSample( IMediaSample *pMediaSample );
SOCKET *sock;
static CUnknown *CreateInstance(IN LPUNKNOWN pUnk, OUT HRESULT *pHr);
//CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr);
}
//COM DLL Stuff.cpp
#include "stdafx.h"
#include "DirectShow Network Sender.h"
;
static WCHAR g_wszName[] = L"Epstone Network Sender Filter";
// Setup information
const AMOVIESETUP_MEDIATYPE sudPinTypes =
{
&MEDIATYPE_Video, // Major type
&MEDIASUBTYPE_NULL // Minor type
};
const AMOVIESETUP_PIN sudpPins[] =
{
{ L"Input", // Pins string name
FALSE, // Is it rendered
FALSE, // Is it an output
FALSE, // Are we allowed none
FALSE, // And allowed many
&CLSID_NULL, // Connects to filter
NULL, // Connects to pin
1, // Number of types
&sudPinTypes // Pin information
}
};
const AMOVIESETUP_FILTER sudSender =
{
&CLSID_NETWORKSENDERFILTER, // Filter CLSID
g_wszName, // String name
MERIT_DO_NOT_USE, // Filter merit
1, // Number of pins
sudpPins // Pin information
};
// List of class IDs and creator functions for the class factory. This
// provides the link between the OLE entry point in the DLL and an object
// being created. The class factory will call the static CreateInstance
CFactoryTemplate g_Templates[] = {
{ g_wszName
, &CLSID_NETWORKSENDERFILTER
, (LPFNNewCOMObject) CNetworkSenderFilter::CreateInstance
, NULL
, &sudSender }
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
CUnknown *CNetworkSenderFilter::CreateInstance(IN LPUNKNOWN pUnk, OUT
HRESULT *pHr)
{
char *message = new char[255];
char *hrstr = new char[20];
char *ptrstr = new char[20];
int pfsize;
char *szpfstr = new char[20];
char *pHrstr = new char[20];
char *pUnkstr = new char[20];
*pHr = S_OK;
CNetworkSenderFilter * pTheFilter;
TCHAR *tszName = new TCHAR[255];
strcpy( (char*) tszName, "CNetworkSenderFilter" );
pTheFilter = new CNetworkSenderFilter( tszName, pUnk, pHr );
if (pTheFilter== NULL)
{
*pHr = E_OUTOFMEMORY;
}
strcpy( message, "Creating CNetworkSenderFilter, hr=" );
itoa( *pHr, hrstr, 16 );
strcat( message, hrstr );
ltoa( (long) pTheFilter, ptrstr, 16 );
strcat( message, ", pFilter=" );
strcat( message, ptrstr );
pfsize = sizeof( *pTheFilter );
itoa( pfsize, szpfstr, 16 );
strcat( message, ", sizeof(*pTheFilter)=" );
strcat( message, szpfstr );
ltoa( (long) pHr, pHrstr, 16 );
strcat( message, ", *pHr=" );
strcat( message, pHrstr );
ltoa( (long) pUnk, pUnkstr, 16 );
strcat( message, ", *pUnk=" );
strcat( message, pUnkstr );
MessageBox( NULL, message, "", MB_OK | MB_ICONINFORMATION );
delete message;
delete hrstr;
delete ptrstr;
delete szpfstr;
delete pHrstr;
delete pUnkstr;
return pTheFilter;
}
STDAPI DllRegisterServer()
{
return AMovieDllRegisterServer2(TRUE);
}
STDAPI DllUnregisterServer()
{
return AMovieDllRegisterServer2(FALSE);
}
// If we declare the correct C runtime entrypoint and then forward it to the
DShow base
// classes we will be sure that both the C/C++ runtimes and the base classes
are initialized
// correctly
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
BOOL WINAPI DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved)
{
return DllEntryPoint(reinterpret_cast<HINSTANCE>(hDllHandle), dwReason,
lpReserved);
}
date: Thu, 20 Oct 2005 17:49:07 -0700
author: Andrew Garrett
Re: Creating a custom DirectShow renderer filter.
On Thu, 20 Oct 2005 17:36:06 -0700, "Andrew Garrett"
wrote:
>> > TCHAR *tszName;
>> >
>> > strcpy( (char*) tszName, "CNetworkSenderFilter" );
>> Here you have two problems. First, you're copying to an uninitialized
>> string pointer. Second, if you're compiling for Unicode, the string will
>> be invalid. If you're never compiling for Unicode, you shouldn't be
>> using TCHAR.
>I'm never compiling for unicode, but the CBaseRenderer argument expects a
>TCHAR pointer, which I am providing it.
That's not the way it works. TCHAR is a typedef for either char or
wchar_t, depending on whether you are compiling for Unicode or not.
Those are two completely different types, and you can't use strcpy() to
copy a char string to a wchar_t string. What's more, since you're not
compiling for Unicode anyway, you can just pass the string directly.
You are also not deleting your strings correctly. You have to delete
them with delete [], not plain delete. It's better not to allocate and
deallocate these strings at all.
Try rewriting your function like this:
CUnknown *CNetworkSenderFilter::CreateInstance(IN LPUNKNOWN pUnk, OUT
HRESULT *pHr)
{
*pHr = S_OK;
CNetworkSenderFilter *filter = new
CNetworkSenderFilter("CNetworkSenderFilter", pUnk, pHr);
if (!filter)
*pHr = E_OUTOFMEMORY;
return filter;
}
If you want to construct a temporary string for debug purposes, I
recommend either the CString class, std::string, std::stringstream, or
sprintf()/wsprintf() to a local char array.
--
Be seeing you.
date: Thu, 20 Oct 2005 19:59:55 -0500
author: Thore Karlsen [MVP DX]
Re: Creating a custom DirectShow renderer filter.
"Thore Karlsen [MVP DX]" wrote:
> On Thu, 20 Oct 2005 17:36:06 -0700, "Andrew Garrett"
> wrote:
>
> >> > TCHAR *tszName;
> >> >
> >> > strcpy( (char*) tszName, "CNetworkSenderFilter" );
>
> >> Here you have two problems. First, you're copying to an uninitialized
> >> string pointer. Second, if you're compiling for Unicode, the string will
> >> be invalid. If you're never compiling for Unicode, you shouldn't be
> >> using TCHAR.
>
> >I'm never compiling for unicode, but the CBaseRenderer argument expects a
> >TCHAR pointer, which I am providing it.
>
> That's not the way it works. TCHAR is a typedef for either char or
> wchar_t, depending on whether you are compiling for Unicode or not.
> Those are two completely different types, and you can't use strcpy() to
> copy a char string to a wchar_t string. What's more, since you're not
> compiling for Unicode anyway, you can just pass the string directly.
>
> You are also not deleting your strings correctly. You have to delete
> them with delete [], not plain delete. It's better not to allocate and
> deallocate these strings at all.
>
> Try rewriting your function like this:
>
> CUnknown *CNetworkSenderFilter::CreateInstance(IN LPUNKNOWN pUnk, OUT
> HRESULT *pHr)
> {
> *pHr = S_OK;
>
> CNetworkSenderFilter *filter = new
> CNetworkSenderFilter("CNetworkSenderFilter", pUnk, pHr);
>
> if (!filter)
> *pHr = E_OUTOFMEMORY;
>
> return filter;
> }
Copy-and-pasted this routine into my code, still no luck. The error again:
"Unhandled exception at 0x00000000 in Webcam Capture Test.exe: 0xC0000005:
Access violation reading location 0x00000000."
Stack Trace:
> DSNetworkSender.ax!CClassFactory::CreateInstance() + 0xa9 C++
ole32.dll!775202e3()
ole32.dll!77520143()
ole32.dll!775203f2()
ole32.dll!77520369()
ole32.dll!7752112b()
ole32.dll!775210e2()
ole32.dll!77520453()
ole32.dll!77520143()
ole32.dll!775200de()
ntdll.dll!7c90fb6c()
ntdll.dll!7c90fb71()
kernel32.dll!7c809392()
ole32.dll!7750055e()
ole32.dll!7750067b()
ole32.dll!7750078e()
ole32.dll!775009b5()
ole32.dll!775017f3()
ole32.dll!775008df()
ole32.dll!775008fa()
ole32.dll!7751e53b()
ole32.dll!7751f4a2()
ole32.dll!77520143()
ole32.dll!7751f4ed()
ole32.dll!7751ff88()
ntdll.dll!7c96d886()
ntdll.dll!7c96d886()
ntdll.dll!7c949d18()
ntdll.dll!7c91b686()
ntdll.dll!7c91056d()
advapi32.dll!77dde0ae()
advapi32.dll!77dde32e()
advapi32.dll!77dde343()
advapi32.dll!77dde350()
>
> If you want to construct a temporary string for debug purposes, I
> recommend either the CString class, std::string, std::stringstream, or
> sprintf()/wsprintf() to a local char array.
>
> --
> Be seeing you.
>
date: Thu, 20 Oct 2005 18:39:02 -0700
author: Andrew Garrett
Re: Creating a custom DirectShow renderer filter.
On Thu, 20 Oct 2005 18:39:02 -0700, "Andrew Garrett"
wrote:
[...]
>Copy-and-pasted this routine into my code, still no luck. The error again:
>"Unhandled exception at 0x00000000 in Webcam Capture Test.exe: 0xC0000005:
>Access violation reading location 0x00000000."
OK, try changing the signature of CNetworkSenderFilter::CreateInstance()
to this:
static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT
*pHr);
And remove the cast to LPFNNewCOMObject in g_Templates:
CFactoryTemplate g_Templates[] =
{
{
g_wszName,
&CLSID_NETWORKSENDERFILTER,
CNetworkSenderFilter::CreateInstance,
NULL,
&sudSender
}
};
You shouldn't do any casts without a very good reason, and it looks like
you cast here to silence the compiler when it warned you about using the
wrong calling convention.
--
Be seeing you.
date: Thu, 20 Oct 2005 21:33:30 -0500
author: Thore Karlsen [MVP DX]
Re: Creating a custom DirectShow renderer filter.
"Thore Karlsen [MVP DX]" wrote:
> On Thu, 20 Oct 2005 18:39:02 -0700, "Andrew Garrett"
> wrote:
>
> [...]
>
> >Copy-and-pasted this routine into my code, still no luck. The error again:
> >"Unhandled exception at 0x00000000 in Webcam Capture Test.exe: 0xC0000005:
> >Access violation reading location 0x00000000."
>
> OK, try changing the signature of CNetworkSenderFilter::CreateInstance()
> to this:
>
> static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT
> *pHr);
>
> And remove the cast to LPFNNewCOMObject in g_Templates:
>
> CFactoryTemplate g_Templates[] =
> {
> {
> g_wszName,
> &CLSID_NETWORKSENDERFILTER,
> CNetworkSenderFilter::CreateInstance,
> NULL,
> &sudSender
> }
> };
>
> You shouldn't do any casts without a very good reason, and it looks like
> you cast here to silence the compiler when it warned you about using the
> wrong calling convention.
That did the trick - i seemed to have forgotten the WINAPI bit. It tests
okay in GraphEdit now. Thanks a lot
>
> --
> Be seeing you.
>
date: Thu, 20 Oct 2005 20:53:03 -0700
author: Andrew Garrett
Re: Continued...
On Thu, 23 Feb 2006 13:35:28 -0800, Andrew Garrett wrote:
> That's how I thought it was done. However, I'm using Visual Studio 2005.
> From the looks of MSDN, I need to create an Interface Definition (IDL) file,
> and then compile it using a MIDL compiler and somehow import it into my
> Visual Studio 2005 project. Is this correct?
You can do it this way but I don't use MIDL so I can't give any expert
advice. See Geraint's GMFBridge same which, IIRC, does it this way. Or,
if you have VS2003 lying around, just create a project there and see what
it does. Or, for an SDK sample that has a custom interface to model from
look at ezrgb.
--
Please read this before replying:
1. Dshow & posting help: http://tmhare.mvps.org/help.htm
2. Trim & respond inline (please don't top post or snip everything)
3. Benefit others: follow up if you are helped or you found a solution
date: Thu, 23 Feb 2006 15:42:07 -0700
author: The March Hare [MVP]
Re: Continued...
"The March Hare [MVP]" wrote:
> On Thu, 23 Feb 2006 13:35:28 -0800, Andrew Garrett wrote:
>
> > That's how I thought it was done. However, I'm using Visual Studio 2005.
> > From the looks of MSDN, I need to create an Interface Definition (IDL) file,
> > and then compile it using a MIDL compiler and somehow import it into my
> > Visual Studio 2005 project. Is this correct?
>
> You can do it this way but I don't use MIDL so I can't give any expert
> advice. See Geraint's GMFBridge same which, IIRC, does it this way. Or,
> if you have VS2003 lying around, just create a project there and see what
> it does. Or, for an SDK sample that has a custom interface to model from
> look at ezrgb.
I've created the interface using MIDL, compiled it and imported the
necessary C files into my original DLL. I've also overridden
NonDelegatingQueryInterface like so:
STDMETHODIMP CNetworkSenderFilter::NonDelegatingQueryInterface(REFIID riid,
void **ppv)
{
bool IsIDSNetSender = Compare_IID( riid, IID_IDSNetSender );
if (IsIDSNetSender == true) {
printf("Querying for IDSNetSender interface\r\n");
} else {
printf("Querying for another interface\r\n");
}
if (IsIDSNetSender == true)
{
return GetInterface((IDSNetSender*)this, ppv);
}
// Default: Call parent class method.
// The CUnknown class must be in the inheritance chain.
return CBaseRenderer::NonDelegatingQueryInterface(riid, ppv);
}
bool Compare_IID(const IID firstguid, const IID secondguid) {
if ((firstguid.Data1) != (secondguid.Data1)) {return false;}
if ((firstguid.Data2) != (secondguid.Data2)) {return false;}
if ((firstguid.Data3) != (secondguid.Data3)) {return false;}
return true;
}
But when I instantiate the filter and try to get its interface, like so:
IBaseFilter *pSender = NULL;
IDSNetSender *pNSender = NULL;
CoCreateInstance( CLSID_NETWORKSENDERFILTER, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**) &pSender );
//Get the IDSNetSender Interface
hr = pSender->QueryInterface( IID_IDSNetSender, (void**) &pNSender );
printf("hr from getting IDSNetSender pointer: %li\r\n", hr);
hr = pNSender->SetSocket(NULL);
hr = pGraph->AddFilter( pSender, L"Network Sender Filter" );
pNSender is actually a NULL pointer, however I can still call ->SetSocket
and I get the correct address for the this pointer in my routine. It seems to
correctly set this->sock perfectly in that routine, however when it runs
DoRenderSample, this->sock acts as if it's never changed, and the this
pointer references a completely different location in memory. Well, I'm
flummoxed. Here are my DoRenderSample and SetSocket routines:
HRESULT CNetworkSenderFilter::DoRenderSample( IMediaSample *pMediaSample ) {
BYTE* data = NULL;
long length = 0;
pMediaSample->GetPointer( &data );
length = pMediaSample->GetSize();
send( sock, (char*) data, length, 0 );
return S_OK;
}
HRESULT CNetworkSenderFilter::SetSocket( SOCKET thesock ) {
this->sock = thesock;
return S_OK;
}
Thanks
--
Andrew Garrett
Epstone Networks
--
Andrew Garrett
Epstone Networks
date: Sun, 26 Feb 2006 03:50:26 -0800
author: Andrew Garrett
|
|