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

Переписываю свой старый видеоплеер. Использую библиотеку DirectShowLib. Знаю, что для этого есть более удобные библиотеки, но я использую именно эту.
Собственно, видео-файл удалось запустить с первой же попытки, а проблема вот в чём. В интернете нашел, что фильтр можно создать так:

        public static IBaseFilter CreateFilter(Guid guid)
        {
            Type type = Type.GetTypeFromCLSID(guid);
            return (IBaseFilter)Activator.CreateInstance(type);
        }

граф вот так:

                    graphBuilder = (IGraphBuilder)new FilterGraph();
                    captureGraphBuilder2 = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();

а потом вытаскиваем из графа нужные интерфейсы:

                        basicVideo = (IBasicVideo)graphBuilder;
                        if (basicVideo != null)
                        {
                            mediaPosition = (IMediaPosition)graphBuilder;
                            videoWindow = (IVideoWindow)graphBuilder;
                        ...........

А как узнать код ошибки, если какой-то объект создать не удалось? :thinking:
как здесь:

Ну так раз не через возврат кода ошибки, значит исключение )

Получается, надо всё через try делать? Это же неудобно.
Для фильтров можно так:

        public static int CreateFilter(Guid guid, out IBaseFilter filter)
        {
            filter = null;
            Type type = Type.GetTypeFromCLSID(guid);
            try
            {
                filter = (IBaseFilter)Activator.CreateInstance(type);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.HResult);
                return ex.HResult;
            }
            return 0;
        }

а если объекты разного типа и по-разному создаются


                    graphBuilder = (IGraphBuilder)new FilterGraph();
                    captureGraphBuilder2 = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();

                    basicVideo = (IBasicVideo)graphBuilder;
                    mediaPosition = (IMediaPosition)graphBuilder;
                    videoWindow = (IVideoWindow)graphBuilder;

Для каждого писать отдельный метод с try?

Так а код ошибки без исключений не у каждого проверять что ли?

Вообще-то так как раз удобнее

  • Можно просто ловить исключение на более верхнем уровне.
  • Не получится случайно забыть проверить и получить непонятную фигню дальше.

не понял

Ну если вам надо

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

Но тут вообще непонятно чего вы добились оберткой возвращающей код ошибки вместо исключения. Их же тоже потом проверять надо.

:arrow_down:

Я добиваюсь того, чтобы методы просто возвращали коды ошибок как в WinAPI. Ведь так логичнее, чем ловить исключение на верхнем уровне. Зачем мне исключение на верхнем уровне, если это приведёт к прекращению работы нижнего? :thinking: Или не приведёт?
Объясняю на примере плеера. Есть класс Player и код в главной форме:


            player = new Player();
            player.OutputWindow = panel1;
            player.FileName = @"D:\video.avi";
            try
            { 
                player.Play();
            }
            catch ().....

Если плеер не сможет загрузить какой-нибудь фильтр, то произойдёт ошибка и выкинет экскепшен, и финита ля комедия, верно?
А если, допустим, видео-дорожку он не сможет отрендерить, а аудио-дорожку сможет (или наоборот), тогда не будет экскепшена и воспроизведется что-то одно? Они же по отдельности рендерятся. Как try верхнего уровня узнает, что именно не отрендерилось - видео или аудио? :thinking:

Так а дальше что с ними делать?
Все равно ж надо тогда проверять каждый вызов, чтобы хотя бы в лог и т.п. записать.

Если видео не отрендерилось, то забиваем болт на видео и переходим к аудио (или наоборот). А если ловить экскепшен на верхнем уровне, то так уже не сделаешь (ведь метод рендеринга умрёт от любой ошибки), правильно я понял? :thinking:

Совсем забивать не стоит, надо хотя бы лог писать, иначе как потом понять в чем проблема.

А более верхний уровень же не один. Для аудио и видео можно сделать отдельные функции и ловить вокруг каждой из них.

Ну даже если отдельными, и что? :thinking: Ошибка же может в разных местах произойти (при загрузке каждого объекта). А как верхний уровень узнает, где именно она произошла?

void Play()
{
    try
    {
        initAudio();
    }
    catch (Exception ex)
    {
        Log("Failed to start audio: " + ex);
    }

    try
    {
        initVideo();
    }
    catch (Exception ex)
    {
        Log("Failed to start video: " + ex);
    }

    ...
}

А как узнать, на каком объекте произошла ошибка, чтобы вывести её код и имя объекта?
И как тогда перебрать по очереди все кодеки из заранее вбитого списка, если загрузка или подключение одного провалилась? :thinking:

Оно может быть в сообщении исключения. Или ex (ex.ToString()) выведет и стектрейс, из которого видно где это было.

Внутри цикла try catch

Но мне не нужен полный стектрейс в логе, а нужен лог вот такого вида:
Screenshot
Это легко делается без ловли экскепшена верхнем уровне. А с его ловлей я вообще не пойму, как вы предполагаете это сделать :man_shrugging:
Тут, конечно, не допилено. Но смысл не в этом.

Как? Если проверять результат и выводить, то точно так же можно ловить и кидать свое исключение.

    catch (Exception ex)
    {
        throw Exception("Failed to create XXX: " + ex.Message, ex);
    }

Если создавать методы-обертки, то это

можно решить одним методом либо с помощью дженериков, либо просто колбек принимать.

Но вообще я ж говорю, что и так может быть вся нужная инфа в ex.Message.

Еще можно например так

    catch (COMException ex)
    {
        Log($"Failed to start video: {ex.Message}, {ex.ErrorCode}");
    }
    catch (Exception ex)
    {
        Log($"Failed to start video: {ex.Message}");
    }

Бывает может сильно помочь )

Если вообще не кидать экскепшен на верхний уровень, а делать все проверки в методе построения Графа (и тут же писать лог). А на верхний уровень возвращать только общий код ошибки, типа успешно / не успешно (ну или какую-нибудь структуру). Единственная проблема, которую я вижу, это то что каждый создаваемый объект надо проверять через try catch.

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

А как это?

Я о том, что можно выводить разные свойства конкретных типов исключений.

Так а без исключений чем отличается?)
Точно так же if + log + return. С исключениями наоборот проще, перекинуть исключение (если надо добавить детали типа имени фильтра), в цикле обхода кодеков поймать и вывести.

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

Так логика та же что с исключениями, что без. Все равно ж надо завершать загрузку кодека при неудаче и переходить к следующему.

Исключения не влияют на количество нужных методов, но конечно обычно удобнее не делать один метод на 100500 строк с 10 уровнями вложений.