LLENN
@LLENN

Бросается исключение при вызове метода Com объекта вместо результата выполнения?

Что бы было более понятно о чем идет речь, я описываю интерфейс DXGI, а точнее переношу функционал из данного API себе в проект, для некоторых манипуляций.

Описываю IDXGIObject:

[ComImport]
[Guid("aec22fb8-76f3-4639-9be0-28eb43a67a2e")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDXGIObject
{
    HResult SetPrivateData(ref Guid name, uint dataSize, IntPtr dataPtr);

    HResult SetPrivateDataInterface(ref Guid name, [MarshalAs(UnmanagedType.IUnknown)] object unknownInterfaceObject);

    HResult GetPrivateData(ref Guid name, out int dataSize, out IntPtr dataPtr);

    HResult GetParent(ref Guid rIId, out object pParent);
}


Далее наследую данный интерфейс, и определяю новый интерфейс IDXGIFactory:

[ComImport]
[Guid("7b7166ec-21c7-44ae-b21a-c9ae321ae369")]
public interface IDXGIFactory : IDXGIObject
{
    HResult EnumAdapters(uint numAdapter, [MarshalAs(UnmanagedType.IUnknown)] out object adapter);

    HResult MakeWindowAssociation(IntPtr windowHandle, uint flags);

    HResult GetWindowAssociation(out IntPtr outHandleWindow);

    HResult CreateSwapChain(IntPtr lpIUnknown, IntPtr ptr, out IntPtr outPtr);

    HResult CreateSoftwareAdapter(IntPtr moduleHandle, out IntPtr outPtr);
}


Так же имеется небольшой Manager класс, для инициализации интерфейса IDXGIFactory:

public static class Manager
{
    private static Guid _dxgiFactory1Guid =
        new Guid("7b7166ec-21c7-44ae-b21a-c9ae321ae369");

    public static HResult CreateDxgiFactory(out IDXGIFactory factory)
    {
        HResult result = (HResult)CreateDXGIFactory(ref _dxgiFactory1Guid, out object tmpObject);
        factory = tmpObject as IDXGIFactory;
        return result;
    }

    [DllImport("dxgi.dll")]
    private static extern long CreateDXGIFactory(ref Guid refIId,
        [MarshalAs(UnmanagedType.IUnknown)] out object factoryPtr);
}


Так, все хорошо вызвалось, получили объект IDXGIFactory、далее, пытаемся выполнить перечисление доступных адаптеров:

internal class Program
{
    private static void Main(string[] args)
    {
        HResult result = Manager.CreateDxgiFactory(out IDXGIFactory factory);

        if (result != HResult.Ok)
        {
            Marshal.ThrowExceptionForHR((int)result);
        }

        uint count = 0;
        
        try
        {
            while (factory.EnumAdapters(count, out _) != HResult.ErrNotFound)
            {
                count++;
            }
        }
        catch (COMException e)
        {
            Console.WriteLine(e);
        }

        IDXGIAdapter[] adapters = new IDXGIAdapter[count];
        for (uint i = 0; i < count; i++)
        {
            factory.EnumAdapters(i, out object adapter);
            adapters[i] = adapter as IDXGIAdapter;
        }

        foreach (IDXGIAdapter dxgiAdapter in adapters)
        {
            dxgiAdapter.GetDesc(out DxgiAdapterDesc dxgiAdapterDesc);
            Debug.WriteLine(
                $"IDXGIAdapter {dxgiAdapterDesc.Name} refs count = {Marshal.ReleaseComObject(dxgiAdapter)}",
                "INFO");
        }

        adapters = null;

        int refs = Marshal.ReleaseComObject(factory);
    }
}


Сам вызов метода EnumAdapters выполняется успешно、и возвращает IDXGIAdapter、но, как только перечеслитель становится больше чем доступно адаптеров、бросается исключение:

Объект не найден. При вызове IDXGIFactory::EnumAdaptes отсутствует адаптер с указанным порядковым номером. (Исключение из HRESULT: 0x887A0002)


Как и почему выкидывается исключение、ведь по сути сам программист должен обрабатывать такие ошибки。

Как избавиться от данных выбросов если они на самом деле не нужны?
  • Вопрос задан
  • 100 просмотров
Решения вопроса 1
LLENN
@LLENN Автор вопроса
Оказывается, COM Interop по умолчанию преобразует все неуспешные возвращенные HRESULT в исключения.

Стоит добавить атрибут [PreserveSig], чтобы это предотвратить:

[PreserveSig] int EnumAdapters(...);
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы