} catch (Exception exFile) {
MessageBox.Show("Не могу открыть " + exFile.ToString());
return;
}
// Создаем IrDA-клиент с установленным именем службы.
// которое должно совпадать с именем службы на другом
// IrDA-клиенте
try {
irClient = new IrDAClient(irServiceName);
} catch (SocketException exS) {
MessageBox.Show("Ошибка сокета: " + exS.Message +
" - Вы щелкнули на кнопке Получить на другом устройстве?");
return;
}
// Получим поток
Stream baseStream = irClient.GetStream();
// Получим размер отправляемого файла
// и запишем это значение в поток
byte[] length = BitConverter.GetBytes((int)fileStream.Length);
baseStream.Write(length, 0, length.Length);
// Создаем буфер для чтения файла
byte[] buffer = new byte[buffersize];
// Показываем число отправленных байт
int fileLength = (int)fileStream.Length;
statusBar1.Text = "Отправлено " + fileLength + " байт";
// Читаем файловый поток в базовом потоке
while (fileLength > 0) {
int numRead = fileStream.Read(buffer, 0, buffer.Length);
baseStream.Write(buffer, 0, numRead);
fileLength -= numRead;
}
fileStream.Close();
baseStream.Close();
irClient.Close();
statusBar1.Text = "Файл отправлен";
}
private void butReceive_Click(object sender, EventArgs e) {
// Создаем поток для записи файла
Stream writeStream;
try {
writeStream = new FileStream(fileReceive, FileMode.OpenOrCreate);
} catch (Exception) {
MessageBox.Show("Не могу открыть "+ fileReceive + " для записи");
return;
}
// Создаем соединение с помощью класса IrDAEndPoint
// для выбранного устройства из списка
// Начинаем прослушку входящих сообщений
// из устройства с объектом IrDAListener
try {
int i = listBox1.SelectedIndex;
irEndP = new IrDAEndPoint(irDevices[i].DeviceID, irServiceName);
irListen = new IrDAListener(irEndP);
irListen.Start();
} catch (SocketException exSoc) {
MessageBox.Show("Не могу прослушивать на службе " + irServiceName + ": " +
exSoc.ErrorCode);
}
// Показываем прослушивание выбранного устройства
statusBar1.Text = "Прослушка " + listBox1.SelectedItem.ToString();
// Создаем соединение
// для службы, обнаруженной прослушкой
IrDAClient irClient;
try {
irClient = irListen.AcceptIrDAClient();
} catch (SocketException exp) {
MessageBox.Show("Не могу принять сокет "+ exp.ErrorCode);
return;
}
// Показываем, идет ли передача файла
if (irListen.Pending() == true)
statusBar1.Text = "Передача из " + irClient.RemoteMachineName;
else
statusBar1.Text = "Нет передачи из " + irClient.RemoteMachineName;
// Получим поток из клиента
Stream baseStream = irClient.GetStream();
int numToRead;
// Создаем буфер для чтения файла
byte[] buffer = new byte[buffersize];
// Читаем поток данных, который содержит
// данные из передающего устройства
numToRead = 4;
while (numToRead > 0) {
int numRead = baseStream.Read(buffer, 0, numToRead);
numToRead -= numRead;
}
// Получим размер буфера для показа
// числа байт для записи в файл
numToRead = BitConverter.ToInt32(buffer, 0);
statusBar1.Text = "Записываем "+ numToRead + " байт";
// Записываем поток в файл до тех пор,
// пока не будут прочитаны все байты
while (numToRead > 0) {
int numRead = baseStream.Read(buffer, 0, buffer.Length);
numToRead -= numRead;
writeStream.Write(buffer, 0, numRead);
}
// Сообщаем, что файл получен
statusBar1.Text = "Файл получен";
baseStream.Close();
writeStream.Close();
irListen.Stop();
irClient.Close();
}
Итак, можно запустить приложение на двух устройствах и попробовать отправить и принять файл. Перед тестированием программы нужно создать текстовый документ send.txt с любым содержанием. Затем нужно повернуть друг к другу инфракрасные датчики двух устройств и на первом устройстве нажать кнопку Искать. Если поиск завершился успешно, то в списке отобразится имя второго устройства.
Затем на втором устройстве надо нажать кнопку Принять, а на первом устройстве нажать кнопку Отправить. В результате ваших действий текст сообщения из файла send.txt должен быть передан на другое устройство и сохранен в файле receive.txt.
К сожалению, данный пример нельзя тестировать на эмуляторе. Для проведения эксперимента вам необходимо иметь два настоящих устройства. Так как у меня нет второго КПК, я решил воспользоваться в качестве второго устройства своим смартфоном под управлением Windows Mobile 2005. Поскольку графический интерфейс программ для смартфонов не поддерживает кнопки, мне пришлось добавить в решение новый проект IrDA_Smartphone_CS и частично переписать код программы.
Вместо кнопок использовалось меню, а вместо элемента управления ListBox — элемент ComboBox. Но можно было обойтись и без создания текстовых файлов, а просто считывать данные из потока. В этом случае наша программа приобрела бы черты чата. Также можно написать какую-нибудь игру, в которой участвуют два игрока. С помощью инфракрасной связи вы можете передавать информацию, например, о сделанном ходе в шахматах.
Несмотря на свою дешевизну и простоту, инфракрасное соединение имеет несколько существенных недостатков. К ним относятся маленький радиус действия и возможность связи в пределах прямой видимости. Этих недостатков лишено Bluetooth-соединение.
Но и тут не обошлось без ложки дегтя в бочке меда. Во-первых, существует два различных подхода к реализации Bluetooth-соединений, которые не совместимы друг с другом. Во-вторых, пока не существует поддержки этой технологии в управляемом коде .NET Compact Framework. Примеры с Bluetooth-связью мы будем приводить для устройств под управлением Windows Mobile 5.0, так как они гарантированно используют одну и ту же реализацию Bluetooth-технологии. Так как библиотека .NET Compact Framework не имеет в своем составе классов, работающих с Bluetooth, то придется воспользоваться вызовами функций Windows API, как показано в листинге 12.6.
Листинг 12.6
public enum RadioMode {
Off = 0,
Connectable = 1,
Discoverable = 2
}
/// <summary>
/// Получает текущий статус bluetooth
/// </summary>
/// <param name="dwMode">флаги</param>
/// <returns></returns>
[DllImport("BthUtil.dll")]
public static extern int BthGetMode(out RadioMode dwMode);
/// <summary>
/// Устанавливает новый режим bluetooth
/// </summary>
/// <param name="dwMode">флаги для установки режима</param>
/// <returns></returns>
[DllImport("BthUtil.dll")]
public static extern int BthSetMode(RadioMode dwMode);
private void mnuOn_Click(object sender, EventArgs e) {
BthSetMode(RadioMode.Connectable);
lblStatus.Text = RadioMode.Connectable.ToString();
}
private void Form1_Load(object sender, EventArgs e) {
RadioMode mode;
int ret = BthGetMode(out mode);
lblStatus.Text = mode.ToString();
}
private void mnuOff_Click(object sender, EventArgs e) {
ВthSetMode(RadioMode.Off);
lblStatus.Text = RadioMode.Off.ToString();
}
В этом примере после запуска приложения текущий режим Bluetooth определяется при помощи функции BthGetMode, а с помощью команд меню пользователь может включать или выключать Bluetooth-соединение, используя функцию BthSetMode.
Несомненно, маленькие мобильные устройства, будь то смартфон или КПК, идеально подходят на роль коммуникационных устройств. В этой главе были приведены только самые простые примеры использования связи между устройствами. В последнее время набирают обороты такие виды связи, как Wi-Fi, GPS и GPRS. Кроме того, мобильные устройства имеют в своем составе браузеры для путешествия по Всемирной паутине. Таким образом, серьезному разработчику необходимо освоить весь спектр технологий, связанных с обменом данными между устройствами.
Глава 13
Использование неуправляемого кода
Несмотря на то что библиотека .NET Compact Framework имеет множество классов для выполнения самых разных задач, во многих случаях приходится прибегать к вызовам функций Windows API. А в некоторых случаях использование функций Windows API даже предпочтительнее, чем использование аналогичных методов управляемого кода, так как они позволяют оптимизировать и повысить производительность приложения.