В данной публикации я продемонстрирую взаимодействие с COM объектом на языке C#. В примере будет использована OLE-компонента для взаимодействия с ТСД Cipher 8001L компании CitySoft. Думаю, всё то что описано можно использовать и для других COM-Объектов.
Для начала поясню в чём суть позднего связывания, и зачем это надо. Позднее связывание необходимо нам тогда, когда тип объекта заранее не известен и мы не можем напрямую обращаться к параметрам, методам и свойствам используемого объекта — вот для этого и используется позднее связывание.
Для вызова метода надо знать его название и список формальных параметров, которые он принимает. Для вызова используем метод
InvokeMember().
Вообще метод
InvokeMember() и имеет три модификации:
//Первая
public object InvokeMember(
string name, BindingFlags flags, Binder binder,
object target, object[] args);
//Вторая
public object InvokeMember(
string name, BindingFlags flags, Binder binder,
object target, object[] args, CultureInfo info);
//Третья
public abstract object InvokeMember(
string name, BindingFlags flags, Binder binder,
object target, object[] args, ParameterModifier[] modifiers,
CultureInfo info, string[] namedParameters);
Для наших целей понадобится только первая модификация.
public object InvokeMember(
string name, BindingFlags flags, Binder binder,
object target, object[] args);
Первый параметр это — строковое название метода (поля, свойства) того объекта, с которым устанавливается связь.
В названии не должно быть пробелов или лишних символов, ещё, этот параметр чувствителен к регистру.
Второй параметр принимает на вход флаги, характеризующие связывание. В нашем случае понадобятся только следующие флаги:
BindingFlags.InvokeMethod – найти метод, определить его точку входа, и выполнить, передав ему массив фактических параметров.
BindingFlags.GetProperty – получить значение свойства
BindingFlags.SetProperty – установить свойство.
Третий параметр –
binder – устанавливается в
null.
Четвертым параметром –
target – передается ссылка на объект, к методу которого нужно обратиться.
Пятый параметр –
args – это массив с параметрами, который принимает на вход вызываемый поздним связыванием метод или массив, который содержит один элемент – устанавливаемое значение свойства.
Метод
InvokeMember() возвращает результат выполнения метода или значение свойства.
На этом краткая часть с теорией завершена, перехожу к практическому программированию Cipher 80XX через библиотеку от CitySoft.
Пример загрузки файла в терминал сбора данных:
string appProgID = "CitySoftWarehouseDos.Cpt";
// Получаем ссылку на интерфейс
Type CptType = Type.GetTypeFromProgID(appProgID);
// Запускаем Объект CPT
object CPT = Activator.CreateInstance(CptType);
object[] args = new object[1];
object[] args1 = new object[1];
args1[0] = 2; //Номер COM порта.
//Устанавливаем свойство номера порта.
CPT.GetType().InvokeMember("Port", BindingFlags.SetProperty, null, CPT, args1);
object[] args2= new object[1];
args2[0] = 1; // Скорость 115200
CPT.GetType().InvokeMember("BaudRate", BindingFlags.SetProperty, null, CPT, args2);
object[] args3 = new object[1];
args3[0] = 0; //Тип соединения 0 - ИК-Подставка.
CPT.GetType().InvokeMember("ConnectionType", BindingFlags.SetProperty, null, CPT, args3);
CPT.GetType().InvokeMember("InitComm", BindingFlags.InvokeMethod, null, CPT, null);
object[] args4 = new object[1];
args4[0] = 0; //Кодировка 0 - Win-1251.
CPT.GetType().InvokeMember("CodePage", BindingFlags.SetProperty, null, CPT, args4);
object[] args5 = new object[1];
args5[0] = 44; //Разделитель 44 - это запятая.
CPT.GetType().InvokeMember("LookupDelimiter", BindingFlags.SetProperty, null, CPT, args5);
object[] args10 = new object[3];
args10[0] = "DB.txt";//Имя файла, можно указать путь целиком.
args10[1] = 0;
args10[2] = 1;
object err = CPT.GetType().InvokeMember("Write", BindingFlags.InvokeMethod, null, CPT, args10);
while (err.ToString() == "80")
{
err = CPT.GetType().InvokeMember("State", BindingFlags.GetProperty, null, CPT, null);
}
if (err.ToString() != "0")
{
MessageBox.Show("Ошибка №" + err.ToString());
}
else
{
MessageBox.Show("Загрузка успешно завершена!");
}
//Закрываем порт
CPT.GetType().InvokeMember("CloseComm", BindingFlags.InvokeMethod, null, CPT, null);
// Уничтожение объекта.
Marshal.ReleaseComObject(CPT);
// Вызываем сборщик мусора для очистки памяти
GC.GetTotalMemory(true);
Получение файла с устройства:
string appProgID = "CitySoftWarehouseDos.Cpt";
// Получаем ссылку на интерфейс
Type CptType = Type.GetTypeFromProgID(appProgID);
// Запускаем CPT
object CPT = Activator.CreateInstance(CptType);
object[] args = new object[1];
object[] args1 = new object[1];
args1[0] = 2;
CPT.GetType().InvokeMember("Port", BindingFlags.SetProperty, null, CPT, args1);
object[] args2 = new object[1];
args2[0] = 1;
CPT.GetType().InvokeMember("BaudRate", BindingFlags.SetProperty, null, CPT, args2);
object[] args3 = new object[1];
args3[0] = 0;
CPT.GetType().InvokeMember("ConnectionType", BindingFlags.SetProperty, null, CPT, args3);
CPT.GetType().InvokeMember("InitComm", BindingFlags.InvokeMethod, null, CPT, null);
object[] args4 = new object[1];
args4[0] = 0;
CPT.GetType().InvokeMember("CodePage", BindingFlags.SetProperty, null, CPT, args4);
object[] args5 = new object[1];
args5[0] = 44;
CPT.GetType().InvokeMember("LookupDelimiter", BindingFlags.SetProperty, null, CPT, args5);
object[] args10 = new object[5];
args10[0] = "file.txt"; //Имя файла.
args10[1] = 0; //Формат файла 0 - txt / 1 - DBF
args10[2] = 0; //Тип файла 0 - собранный файл / 1 - база
args10[3] = 1; //Номер файла 1..10 для собранных / 1..3 для данных
args10[4] = 1; //Флаг перезаписи - если 0 - существующий файл не будет перезаписан, 1 - наоборот.
//Читаем файл с терминала сбора данных
object err = CPT.GetType().InvokeMember("Read", BindingFlags.InvokeMethod, null, CPT, args10);
while (err.ToString() == "81")
{
err = CPT.GetType().InvokeMember("State", BindingFlags.GetProperty, null, CPT, null);
}
if (err.ToString() != "0")
{
MessageBox.Show("Ошибка №" + err.ToString());
}
else
{
//Если всё удалось удаляем данные из файла ТСД.
object[] args11 = new object[2];
args11[0] = 0; //Тип файла 0 - файл / 1 - база.
args11[1] = 1; //Номер файла
object err1 = CPT.GetType().InvokeMember("DeleteData", BindingFlags.InvokeMethod, null, CPT, args11);
if (err1.ToString() == "-1")
{
MessageBox.Show("Выгрузка произведена успешно, но файл собранных данных удалить не удалось!");
}
{
MessageBox.Show("Выгрузка успешно завершена!");
}
}
//Закрываем порт
CPT.GetType().InvokeMember("CloseComm", BindingFlags.InvokeMethod, null, CPT, null);
// Уничтожение объекта Excel.
Marshal.ReleaseComObject(CPT);
// Вызываем сборщик мусора для немедленной очистки памяти
GC.GetTotalMemory(true);
P.S. Для того чтобы всё заработало, необходимо иметь установленную OLE-компоненту от CitySoft которая поставляется на диске с ТСД.
P.P.S. Рабочий исходник примера:
CipherOLE_Test.rar
Если есть интерес, пишите в комментариях, могу разместить пример прямого взаимодействия с ТСД через компоненту, без файла. Такой метод работает медленнее но, как выяснилось на практике, несколько надёжнее.
Комментарии (0)
RSS свернуть / развернутьТолько зарегистрированные и авторизованные пользователи могут оставлять комментарии.