Консультация № 186412
25.06.2012, 07:53
97.26 руб.
0 1 0
Уважаемые эксперты! Пожалуйста, ответьте на вопрос:

Мне необходимо запросить список доступных разрешений со сканера. Использую библиотеку TwainDotNet, но там предусмотрена возможность запрашивать из Источника(устройства) только OneValue. Список доступных разрешений возвращается при помощи

Код:
[DllImport("twain_32.dll", EntryPoint = "#1")]
public static extern TwainResult DsCapability([In, Out] Identity origin, [In] Identity dest, DataGroup dg, DataArgumentType dat, Message msg, [In, Out] TwainCapability capa);


где origin - handle приложения,
dest - handle источника,
dg - константа DG_CONTROL,
dat - константа DAT_CAPABILITY,
msg - константа MSG_GET.

Но самое интересное здесь - структура capa.

Код:
    
[StructLayout(LayoutKind.Sequential, Pack = 2)]
public class TwainCapability : IDisposable
{
Capabilities _capabilities;
ContainerType _containerType;
IntPtr _handle;
object _value;

protected TwainCapability(Capabilities capabilities, ContainerType containerType, object value)
{
_capabilities = capabilities;
_containerType = containerType;
_value = value;
int size;
if (value == null) { size = 0;} else { size = Marshal.SizeOf(value); }
_handle = Kernel32Native.GlobalAlloc(GlobalAllocFlags.Handle, size);

IntPtr p = Kernel32Native.GlobalLock(_handle);

try
{
if (p.Equals(0)) { Marshal.StructureToPtr(value, p, false); };
}
finally
{
Kernel32Native.GlobalUnlock(_handle);
}
}

~TwainCapability()
{
Dispose(false);
}

public static TwainCapability DCCap(Capabilities capabilities, object value)
{
ContainerType containerType;
containerType = ContainerType.DontCare;
return new TwainCapability(capabilities, containerType, value);
}

public void Dispose()
{
Dispose(true);
}

protected virtual void Dispose(bool disposing)
{
if (_handle != IntPtr.Zero)
{
Kernel32Native.GlobalFree(_handle);
}
}

}



где в последнем поле после вызова функции должен оказаться объект со структурой, соответствующей второму полю _containerType, т.е. перечисление, массив или Range.

У меня получилось распознавать структуру, которая находится там таким примерно образом:

Код:

public SomeResult ReadBackSomeValue()
{
IntPtr p = Kernel32Native.GlobalLock(_handle);
SomeResult sr = new SomeResult();

try
{
CapabilityEnumValue eval = new CapabilityEnumValue();
Marshal.PtrToStructure(p, eval);
sr.contype = ContainerType.Enum;
sr.value = eval;
return sr;
}
catch
{
try
{
CapabilityRangeValue rval = new CapabilityRangeValue();
Marshal.PtrToStructure(p, rval);
sr.contype = ContainerType.Range;
sr.value = rval;
return sr;
}
catch
{
try
{
CapabilityArrayValue aval = new CapabilityArrayValue();
Marshal.PtrToStructure(p, aval);
sr.contype = ContainerType.Array;
sr.value = aval;
return sr;
}
catch
{
sr.contype = ContainerType.DontCare;
sr.value = null;
return sr;
}

}

}
finally
{
Kernel32Native.GlobalUnlock(_handle);
}
}


Но как-то это не тру, по моему... Простите если все путано, но может быть есть что-то в C# такое чтобы проверить какой структуры или типа объект лежит по определенному указателю?

Обсуждение

Неизвестный
27.06.2012, 02:01
общий
Это же внешний С АПИ, тут и С++ не особо проверит. Он тупо берет структуру из h-файла. Я вообще не очень понимаю взаимосвязь последней функции с предыдущим.


Capabilities _capabilities;
ContainerType _containerType;
IntPtr _handle;
object _value;

Если эта структура заполняется функцей АПИ, то _value должно быть указателем на нужный объект. Соответственно - свитч по _containerType, а потом приведение _value к нужному типу. Только не уверен, что такая конструкция может работать. Маршалер должен при этом сам знать, что за объект в _value. А он наверняка даже не знает его размеры. Скорее всего, там тоже должен стоять IntPtr, из которого позже можно данные взять.
Форма ответа