Глава.25 .Взаимодействие.с.компонентами.WinRT
Одно из преимуществ использования проекций потоков .NET Framework за-
ключается в том, что если метод используется более одного раза для
AsStreamXxx
для одного экземпляра потока WinRT, вам не придется беспокоиться о возможно-
сти создания нескольких разных буферов и о том, что данные, записанные в один
буфер, не будут видны в другом. Функции .NET Framework API следят за тем,
чтобы каждый объект потока использовал уникальный экземпляр адаптера, а все
пользователи работали с одним буфером.
И хотя в большинстве случаев стандартная буферизация обеспечивает хороший
компромисс между производительностью и затратами памяти, иногда требуется
изменить 16-килобайтный размер буфера, используемый по умолчанию. Методы
AsStreamXxx
предоставляют перегруженные версии с такой возможностью. На-
пример, если вы знаете, что будете работать с очень большим файлом в течение
длительного времени, а количество одновременно используемых других буфери-
зованных потоков будет небольшим, вы сможете обеспечить некоторый прирост
производительности, выделив для своего потока очень большой буфер. И наобо-
рот, в некоторых ситуациях с необходимостью минимальной задержки можно
потребовать, чтобы из сети читалось ровно столько байтов, сколько необходимо
приложению; тогда буферизацию можно вообще отключить. Если передать методу
AsStreamXxx
нулевой размер буфера, то объект буфера не создается.
Передача блоков данных между CLR и WinRT
Там, где это возможно, рекомендуется использовать проекции потоков из предыду-
щего раздела, потому что они обладают достаточно хорошими характеристиками
производительности. Однако некоторые ситуации требуют передачи между CLR
и компонентами WinRT физических блоков данных. Например, при использовании
компонентов файловых и сокетовых потоков WinRT необходимо выполнять чтение
и запись физических блоков данных. Кроме того, криптографические компоненты
WinRT выполняют шифрование и дешифрование блоков данных, а пикселы рас-
тровой графики также хранятся в виде физических блоков данных.
В .NET Framework блоки данных обычно передаются в виде массива байтов
(
Byte[]
) или в виде потока (например, при использовании класса
MemoryStream
).
Конечно, массивы байтов и объекты
MemoryStream
не могут передаваться компо-
нентам WinRT напрямую, поэтому WinRT определяет интерфейс
IBuffer
; объекты,
реализующие этот интерфейс, представляют физические блоки данных, которые
могут передаваться функциям WinRT API. Интерфейс WinRT
IBuffer
определя-
ется следующим образом:
namespace Windows.Storage.Streams {
public interface IBuffer {
UInt32 Capacity { get; } // Максимальный размер буфера (в байтах)
UInt32 Length { get; set; } // Количество используемых байтов
} // в буфере
}
713
Проекции.уровня. NET.Framework
Как видите, объект
IBuffer
имеет максимальный размер и текущую длину; как
ни странно, он не предоставляет средств для выполнения чтения или записи данных
в буфер. Это объясняется, прежде всего, тем, что типы WinRT не могут выражать
указатели в своих метаданных, потому что указатели плохо соответствуют пра-
вилам некоторых языков (например, JavaScript или безопасного кода C#). Таким
образом, объект
IBuffer
— всего лишь способ передачи адреса памяти между CLR
и WinRT API. Для обращения к байтам по адресу памяти используется внутрен-
ний интерфейс COM
IBufferByteAccess
. Обратите внимание: это интерфейс
COM (потому что он возвращает указатель), а не интерфейс WinRT. Группа .NET
Framework определила для этого интерфейса COM внутреннюю обертку RCW,
которая выглядит примерно так:
namespace System.Runtime.InteropServices.WindowsRuntime {
[Guid("905a0fef bc53 11df 8c49 001e4fc686da")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
internal interface IBufferByteAccess {
unsafe Byte* Buffer { get; }
}
}
Во внутренней реализации CLR может взять объект
IBuffer
, запросить его ин-
терфейс
IBufferByteAccess
, а затем обратиться к свойству
Buffer
для получения
небезопасного указателя на байты, содержащиеся в буфере. По этому указателю
к байтам можно обратиться напрямую.
Чтобы избавить разработчиков от написания небезопасного кода, работающего
с указателями, в FCL был включен класс
WindowsRuntimeBufferExtensions
. Он
определяет набор методов расширения, которые явно вызываются разработчи-
ками для передачи блоков данных между массивами байтов и потоками CLR и
объектами WinRT
IBuffer
. Для использования этих методов расширения следует
включить в исходный код директиву
using System.Runtime.InteropServices.
WindowsRuntime;
:
namespace System.Runtime.InteropServices.WindowsRuntime {
public static class WindowsRuntimeBufferExtensions {
public static IBuffer AsBuffer(this Byte[] source);
public static IBuffer AsBuffer(this Byte[] source, Int32 offset,
Int32 length);
public static IBuffer AsBuffer(this Byte[] source, Int32 offset,
Int32 length, Int32 capacity);
public static IBuffer GetWindowsRuntimeBuffer(this MemoryStream stream);
public static IBuffer GetWindowsRuntimeBuffer(this MemoryStream stream,
Int32 position, Int32 length);
}
}
Итак, если у вас имеется массив
Byte[]
и вы хотите передать его функции
WinRT, получающей
IBuffer
, просто вызовите
AsBuffer
для массива
Byte[]
.
714
Do'stlaringiz bilan baham: |