Узнать код ошибки при создании объекта DirectShow

Я не пойму логику цикла. Если кодеки мы создаём на нижнем уровне, а на верхнем ловим экскепшен, то как переходить?

foreach (Guid codec in codecs)
{
      try
      {
          //тут что?
      }
}

Соединять фильтры я умею. Я не пойму, что должно быть на верхнем уровне, а что на нижнем?
Cейчас у меня такой код (еще не допиленный):

        private int BuildGraph()
        {
            switch (GraphMode)
            {
                case GRAPH_MODE.GM_INTELLECTUAL:
                    CreateGraphBuilder(out graphBuilder);
                    CreateCaptureGraphBuilder2(out captureGraphBuilder2);
                    captureGraphBuilder2.SetFiltergraph(graphBuilder);
                    graphBuilder.AddSourceFilter(FileName, "source", out sourceFilter);
                     
                    //тут надо будет запустить цикл перебора кодеков, но этого пока не сделано.
                    //если все будут с ошибками, то просто возвращаем код последней ошибки.
                    int errorCode = CreateFilter(CLSID_LAV_VideoDecoder, out videoDecoder);
                    if (errorCode != 0)
                    {
                         //log
                        Clear();
                        return errorCode;
                    }
                    graphBuilder.AddFilter(videoDecoder, "video decoder");

                    errorCode = CreateFilter(CLSID_VideoMixingRenderer9, out videoRenderer);
                    if (errorCode != 0)
                    {
                         //log
                        Clear();
                        return errorCode;
                    }
                    graphBuilder.AddFilter(videoRenderer, "video renderer");

                     captureGraphBuilder2.RenderStream(null, MediaType.Video, sourceFilter, videoDecoder, videoRenderer);
                    if (errorCode != 0)
                    {
                        //log
                        Clear();
                        return errorCode;
                    }

                    CreateFilter(CLSID_LAV_AudioDecoder, out audioDecoder);
                    graphBuilder.AddFilter(audioDecoder, "audio decoder");
                    errorCode = CreateFilter(CLSID_DirectSoundAudioRenderer, out audioRenderer);                    
                    if (errorCode != 0)
                    {
                         //log
                        Clear();
                        return errorCode;
                    }
                    graphBuilder.AddFilter(audioRenderer, "audio renderer");

                    errorCode = captureGraphBuilder2.RenderStream(null, MediaType.Audio, sourceFilter, audioDecoder, audioRenderer);
                    if (errorCode != 0)
                    {
                        Clear();
                        return errorCode;
                    }
                    errorCode = CreateBasicVideo(graphBuilder, out basicVideo);
                    if (errorCode != 0)
                    {
                        Clear();
                        return errorCode;
                    }
                    CreateMediaPosition(graphBuilder, out mediaPosition);
                    CreateVideoWindow(graphBuilder, out videoWindow);
                    videoWindow.put_Owner(OutputWindow.Handle);
                    videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren | WindowStyle.ClipSiblings);
                    basicVideo.GetVideoSize(out _videoWidth, out _videoHeight);
                    OutputScreenRect = CenterRect(ResizeRect(new Rectangle(0, 0, _videoWidth, _videoHeight), OutputWindow.Size), OutputWindow.ClientRectangle);
                    videoWindow.SetWindowPosition(OutputScreenRect.X, OutputScreenRect.Y, OutputScreenRect.Width, OutputScreenRect.Height);
                    videoWindow.put_MessageDrain(OutputWindow.Handle);
                    videoWindow.put_Visible(OABool.True);

                    errorCode = CreateBasicAudio(graphBuilder, out basicAudio);
                    if (errorCode == 0)
                        basicAudio.put_Volume(GetDecibellsVolume(Volume));

                    errorCode = CreateMediaControl(graphBuilder, out mediaControl);
                    if (errorCode != 0)
                    {
                         //log
                        Clear();
                        return errorCode;
                    }
                    
                    _state = PLAYER_STATE.PS_STOPPED;
                    
                    
                    return errorCode;
            }
            return -1;
        }

Возможно, не профессионально. Зато всё предельно понятно и работает. Я не знаю, что и зачем тут можно вынести в try :man_shrugging: Просто можно создать отдельные методы для перебора кодеков видео и аудио.
Мне кажется, что перебор и соединение фильтров должны быть на одном и том же уровне :thinking:

Так тут нет перебора :thinking:

foreach (Guid codec in codecs)
{
    try
    {
        сделать_чтото(codec);
        return;
    }
    catch (Exception ex)
    {
        Log(...);
    }  
}

throw new Exception("Failed to find a suitable codec");

Там в комментарии написано, что он должен быть, но его пока нет. Я просто показал принцип, как я это вижу.

Если речь идёт об объектах типа IBaseFilter, то я примерно так и хотел сделать. Тут проблемы вообще нет. Проблема с объектами других типов. Они по-другому создаются.
Вы говорили, что

но как? Дженерики, вроде, только к классам применимы public class MyClass<T>.
например, как это

IGraphBuilder graphBuilder = (IGraphBuilder)new FilterGraph();

и это

ICaptureGraphBuilder2 captureGraphBuilder2 = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();

завернуть в дженерик, чтобы каждый раз не писать try catch?
или какой колбэк тут можно сделать?

Можно и с классом это сделать.
Но и к функциям тоже.

using System;

class A
{
	public A()
	{
		throw new Exception("BOOM");
	}
}

class B {}

public class Program
{
	static T Create<T>() where T : new()
	{
		try
		{
			return new T();
		}
		catch (Exception ex)
		{
			throw new Exception($"Failed to create {typeof(T).FullName}: {ex}");
		}
	}

	public static void Main(string[] args)
	{
		Console.WriteLine(Create<B>());
		Console.WriteLine(Create<A>());
	}
}

В колбеке делать что надо для создания и возвращать (либо дженерик, либо object и кастовать потом).

А как этим

заменить это

:thinking:
Мне надо что-то типа этого: public static int CreateObj(Interface type, out obj).
Чтобы передать тип нужного интерфейса, чтобы он создался и вернулся код ошибки.

callback это же, по сути, обработчик события объекта. Например, у SampleGrabberа есть callback. Но как callback можно использовать, если сам объект ещё даже не создан?
Всё, понял! :grinning: Мне надо было вот так вот:

        public static int CreateObj<T, T2>(out T2 obj) where T : new()
        {
            try
            {
                object o = new T();
                obj = (T2)o;
                return 0; 
            }
            catch (Exception ex)
            {
                obj = default(T2);
                return ex.HResult;
            }
        }

Спасибо!

Это просто любая функция передаваемая параметром.

Формулировка это одно, а на практике колбэки используются для обработки событий. Например, в библиотеке GLFW. Там чётко написано callbacks. Или это какие-то другие колбэки?

А здесь как такое применить? :thinking: Ведь нету же параметра для колбэка. Или оборачивать во что-то надо?

Для чего угодно используются.
В функциях сортировки например бывает для сравнения элементов.
В filter, map, reduce и аналогах (LINQ .Select и т.д. в .NET).

Так я ж говорю, если создание объекта сложное и разное (вызов разных функций, а не просто new), то

а сам колбэк-то что из себя представляет? Это метод какой-то или что?

Объект создает и возвращает.

То есть, что-то вроде этого?

Только эта часть. И вызвать в этом try.

И чем это будет отличаться от моего?

Так это нужно когда

То есть, создаём метод, в который передаём тип нужного объекта. И в зависимости от переданного типа, создаём и возвращаем объект этого типа? Так что ли?

Самому колбеку тип вряд ли нужен, он его и так знает потому что

То есть каждый колбек просто как-то создает свой тип.

Но колбэк же вручную надо писать? Или он уже где-то написан?
То есть, свой колбэк под каждый тип? Или имеется ввиду обёртки как CreateXXX()?

Вручную, кто ж еще знает как создавать эти объекты.

Ну и для простых случаев как выше просто new конечно можно сделать дженерик функцию и передавать ее как колбек (а можно и не делать, все равно одна строка типа () => new MyClass()).

Не пойму, как это должно выглядеть. Если невозможно написать универсальный метод, то почему просто не использовать обёртки?

Так это о том, чтобы не дублировать весь код обертки на каждый тип.