Let's say first that our sample code works in a MultiThreadedApartment.
The main entry point creates the thread, setting it to
ApartmentState.MTA. Cleanup code is unnecesarry for our purpose.
public void Thread1()
{
string monikerID =
"@device:cm:{860BB310-5D01-11D0-BD3B-00A0C911CE86}\\Creative WebCam
Live! (VFW)";
ICaptureGraphBuilder2 captureBuilder;
IFilterGraph filterGraph;
int hr;
//set up main interfaces
captureBuilder = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
filterGraph = (IFilterGraph)new FilterGraph();
graphBuilder = (IGraphBuilder)filterGraph;
captureBuilder.SetFiltergraph(graphBuilder);
rotEntry = new DsROTEntry(filterGraph);
//get the source filter
IBaseFilter source = (IBaseFilter)Marshal.BindToMoniker(monikerID);
//first set of operations (add/remove)
hr=graphBuilder.AddFilter(source, "source");
DsError.ThrowExceptionForHR(hr);
hr = graphBuilder.RemoveFilter(source);
DsError.ThrowExceptionForHR(hr);
//second set of operations (add/remove)
hr = graphBuilder.AddFilter(source, "source");
DsError.ThrowExceptionForHR(hr);
//the following line fail to remove the filter,
// but returns no error code
hr = graphBuilder.RemoveFilter(source);
DsError.ThrowExceptionForHR(hr);
//third add operation
//this will fail with an error code informing
// the hardware is in use
hr = graphBuilder.AddFilter(source, "source");
DsError.ThrowExceptionForHR(hr);
}
This sample code works flawlessly under STA. Why does it work under STA
if it doesn't work under MTA? And besides, what's wrong with the code
anyway?
I have no idea why I encoutered this strange behaviour. I don't even
know who to blame.
Feel free to enlighten me :)
My modified code:
[MTAThread]
static void Main()
{
Application.Run(new Form1());
}
private void button1_Click(object sender, System.EventArgs e)
{
ICaptureGraphBuilder2 captureBuilder;
IFilterGraph filterGraph;
int hr;
DsDevice [] d =
DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
//set up main interfaces
captureBuilder = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
filterGraph = (IFilterGraph)new FilterGraph();
IGraphBuilder graphBuilder = (IGraphBuilder)filterGraph;
captureBuilder.SetFiltergraph(graphBuilder);
DsROTEntry rotEntry = new DsROTEntry(filterGraph);
//get the source filter
IBaseFilter source =
(IBaseFilter)Marshal.BindToMoniker(d[0].DevicePath);
//first set of operations (add/remove)
hr=graphBuilder.AddFilter(source, "source");
DsError.ThrowExceptionForHR(hr);
hr = graphBuilder.RemoveFilter(source);
DsError.ThrowExceptionForHR(hr);
//second set of operations (add/remove)
hr = graphBuilder.AddFilter(source, "source");
DsError.ThrowExceptionForHR(hr);
//the following line fail to remove the filter,
// but returns no error code
hr = graphBuilder.RemoveFilter(source);
DsError.ThrowExceptionForHR(hr);
//third add operation
//this will fail with an error code informing
// the hardware is in use
hr = graphBuilder.AddFilter(source, "source");
DsError.ThrowExceptionForHR(hr);
}
A few notes:
- You create captureBuilder, but you never use it. I'm assuming you do in
the code you extracted this from.
- I like to use DsDevice for working with devices (shown above). That lets
me use this for adding devices to the graph:
// Do the BindCtx, and use the actual device name in the graph.
IFilterGraph2 ifg2 = as IFilterGraph2;
hr = ifg2.AddSourceFilterForMoniker(d[0].Mon, null, d[0].Name, out source).
This is about that OleCreatePropertyFrame thing, isn't it?
And yes, you are right, it all started from that propertyframe thing
:)) I found out that tearing down the graph and reconstruct it didn't
work, and it all came down to the apartment model I used.
I just had to create a new very simple project from scratch to test
various scenarios that fail in my bigger project since I got my hands
on VfW devices. I got an unpleasant feeling it's all related to VfW
device drivers. And I have two devices with the same kind of problems
right in front of me :). But that's NO true explanation. The AmCap
sample in PSDK, in C++, modified to use MTA and these add/remove
operations, runs with no problems. Why?