Модераторы: Akina

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как отловить приход данных на COM-порт? без применения контролов 
V
    Опции темы
JusTalionis
Дата 10.3.2008, 19:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 576
Регистрация: 11.7.2006

Репутация: 6
Всего: 17



COM-порт открыт при помощи оператора Open как файл.
Задача: получать с него периодически появляющиеся данные. 

Можно, конечно, непрерывно проверять его: пришли данные, или нет. Но это грубое решение. Хочется использовать событие от COM-порта. Можно ли это сделать без использования контрола?

PM MAIL   Вверх
Akina
Дата 10.3.2008, 21:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20570
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 34
Всего: 453



В указанных условиях - однозначно нет.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
Denjs
Дата 10.3.2008, 23:08 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 35
Регистрация: 3.3.2008

Репутация: нет
Всего: нет



я запускал в отдельном потоке именно циклическое чтение, предварительно настроив таймаут чтения. т.е. второй поток висит скажем 1 ms потом смотрит - не вывешен ли флаг завершитсья , складывает полученные полученные данные и снова в цикл чтения. Таймаут даже нафиг не нужен кроме того, что иначе процессор будет вешаться...

Не совсем красиво, но я почему-то не смог подсунуть ссылку на метод заданного объекта вместо указателя на функцию асинхронного вызова (или как там оно называется...)... потому пришлось извращатсья с потоками, ибо организовывать отдельную "висячую функцию" посреди набора объектов - это имхо сродни извращению...


PM MAIL   Вверх
JusTalionis
Дата 10.3.2008, 23:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 576
Регистрация: 11.7.2006

Репутация: 6
Всего: 17



Я понимаю, что извращение. Просто еще файл контрола тянуть с собой не хочется ужасно.
Думал, мож с API что-нить подходящее можно наворотить.

PM MAIL   Вверх
GorbunovDiman
Дата 13.3.2008, 08:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 89
Регистрация: 3.3.2008

Репутация: нет
Всего: нет



Люди а как вообще работать с COM портом? smile 
PM MAIL   Вверх
Akina
Дата 13.3.2008, 08:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20570
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 34
Всего: 453



Цитата(GorbunovDiman @  13.3.2008,  09:53 Найти цитируемый пост)
как вообще работать с COM портом

Берем описание драйвера IOPort и читаем до полного просветления


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
GorbunovDiman
Дата 13.3.2008, 14:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 89
Регистрация: 3.3.2008

Репутация: нет
Всего: нет



Цитата

Берем описание драйвера IOPort и читаем до полного просветления 

 smile 
А где его отрыть? smile  smile 
PM MAIL   Вверх
Akina
Дата 13.3.2008, 16:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20570
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 34
Всего: 453



Отбросить предубеждения и использовать поиск по Инету. Гугль дает нужную ссылку уже на первой странице.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
JusTalionis
Дата 13.3.2008, 20:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 576
Регистрация: 11.7.2006

Репутация: 6
Всего: 17



Цитата(Akina @  13.3.2008,  08:58 Найти цитируемый пост)
Берем описание драйвера IOPort 
 Акин, это ты перепутал машинныи порт c асинхронным, или я чо-то пропустил?


PM MAIL   Вверх
Akina
Дата 13.3.2008, 22:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20570
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 34
Всего: 453



А с СОМ-портом, пардон, с использованием IRQ, а не поллинга, ты как собираешься мимо портов ввода-вывода работать? использование IOPort просто избавляет от необходимости писАть собственный драйвер ядра.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
JusTalionis
Дата 13.3.2008, 22:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 576
Регистрация: 11.7.2006

Репутация: 6
Всего: 17



Это, в общем "нелегальный" путь. Например в XP обращение к железу не весьма приветствуется.
Как мне показалось, GorbunovDiman спрашивал про штатные бейсиковские способы работы с COM.

PM MAIL   Вверх
Akina
Дата 13.3.2008, 23:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20570
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 34
Всего: 453



Цитата(JusTalionis @  13.3.2008,  23:55 Найти цитируемый пост)
Это, в общем "нелегальный" путь. Например в XP обращение к железу не весьма приветствуется.

Гм... мне это утверждение кажется сомнительным.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
Denjs
Дата 13.3.2008, 23:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 35
Регистрация: 3.3.2008

Репутация: нет
Всего: нет



Цитата(Akina @ 13.3.2008,  08:58)
Цитата(GorbunovDiman @  13.3.2008,  09:53 Найти цитируемый пост)
как вообще работать с COM портом

Берем описание драйвера IOPort и читаем до полного просветления

да что вы все прицепились к этому ioPORTS?
мы народ плечистый - нам работать с контроллером напрямую - раз плюнуть.. да?

подыму в обсуждение тему работы с COM-портами через файлы.
в отношении QB не скажу что и как, но если заинтересует C++ исходник - что бы по аналогии разобраться - примеры есть и много. могу и свои исходники дать.

Цитата
Цитата(JusTalionis @  13.3.2008,  23:55 Найти цитируемый пост)
Это, в общем "нелегальный" путь. Например в XP обращение к железу не весьма приветствуется.
Гм... мне это утверждение кажется сомнительным.

а я не соглашусь.  "нелегальный" путь - это мягко сказано... это настоящее "варварство". Причем не приветствуется оно нигде. ни в windows ни в linux.
Непосредственно "железом" такого рода должны заниматься драйвера или система. 
и я молчу об относительной сложности работы с контроллером "напрямую" по сравнению с работой с файлами.




Это сообщение отредактировал(а) Denjs - 13.3.2008, 23:39
PM MAIL   Вверх
JusTalionis
Дата 13.3.2008, 23:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 576
Регистрация: 11.7.2006

Репутация: 6
Всего: 17



Akina
Не знаю именно про "IOPort", но что-то очень похожее я юзал, и в 98 всё было ОК, а под XP - фигушки smile 

Denjs
В VB даже по сравнению с QB по этой теме есть существенные различия, а про Си - вообще молчу.


Это сообщение отредактировал(а) JusTalionis - 13.3.2008, 23:32
PM MAIL   Вверх
Denjs
Дата 13.3.2008, 23:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 35
Регистрация: 3.3.2008

Репутация: нет
Всего: нет



Цитата(JusTalionis @ 13.3.2008,  23:28)
Denjs
В VB даже по сравнению с QB по этой теме есть существенные различия, а про Си - вообще молчу.

гм... а в VB что? *DCB структуру на что-то другое заменили?


Это сообщение отредактировал(а) Denjs - 13.3.2008, 23:46
PM MAIL   Вверх
JusTalionis
Дата 14.3.2008, 00:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 576
Регистрация: 11.7.2006

Репутация: 6
Всего: 17



Random действует не так, как в QB, а при открытии COM как файл, этот режим предпочтителен. (Не знаю почему, но так в мануалах утверждают.)


PM MAIL   Вверх
Akina
Дата 14.3.2008, 00:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20570
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 34
Всего: 453



Цитата(Denjs @  14.3.2008,  00:25 Найти цитируемый пост)
подыму в обсуждение тему работы с COM-портами через файлы.
в отношении QB не скажу что и как, но если заинтересует C++ исходник - что бы по аналогии разобраться - примеры есть и много. могу и свои исходники дать.

Через файлы - без поллинга?  smile Если можно, сюда хотя бы основы исходного кода. Желательно упростить и прокомментировать, чтобы и обезьяна поняла суть происходящего...


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
Denjs
Дата 14.3.2008, 02:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 35
Регистрация: 3.3.2008

Репутация: нет
Всего: нет



Цитата(Akina @ 14.3.2008,  00:34)
Цитата(Denjs @  14.3.2008,  00:25 Найти цитируемый пост)
подыму в обсуждение тему работы с COM-портами через файлы.
в отношении QB не скажу что и как, но если заинтересует C++ исходник - что бы по аналогии разобраться - примеры есть и много. могу и свои исходники дать.

Через файлы - без поллинга?  smile Если можно, сюда хотя бы основы исходного кода. Желательно упростить и прокомментировать, чтобы и обезьяна поняла суть происходящего...

поллингы? ааа.... поллитры?! smile))
да) в начале сложно, но это удобнее чем работать с контроллером напрямую - и не засоряем систему лишними драйверами... и удобнее пользователю - никаких доп драйверов для работы программы не нужно.


куски кода - для QT4 - потому не сильно пугайтесь увидев что незнакомое...
"выдрал" не чистив от комментариев, ссылок на функции других классов и др. ... думаю сути дела это не мешает....

открываем ..
DevPath_ - имя порта.
Код

        WCHAR buf[255];
        //qDebug() << "---> entering: " << "Open() " << DevPath_;
        buf[DevPath_.toWCharArray((wchar_t*)&buf)]=0;
    
        Serial_Handle = CreateFile(
                (const WCHAR*)&buf
                ,GENERIC_READ | GENERIC_WRITE  // Read-Write access
                ,0 // Cannot be shared ( else- FILE_SHARE_READ | FILE_SHARE_WRITE )
                ,NULL // Security Attributes
                ,OPEN_EXISTING // Open existing file
                ,FILE_ATTRIBUTE_NORMAL || FILE_FLAG_WRITE_THROUGH // | FILE_FLAG_NO_BUFFERING // Auto flush
                ,NULL // Template File
                );
        if ( Serial_Handle == INVALID_HANDLE_VALUE) 
             {
            GenerateError(-101,-1,"t_seriallink_otpd::open()::0448(win) :: ERROR: can`t open serial port."," it may be ACCESS_DENIED or device is busy ? ["+DevPath_+"]");
            //qDebug() << "ERROR: " << "CreateFile " << DevPath_ << " Error:" << GetLastError();
            //CloseComPort( void );
            return -1;
             };
        Serial_DCB.DCBlength= sizeof(DCB); 
                    //в первое поле структуры DCB необходимо занести её длину,
                    //она будет использоваться функциями настройки порта
                    //для контроля корректности структуры
    
        if( ! GetCommState( Serial_Handle, &Serial_DCB ))
            {
            //qDebug() << "ERROR: " << "GetCommState " << DevPath_  << " Error:" << GetLastError();
            GenerateError(-101,-2,"t_seriallink_otpd::open()::0462(win) :: ERROR: can`t get DCB struct for opened serial port."," is devicepath a simple file? but not a serial device ? ["+DevPath_+"]");
            //CloseComPort( void );
            return -2;
            };



самое геморройное - инициация DCB. Она переписывается по шаблону и правится в нужных местах.
Код

        DWORD _BaudRate = baud_rate_;
        DWORD _ByteSize  = word_length_;
        DWORD _StopBits  = (stop_bits_-1); /* StopBits = 0 => это 1 cтоп бит : для DCB это так */
        DWORD _Parity  = parity_; /* 0 1 2 - none odd  parity*/
        
        // Устанавливаем требуемые параметры 
        // скорость 
        Serial_DCB.BaudRate = _BaudRate; 
        // формат линии 
        Serial_DCB.ByteSize = _ByteSize; 
        Serial_DCB.Parity   = _Parity; 
        Serial_DCB.StopBits = _StopBits; 
        // прочее 
        Serial_DCB.fBinary =  TRUE;  // двоичный режим обмена
        Serial_DCB.fOutxCtsFlow = FALSE;      // CTS output flow control / режим слежения за сигналом CTS
        Serial_DCB.fOutxDsrFlow = FALSE;      // DSR output flow control / режим слежения за сигналом DSR
        Serial_DCB.fDtrControl  = DTR_CONTROL_DISABLE;      // DTR flow control type /использование линии DTR
        Serial_DCB.fDsrSensitivity = FALSE;  // DSR sensitivity / восприимчивость драйвера к состоянию линии DSR
        Serial_DCB.fTXContinueOnXoff = 1; // XOFF continues Tx 
        Serial_DCB.fOutX        = 0;      // XON/XOFF out flow control 
        Serial_DCB.fInX        = 0;      // XON/XOFF in flow control 
        Serial_DCB.fRtsControl  = RTS_CONTROL_DISABLE;      // RTS flow control / использование линии RTS
        Serial_DCB.fAbortOnError= FALSE;      // abort reads/writes on error   / остановка всех операций чтения/записи при ошибке
        Serial_DCB.fNull = FALSE;    //разрешить приём нулевых байтов
        
        if( ! SetCommState( Serial_Handle, &Serial_DCB ))
            {
            qDebug() << "t_seriallink_otpd::Setattr()::0681(win) :: ERROR: " << "SetCommState " << DevicePath  << " Error:" << GetLastError() << " \n";;
            GenerateError(-101,-4,"t_seriallink_otpd::Setattr()::0682(win) :: can`t do SetCommState "," SetCommState for ["+DevicePath+"] did not done.");
            //CloseComPort( void );
            return -1;
            };
        
        if( ! GetCommTimeouts( Serial_Handle, &Serial_Timeouts ) )
            {
            qDebug() << "t_seriallink_otpd::open()::0689(win) :: ERROR: " << "GetCommTimeouts " << "DevicePath=" << DevicePath  << " Error:" << GetLastError() << " \n";;
            GenerateError(-101,-5,"t_seriallink_otpd::Setattr()::0689(win) :: can`t do GetCommTimeouts "," GetCommTimeouts for ["+DevicePath+"] did not done.");
            //CloseComPort( void );
            return -1;
            };
        
        Serial_Timeouts.ReadIntervalTimeout = 0;        //таймаут между двумя символами
        Serial_Timeouts.ReadTotalTimeoutMultiplier = 1;    //общий таймаут операции чтения
        Serial_Timeouts.ReadTotalTimeoutConstant = 10;       //константа для общего таймаута операции чтения (10 ms - макс "100" циклов в сек.)
        Serial_Timeouts.WriteTotalTimeoutMultiplier = 0;    //общий таймаут операции записи
        Serial_Timeouts.WriteTotalTimeoutConstant = 0;      //константа для общего таймаута операции записи
        
        if( ! SetCommTimeouts( Serial_Handle, &Serial_Timeouts ) )
           {
            qDebug() << "t_seriallink_otpd::open()::0664(win) :: ERROR: " << "SetCommTimeouts " << " DevicePath=" << DevicePath  << " Error:" << GetLastError() << " \n";
            GenerateError(-101,-4,"t_seriallink_otpd::Setattr()::0689(win) :: can`t do SetCommTimeouts "," SetCommTimeouts for ["+DevicePath+"] did not done.");
            //CloseComPort( void );
            return -1;
           };
        // Выставляем DTR и RTS 
        EscapeCommFunction(Serial_Handle, SETDTR); 
        EscapeCommFunction(Serial_Handle, SETRTS); 
        SetupComm(Serial_Handle,2000,2000);      //установить размеры очередей приёма и передачи
        PurgeComm(Serial_Handle, PURGE_RXCLEAR);  //очистить принимающий буфер порта

таймауты настроены так: - операция чтения не может длится более 100 ms.

читаем
Код

        if( ! ReadFile(
            Serial_Handle
            ,buff
            , 1 // Buffer Length // пока читаем по одному байту...
            , &bytesread
            , NULL
            )
          )
             {
                qDebug() << "ERROR: " << "ReadFile \n" ;
                //((t_seriallink_otpd*)parent())->GenerateError(-101,-8,"t_seriallink_otpd::t_AsincSimFileReader::read():0136: Error while reading port"," unknown error ");
                breakit=true;
             };

Из read вываливаемся через 100 ms (?) или раньше - если пришли данные.
Я предпочитаю крутить это в цикле в отдельном потоке и "складывать" эти данные в основной поток.
Как уже говорил - это все содержимое единого класса и мне не хотелось делать "висячие функции" вне какого-либо класса для реализации "асинхронного режима".. а так - полная эмуляция асинхронности )) за счет 2-х потоков...


пишем
Код

        unsigned long io_i=0; //число реально записанных байт?
        if( ! WriteFile(
            Serial_Handle
            , data_.data()
            , bytes_ // nomber of bytes to write
            , &io_i
            , NULL
            ) /*data_.data() - может дать ошибку? проверить!*/
           )
           { 
            qDebug() << "ERROR: " << "WriteFile \n";
            GenerateError(-101,-6,"t_seriallink_otpd::Write():0793: Error while writing data."," unknown error ");
            return -1;
           };
        return io_i;


Закрываем:
Код

        if( ! CloseHandle( Serial_Handle ))
         {
            qDebug() << "ERROR: " << " CloseFile \n" ;
            GenerateError(-101,-7,"t_seriallink_otpd::Close():0935: Error while Closing port"," unknown error ");
            return -1;
        };

полный исходник тут: otpdlinks.berlios.de
там - же и сопоставление оных режимов в линуксе в обертке единого кроссплатформенного класса...
не сочтите за рекламу а будете бить - не бейте сильно )))
Буду рад услышать замечания и кАменты. 

Думаю что данные куски без особого труда копируются и переводятся/переписываются по образцу в тот язык который вам надо... думаю отражения одних и тех-же функций win-библиотек есть во всех языках...

кстати обезьяны не работают с компортами...незачем им понимать метафизическую сущность serial-device ^_^

Это сообщение отредактировал(а) Denjs - 14.3.2008, 03:12
PM MAIL   Вверх
Akina
Дата 14.3.2008, 08:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20570
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 34
Всего: 453



ТО есть все-таки именно поллинг. С определенным интервалом спрашиваем, а не пришло ли там чего... 

При работе же на уровне железа поллинг не нужен - приход каждого байта генерирует аппаратное прерывание, и его обработчик занимается приемом данных и помещением их в очередь. Он же может при достижении определенного содержимого стартовать процедуры обработки принятых данных.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
Denjs
Дата 14.3.2008, 12:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 35
Регистрация: 3.3.2008

Репутация: нет
Всего: нет



Цитата

При работе же на уровне железа поллинг не нужен - приход каждого байта генерирует аппаратное прерывание, и его обработчик занимается приемом данных и помещением их в очередь. Он же может при достижении определенного содержимого стартовать процедуры обработки принятых данных.
 ... обработчик, который мы должны реализовывать сами. ...

кстати - не совсем "спрашиваем с определнным интервалом"... скорее "возобновляем ожидание" поступления данных с определенным интервалом.
обратились в read - и повисли на 100 ms или пока не придут данные. вывалились? ничего не пришло? не надо завершаться?(смотрим флаги) - и снова в ожидание чтения.
а при поступлении данных - read() завершается сразу - не дожидаясь пока истечет таймаут. т.е. событие отлавливается практически немедленно.


____________
просмотрел ещё раз описание DCB... гы... )
господа - под линукс рабоать с компортом удобнее - там в стандартный драйвер можно подсунуть указатель на асинхронный обработчик событий от порта.... Циклическая обработка, (или "поллинг"?), во втором потоке появилась только из-за того, что но у меня "не вышло" подсунуть указатель на метод класса, как на обработчик события поступления данных - данные структуры ориентированы на функциональный стиль программирования и это не совсем удобно... 

почему-то искренне считал что DCB практически полностью эквивалентен структуре termios...  и в него можно подсунуть указатель на обработчик события поступления данных который будет вызываться при появлении новых данных на входе...
виноват, ошибся...  тут надо только 2 потока и waitForCommEvent() как я пониаю... ?
под виндоус все-таки убого )) 

извиняюсь...
Akina, ваша правда судя по всему )
но работать с ioPorts - ещё большее извращение ))



Это сообщение отредактировал(а) Denjs - 14.3.2008, 13:17
PM MAIL   Вверх
GorbunovDiman
Дата 17.3.2008, 18:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 89
Регистрация: 3.3.2008

Репутация: нет
Всего: нет



А теперь это всё на С переведите мне на ВБ smile 

Это сообщение отредактировал(а) Akina - 17.3.2008, 21:14
PM MAIL   Вверх
Akina
Дата 17.3.2008, 21:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20570
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 34
Всего: 453




M
Akina
GorbunovDiman, не надо злоупотреблять смайлами.



--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
JusTalionis
Дата 18.3.2008, 21:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 576
Регистрация: 11.7.2006

Репутация: 6
Всего: 17



Цитата(GorbunovDiman @  17.3.2008,  18:54 Найти цитируемый пост)
А теперь это всё на С переведите мне на ВБ  smile  

Поддерживаю!


PM MAIL   Вверх
GorbunovDiman
Дата 21.3.2008, 19:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 89
Регистрация: 3.3.2008

Репутация: нет
Всего: нет



Цитата

M
Akina GorbunovDiman, не надо злоупотреблять смайлами. 

Ладно , понял.

Добавлено через 4 минуты и 12 секунд
Кстати правда кто небудь переведите
PM MAIL   Вверх
Denjs
Дата 3.4.2008, 23:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 35
Регистрация: 3.3.2008

Репутация: нет
Всего: нет



Цитата(GorbunovDiman @ 21.3.2008,  19:22)
Добавлено @ 19:27
Кстати правда кто небудь переведите

ЗкоГаденеГ? &_$
PM MAIL   Вверх
JusTalionis
Дата 11.4.2008, 19:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 576
Регистрация: 11.7.2006

Репутация: 6
Всего: 17



Цитата(Denjs @  3.4.2008,  23:46 Найти цитируемый пост)
ЗкоГаденеГ? &_$
 Экий ты меркантильный. Не вздумай у мя чо-нить спросить - тоже тугрики потребую. smile С тебя конкретно.

А остальным - даю пример работы с COM через API. Скачано в Интернете, но где именно - не знаю. Автору, бесплатно подарвшему его всем - огромный респект!

frmSerial -форма: 
Код
Private Sub BTNCloseCom_Click()
    TMRComm.Enabled = False
    Call fin_com
    SwitchTags
End Sub

Private Sub BTNOpenCom_Click()
    If Not Init_Com(txt(0).Text, txt(1).Text) Then
        MsgBox txt(0).Text & " Not available!"
        Exit Sub
    End If
    SwitchTags
    TMRComm.Enabled = True
End Sub

Private Sub BTNSend_Click()
    If WriteCOM32(txt(2)) <> Len(txt(2)) Then
        MsgBox "Error writing to comm's"
        Exit Sub
    End If
    txtRec.Text = ""
    Pic.FillColor = &HFF0000
End Sub

Private Sub Frame2_DragDrop(Source As Control, X As Single, Y As Single)

End Sub

Private Sub TMRComm_Timer()
    Dim Ans As String, i As Integer, RtnStr As String
    Ans = ReadCommPure()
    If Pic.FillColor = &HFFFFFF Then
        Pic.FillColor = &H808080
       Else
        Pic.FillColor = &HFFFFFF
    End If
    If Ans = "" Then Exit Sub
    Pic.FillColor = &HFF
    For i = 1 To Len(Ans)
        RtnStr = RtnStr & Hex(Asc(Mid$(Ans, i, 1))) & " "
    Next
    RtnStr = RtnStr & vbCrLf & vbCrLf & CleanStr(Ans)
    txtRec.Text = RtnStr
    FlushComm
End Sub

Function CleanStr(TextLine As String) As String
    Dim i As Integer, RtnStr As String
    RtnStr = ""
    For i = 1 To Len(TextLine)
        Select Case Asc(Mid$(TextLine, i, 1))
            Case &H5D
                RtnStr = RtnStr & "<ACK>"
            Case &H5B
                RtnStr = RtnStr & "<NAK>"
            Case Is >= &H30
                RtnStr = RtnStr & Mid$(TextLine, i, 1)
            Case 13
                RtnStr = RtnStr & "<CR>"
            Case 10
                RtnStr = RtnStr & "<LF>"
            Case Else
                RtnStr = RtnStr & "@"
        End Select
    Next i
    CleanStr = RtnStr
End Function

Sub SwitchTags()
    Dim xs As Control
    For Each xs In Me
        If xs.Tag <> "" Then
            xs.Enabled = Not xs.Enabled
        End If
    Next
End Sub


SerialPort -модуль: 
Код
Option Explicit

Global ComNum As Long
Global bRead(255) As Byte

Type COMSTAT
        fCtsHold As Long
        fDsrHold As Long
        fRlsdHold As Long
        fXoffHold As Long
        fXoffSent As Long
        fEof As Long
        fTxim As Long
        fReserved As Long
        cbInQue As Long
        cbOutQue As Long
End Type

Type COMMTIMEOUTS
        ReadIntervalTimeout As Long
        ReadTotalTimeoutMultiplier As Long
        ReadTotalTimeoutConstant As Long
        WriteTotalTimeoutMultiplier As Long
        WriteTotalTimeoutConstant As Long
End Type

Type DCB
        DCBlength As Long
        BaudRate As Long
        fBinary As Long
        fParity As Long
        fOutxCtsFlow As Long
        fOutxDsrFlow As Long
        fDtrControl As Long
        fDsrSensitivity As Long
        fTXContinueOnXoff As Long
        fOutX As Long
        fInX As Long
        fErrorChar As Long
        fNull As Long
        fRtsControl As Long
        fAbortOnError As Long
        fDummy2 As Long
        wReserved As Integer
        XonLim As Integer
        XoffLim As Integer
        ByteSize As Byte
        Parity As Byte
        StopBits As Byte
        XonChar As Byte
        XoffChar As Byte
        ErrorChar As Byte
        EofChar As Byte
        EvtChar As Byte
End Type

Type OVERLAPPED
        Internal As Long
        InternalHigh As Long
        offset As Long
        OffsetHigh As Long
        hEvent As Long
End Type
Type SECURITY_ATTRIBUTES
        nLength As Long
        lpSecurityDescriptor As Long
        bInheritHandle As Long
End Type

Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Declare Function GetLastError Lib "kernel32" () As Long
Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Long) As Long
Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As Long) As Long
Declare Function SetCommTimeouts Lib "kernel32" (ByVal hFile As Long, lpCommTimeouts As COMMTIMEOUTS) As Long
Declare Function GetCommTimeouts Lib "kernel32" (ByVal hFile As Long, lpCommTimeouts As COMMTIMEOUTS) As Long
Declare Function BuildCommDCB Lib "kernel32" Alias "BuildCommDCBA" (ByVal lpDef As String, lpDCB As DCB) As Long
Declare Function SetCommState Lib "kernel32" (ByVal hCommDev As Long, lpDCB As DCB) As Long
Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Declare Function FlushFileBuffers Lib "kernel32" (ByVal hFile As Long) As Long


Function fin_com()
    fin_com = CloseHandle(ComNum)
End Function

Function FlushComm()
    FlushFileBuffers (ComNum)
End Function

Function Init_Com(ComNumber As String, Comsettings As String) As Boolean
On Error GoTo handelinitcom
    Dim ComSetup As DCB, Answer, Stat As COMSTAT, RetBytes As Long
    Dim retval As Long
    Dim CtimeOut As COMMTIMEOUTS, BarDCB As DCB
    ' Open the communications port for read/write (&HC0000000).
    ' Must specify existing file (3).
    ComNum = CreateFile(ComNumber, &HC0000000, 0, 0&, &H3, 0, 0)
    If ComNum = -1 Then
        MsgBox "Com Port " & ComNumber & " not available. Use Serial settings (on the main menu) to setup your ports.", 48
        Init_Com = False
        Exit Function
    End If
    'Setup Time Outs for com port
    CtimeOut.ReadIntervalTimeout = 20
    CtimeOut.ReadTotalTimeoutConstant = 1
    CtimeOut.ReadTotalTimeoutMultiplier = 1
    CtimeOut.WriteTotalTimeoutConstant = 10
    CtimeOut.WriteTotalTimeoutMultiplier = 1
    retval = SetCommTimeouts(ComNum, CtimeOut)
    If retval = -1 Then
        retval = GetLastError()
        MsgBox "Unable to set timeouts for port " & ComNumber & " Error: " & retval
        retval = CloseHandle(ComNum)
        Init_Com = False
        Exit Function
    End If
    retval = BuildCommDCB(Comsettings, BarDCB)
    If retval = -1 Then
        retval = GetLastError()
        MsgBox "Unable to build Comm DCB " & Comsettings & " Error: " & retval
        retval = CloseHandle(ComNum)
        Init_Com = False
        Exit Function
    End If
    retval = SetCommState(ComNum, BarDCB)
    If retval = -1 Then
        retval = GetLastError()
        MsgBox "Unable to set Comm DCB " & Comsettings & " Error: " & retval
        retval = CloseHandle(ComNum)
        Init_Com = False
        Exit Function
    End If
    
    Init_Com = True
handelinitcom:
    Exit Function
End Function

Function ReadCommPure() As String
On Error GoTo handelpurecom
    Dim RetBytes As Long, i As Integer, ReadStr As String, retval As Long
    Dim CheckTotal As Integer, CheckDigitLC As Integer
    retval = ReadFile(ComNum, bRead(0), 255, RetBytes, 0)
    ReadStr = ""
    If (RetBytes > 0) Then
        For i = 0 To RetBytes - 1
            ReadStr = ReadStr & Chr(bRead(i))
        Next i
       Else
        FlushComm
    End If
    'Return the string read from serial port
    ReadCommPure = ReadStr
handelpurecom:
    Exit Function
End Function

Function WriteCOM32(COMString As String) As Integer
On Error GoTo handelwritelpt
    Dim RetBytes As Long, LenVal As Long
    Dim retval As Long
    
    If Len(COMString) > 255 Then
        WriteCOM32 Left$(COMString, 255)
        WriteCOM32 Right$(COMString, Len(COMString) - 255)
        Exit Function
    End If
    
    For LenVal = 0 To Len(COMString) - 1
        bRead(LenVal) = Asc(Mid$(COMString, LenVal + 1, 1))
    Next LenVal
'    bRead(LenVal) = 0
    retval = WriteFile(ComNum, bRead(0), Len(COMString), RetBytes, 0)
'    FlushComm
    WriteCOM32 = RetBytes
    
handelwritelpt:
    Exit Function
End Function


Собственно, это и есть запрошенный "перевод".

Полный проект находится ниже в приаттаченном зипе.


Присоединённый файл ( Кол-во скачиваний: 42 )
Присоединённый файл  vb_serial_comms.zip 3,68 Kb
PM MAIL   Вверх
cardinal
Дата 13.4.2008, 01:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Инженер
****


Профиль
Группа: Экс. модератор
Сообщений: 6003
Регистрация: 26.3.2002
Где: Германия

Репутация: 19
Всего: 99



JusTalionis, чиркани пару слов пожалуйста на эту тему, я думаю это стоит того, чтобы поместить в FAQ.


--------------------
Немецкая оппозиция потребовала упростить натурализацию иммигрантов
В моем блоге: Разные истории из жизни в Германии

"Познание бесконечности требует бесконечного времени, а потому работай не работай - все едино".  А. и Б. Стругацкие
PM   Вверх
JusTalionis
Дата 13.4.2008, 02:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 576
Регистрация: 11.7.2006

Репутация: 6
Всего: 17



Черкану обязательно; обещаю. Но только после того, как добью эту проблему до победного. (С вашей объединенной помощью smile )
PM MAIL   Вверх
cardinal
Дата 13.4.2008, 02:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Инженер
****


Профиль
Группа: Экс. модератор
Сообщений: 6003
Регистрация: 26.3.2002
Где: Германия

Репутация: 19
Всего: 99



Спасибо!


--------------------
Немецкая оппозиция потребовала упростить натурализацию иммигрантов
В моем блоге: Разные истории из жизни в Германии

"Познание бесконечности требует бесконечного времени, а потому работай не работай - все едино".  А. и Б. Стругацкие
PM   Вверх
GorbunovDiman
Дата 30.4.2008, 06:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 89
Регистрация: 3.3.2008

Репутация: нет
Всего: нет



 Огромное спасибо
PM MAIL   Вверх
JusTalionis
Дата 20.5.2008, 14:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 576
Регистрация: 11.7.2006

Репутация: 6
Всего: 17



Во исполнение моего обещания, здесь данного cardinalу, рассказываю, как я все-таки добил задачу, и выкладываю готовый проект.

Я испробовал много вариантов. Во-первых, должен отметить, что использование контрола в данном случае дает настолько большие облегчения в работе, что я попытался временно отказаться от своего принципа не применять контролы. И тут же налетел на другую проблему: на моей машине все работало легко и просто, но принес экзешник на работу - и на той машине сразу вылетело сообщение, что в системе установлен неподходящий контрол,- и точка. Я писал об этом в соседней темке. Попробовал переименовать файл контрола; пробовал даже сменить внутри контрола все имена - не вышло, все равно запускался либо тот, что в системе, либо на новый надо было перерегистрировать. Пришлось на этот путь конкретно забить. Контролы - неплохая в основе идея, но Микрософт сделали всё от них зависящее, чтоб пользоваться ими было невозможно.

Вторым вариантом было проверить "смешанную" работу бейсика и API. Я попытался открыть порт обычным бейсиковским Open, а настроить его скорости и проч.- функцией API (потому что в VB6 у Open теперь нет параметров настройки порта). Но функция настройки требует хэндл порта, а как его получить?.. Я пробовал использовать описатель файла, возвращаемый Open (#1, #2,... то есть). Не сработало. Ничего не зависало, но порт не настраивался все равно.

Остается только полностью использовать API, что я всем и рекомендую.
Работа API разбиралась на основе найденного мною примера, который был мной выложен выше. С удивлением я обнаружил, что тот проект прекрасно работает с on-board портом, но отказывается писать/читать эмулированный под XP порт, являющийся шнуром USB-COM. Выяснилось, что автором примера допущена ошибка в объявлении функций ReadFile и WriteFile: последний параметр этих функций lpOverlapped должен быть типа OVERLAPPED, а автор присвоил ему Long. Видимо, посмотрел- что вроде всё работает, и выкинул "излишнюю" структуру. Вот вред "отсебятины". Кроме того, в том примере неправильно описан тип DCB, но это не приводит к ошибкам, если не пытаться писать в поля "в ручную". Так что мне пришлось самому подробно разобрать всё, что требуют API.

А вот с этого места начинается FAQ, запрошенный cardinalом.
Выкладываю полный текст моего модуля для работы с COM-портом при помощи API: 
Код

'   МОДУЛЬ ДЛЯ РАБОТЫ С COM-ПОРТОМ
'            при помощи API.
'--------------------------------------------------------
'для использования в программе здесь четыре подпрограммы:
'OpenCOM -открытие порта. Имеет аргументом единственное число - номер указанного порта.
'SetCommParam -настройка порта. Имеет параметрами четыре числа.
'ReadCOM -функция получения данных с порта. Параметр - количество запрашиваемых символов.
'WriteCOM -отправка данных в порт. Параметр - отправляемая строка символов

'Перед завершением программы обязательно закрывайте открытый порт следующим образом:
' If ComNum > 0 Then fin_com = CloseHandle(ComNum)

Option Explicit

'глобальные переменные
Global ComNum As Long 'хэндл открытого порта; >0, если порт открыт.
Global BarDCB As DCB 'таблица параметров порта
Global CtimeOut As COMMTIMEOUTS 'таймауты порта
Global bRead(2047) As Byte 'буфер принятых символов

'Структуры для параметров настройки порта
Type COMMTIMEOUTS
        ReadIntervalTimeout As Long
        ReadTotalTimeoutMultiplier As Long
        ReadTotalTimeoutConstant As Long
        WriteTotalTimeoutMultiplier As Long
        WriteTotalTimeoutConstant As Long
End Type
Type DCB
        DCBlength As Long
        BaudRate As Long
        fBitFields As Long
        wReserved As Integer
        XonLim As Integer
        XoffLim As Integer
        ByteSize As Byte
        parity As Byte
        StopBits As Byte
        XonChar As Byte
        XoffChar As Byte
        ErrorChar As Byte
        EofChar As Byte
        EvtChar As Byte
        wReserved1 As Integer
End Type

'структура для операций файлового чтения-записи
Type OVERLAPPED
        Internal As Long
        InternalHigh As Long
        offset As Long
        OffsetHigh As Long
        hEvent As Long
End Type

'объявления функций API
Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Declare Function PurgeComm Lib "kernel32" (ByVal hFile As Long, ByVal dwFlags As Long) As Long
Public Declare Function SetCommTimeouts Lib "kernel32" (ByVal hFile As Long, lpCommTimeouts As COMMTIMEOUTS) As Long
Public Declare Function SetCommState Lib "kernel32" (ByVal hCommDev As Long, lpDCB As DCB) As Long
Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As OVERLAPPED) As Long
Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As OVERLAPPED) As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Public Declare Function GetLastError Lib "kernel32" () As Long


Public Sub OpenCOM(ByVal com As Integer) 'Открытие COM-порта
    Dim retval As Long

    ComNum = CreateFile(("COM" + Trim(Str$(com))), &HC0000000, 0, 0&, &H3, 0, 0)
    If ComNum = -1 Then
        MsgBox "Ошибка открытия порта COM" + Trim(Str$(com)), vbCritical
      Else
         retval = PurgeComm(ComNum, 0) 'очистка порта, очередей
    End If
    
    ' Начальное заполнение таблицы параметров приемопередачи
    BarDCB.DCBlength = 28  'длина блока DCB
    BarDCB.BaudRate = 2400  'скорость приемопередачи в бодах
    BarDCB.fBitFields = &H83 'Битовое поле, биты которого означают следующее:
            '1 fBinary вкл двоичный режим. Всегда 1 (кроме Windows 3.x :))
            '2 fParity          1 -проверять четность, возвращать код ошибки.
            '3 fOutxCtsFlow     1 -задействовать сигнал CTS: при сброшенном CTS приостанавливает передачу до появления CTS.
            '4 OutxDsrFlow      1 -точно так же задействовать сигнал DSR
            '5,6 fDtrControl    режим управления DTR. Три значения, не выяснил, каких.
            '7 fDsrSensitivity  чувствительность драйвера к DSR. При 1 драйвер устройства будет игнорировать данные, принятые без DSR.
            '8 fTXContinueOnXoff 0 - прием будет приостанавливаться принятым символом Xoff и возобновляться Xon.
            '9 fOutX            1 -передача будет приостанавливаться принятым символом Xoff и возобновляться Xon.
            '10 fInX            1 -драйвер будет передавать управляющие символы Xon\Xoff
            '11 fErrorChar      1 -при ошибке по четности заменить ошибочный символ на заданный в поле ErrorChar
            '12 fNull           1 -отбрасывать при передаче нулевые байты
            '13,14 fRtsControl  0 -выдавать сигнал RTS. Возможны три значения для выбора режима управления, какая кодировка - не выяснил.
            '15 fAbortOnError   1 -при возникновении ошибки драйвер остановится до вызова функции ClearCommError.
            '16 fDummy2         =0 зарезервировано, не используется.
    BarDCB.wReserved = 0 'не используется, должен быть 0
    BarDCB.XonLim = 128 'Задает минимальное число символов в приемном буфере перед посылкой символа XON
    BarDCB.XoffLim = 64 'Определяет макс кол-во байт в приемном буфере перед посылкой символа XOFF. Оно вычисляется вычитанием данного значения из размера применого буфера (в байтах)
    BarDCB.ByteSize = 8      'разрядность данных (кол-во бит)
    BarDCB.parity = 0      '1-проверять нечетность, 2-проверять четность, 0-не проверять ничего
    BarDCB.StopBits = 0     'количество стоповых бит: 0 -один, 1 -полтора, 2 -два
    BarDCB.XonChar = 17 'символ, используемый в качестве Xon
    BarDCB.XoffChar = 19 'символ, используемый в качестве Xoff
    BarDCB.ErrorChar = 35 'символ, заменяющий принятый с ошибкой
    BarDCB.EofChar = 26 'символ "конец данных"
    BarDCB.EvtChar = 0  'символ для сигнализации о событии
    BarDCB.wReserved1 = 0 'зарезервировано. Не используется.

    'Времена ожидания (Time Outs) в миллисекундах
    CtimeOut.ReadIntervalTimeout = 1 'максимальное время между двумя принимаемыми символами.
    CtimeOut.ReadTotalTimeoutConstant = 1 'постоянная часть таймаута на прием
    CtimeOut.ReadTotalTimeoutMultiplier = 1 'время на прием одного символа (для вычисления переменной части таймаута)
    CtimeOut.WriteTotalTimeoutConstant = 20 'постоянная часть таймаута на передачу
    CtimeOut.WriteTotalTimeoutMultiplier = 5 'время на передачу одного символа (для вычисления переменной части таймаута)
                                                         'нулевые времена означают, что таймауты не используются.

End Sub

    
Public Sub SetCommParam(baud As Long, parity As Byte, bits As Byte, stops As Byte)
'подпрограмма установки параметров порту
'все аргументы- числа:
' baud -скорость обмена в бодах, из принятой шкалы скоростей.
' parity -четность. 1=проверять нечетность, 2=проверять четность, 0=не проверять ничего
' bits -битность данных. Число: 5, 6, 7 или 8 бит.
' stops 0=один стоповый бит, 1=полтора стоповых бита, 2=два стоповых бита.


    Dim retval As Long

    'установка таймаутов
 '   CtimeOut.ReadIntervalTimeout = 1 + Int(12000 / baud)
 '   CtimeOut.ReadTotalTimeoutConstant = 1
 '   CtimeOut.ReadTotalTimeoutMultiplier = 1 + Int(12000 / baud)
    CtimeOut.WriteTotalTimeoutMultiplier = 1 + Int(12000 / baud)
    retval = SetCommTimeouts(ComNum, CtimeOut)
    If retval = -1 Then
        retval = GetLastError()
        MsgBox "Ошибка при установке таймаутов, Error: " & retval
    End If
    
    BarDCB.BaudRate = baud  'скорость приемопередачи в бодах
    BarDCB.ByteSize = bits  'разрядность данных (кол-во бит)
    BarDCB.parity = parity  '1-проверять нечетность, 2-проверять четность, 0-не проверять ничего
    BarDCB.StopBits = stops 'количество стоповых бит: 0 -один, 1 -полтора, 2 -два
    retval = SetCommState(ComNum, BarDCB)
    If retval = -1 Then
        retval = GetLastError()
        MsgBox "Не удается настроить порт на заданные параметры Error: " & retval
    End If
         
End Sub

Public Function ReadCOM(ByVal numChar As Integer) As String
'функция приема через COM
'параметр - число принимаемых за раз символов, до 2047
'(при циклическом вызове его можно уменьшить для ускорения работы)
    Dim RetBytes As Long, i As Integer, ReadStr As String, retval As Long
    Dim lpOverlapped As OVERLAPPED

    'чтение с порта
    retval = ReadFile(ComNum, bRead(0), numChar, RetBytes, lpOverlapped)
    If retval = 0 Then
        retval = GetLastError()
        MsgBox "Ошибка работы с портом Error: " & retval
    End If

    ReadStr = ""
    If (RetBytes > 0) Then
        For i = 0 To RetBytes - 1
            ReadStr = ReadStr + Chr(bRead(i))
        Next i
    End If

    ReadCOM = ReadStr

End Function

Public Sub WriteCOM(COMString As String)
'Подпрограмма передачи в порт.
'Параметр - передаваемая строка символов

    Dim RetBytes As Long, LenVal As Long, retval As Long
    Dim lpOverlapped As OVERLAPPED

    If COMString = "" Then Exit Sub

    'Рекурсивный вызов: передача длинных строк
    'частями по 2048 знаков (потому что буфер приемопередачи- 2048 знаков)
    If Len(COMString) > 2047 Then
        Call WriteCOM(Left$(COMString, 2047))
        Call WriteCOM(Right$(COMString, Len(COMString) - 2047))
        Exit Sub
    End If

    'передача знаков в буфер
    For LenVal = 0 To Len(COMString) - 1
        bRead(LenVal) = Asc(Mid$(COMString, LenVal + 1, 1))
    Next LenVal

    'передачa через COM
    retval = WriteFile(ComNum, bRead(0), Len(COMString), RetBytes, lpOverlapped)
    If retval = 0 Then
        retval = GetLastError()
        MsgBox "Ошибка передачи Error: " & retval & vbCrLf & "Передано " & RetBytes & " байт"
    End If
End Sub


Как использовать. Создаете в своем проекте модуль и вписываете в него целиком этот код. В результате в вашей проге доступны три подпрограммы и две функции для работы с COMом.
Сначала открываете желаемый порт подпрограммой OpenCOM. Аргументом ее является только число, напр. 2 (а не COM2: ). Потом настраиваете желаемую скорость и прочее при помощи SetCommParam - у нее тоже все аргументы числовые. Вместо "9600,8,n,1" задаем 9600, 0, 8, 0 . Подробное описание поставил в комментах.
Всё! После этого можно посылать данные WriteCOM и принимать ReadCOM. ReadCOM имеет параметром количество читаемых знаков. Это сделано для того, чтобы при циклическом вызове можно было ускорить вращение цикла, убавив число принимаемых за раз символов (все равно вызовы идут друг за другом!). Можно сделать даже посимвольный прием, но тогда скорость опять падает за счет увеличения количества проходов цикла. Оптимум- 10 - 15 в цикле и 255 знаков при разовом приеме кнопкой.
Замеченные ошибки мной исправлены, формат DCB правильный. При желании можно писать "в ручную" прямо в поля переменной BarDCB, а потом вызвать SetCommParam, которая отправит настройки в порт. Про DCB я могу рассказать отдельно (если спросите), впрочем я постарался по возможности подробно ее откомментировать.

И одно важное предупреждение:
перед завершением программы следует порт закрыть ОБЯЗАТЕЛЬНО! Если Вы этого не сделаете - он останется открытым и недоступным для всех программ. Я не знаю другого способа вернуть такой порт в действие, кроме перезагрузки компа. API принадлежат собственно не Бейсику, а Виндам, и поэтому их действие сохраняется и после закрытия вашей программы. В данном случае - это единственный минус использования API.
Закрыть порт в нашей программе можно, использовав непосредственно функцию API, поставленную в событие Unload формы:
fin_com = CloseHandle(ComNum)
ComNum у нас хранит хэндл порта, полученный при открытии. Эту переменную можно использовать в программе для проверки, открыт ли порт. Если ComNum больше нуля - то открыт.

К этому сообщению я приаттачиваю полностью проект. Собственно, всё необходимое для работы с портом сосредоточено в модуле. А форма - это только пользовательский интерфейс, и все, что наворочено в ней - всего лишь связи элементов между собой. (Дело в том, что текстовые поля не отображают нулевой код, а мне хотелось, чтоб он отсылался/принимался тоже. Пришлось дублировать данные в переменных, и проч. мутату).
Проект был задуман как терминал для отладки микроконтроллеров, и поэтому внешне он реализует подход электронщика, а не программиста. Кнопки "Open" нет: порт открывается автоматически, когда начинается работа с ним, а закрывается при закрытии программы.
Форма About первоначально была предназначена для дополнительных параметров, типа размера буферов. Это делайте сами smile 

Благодарности: Неизвестному автору примера, на котором я тренировался, и от которого остались имена и некоторые решения.
Олегу Титову, за замечательную статью , которая мне всё разъяснила. Об этом я постараюсь рассказать в отдельной темке.

Всем удачи! smile 





Это сообщение отредактировал(а) JusTalionis - 25.5.2008, 10:21

Присоединённый файл ( Кол-во скачиваний: 81 )
Присоединённый файл  comm_API.zip 8,66 Kb
PM MAIL   Вверх
Derks
Дата 13.9.2008, 22:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 19.6.2008

Репутация: нет
Всего: нет



Вообщем можете верить можете проверить... но когда пытался использовать данный код, возникла маленькая проблемка...
Порт никак не хотел открываться. Все заработало когда заменил "COM1" на "\.\\COM1". Решение нашел по адресу http://support.microsoft.com/kb/115831. Может это сэкономит кому время...
PM MAIL   Вверх
JusTalionis
Дата 14.9.2008, 14:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 576
Регистрация: 11.7.2006

Репутация: 6
Всего: 17



Цитата(Microsoft)
 HOWTO: Specify Serial Ports Larger than COM9
SUMMARY
CreateFile() can be used to get a handle to a serial port. The "Win32 Programmer's Reference" entry for "CreateFile()" mentions that the share mode must be 0, the create parameter must be OPEN_EXISTING, and the template must be NULL. 

CreateFile() is successful when you use "COM1" through "COM9" for the name of the file; however, the message 
INVALID_HANDLE_VALUE 
is returned if you use "COM10" or greater. 

If the name of the port is \\.\COM10, the correct way to specify the serial port in a call to CreateFile() is as follows:    CreateFile(
      "\\\\.\\COM10",     // address of name of the communications device
      fdwAccess,          // access (read-write) mode
      0,                  // share mode
      NULL,               // address of security descriptor
      OPEN_EXISTING,      // how to create
      0,                  // file attributes
      NULL                // handle of file with attributes to copy
   );

    
NOTES: This syntax also works for ports COM1 through COM9. Certain boards will let you choose the port names yourself. This syntax works for those names as well. 

APPLIES TO
• Microsoft Win32 Application Programming Interface, when used with: 
    Microsoft Windows 95 
    Microsoft Windows 98 Standard Edition 
    Microsoft Windows 2000 Standard Edition 
    Microsoft Windows Millennium Edition 
    Microsoft Windows NT 4.0 
    the operating system: Microsoft Windows XP 


mihanik!!! smile 
Вы у нас тут специалист,  сертифицированный Микрософт; разъясните, пожалуйста, как же все-таки следует правильно писать имена портов: \\.\COM10, \\\\.\\COM10 или \.\\COM1 ?
И с какой, вообще, стати в именах портов появилась непонятная куча слэшей?

PM MAIL   Вверх
mihanik
Дата 14.9.2008, 15:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


-=Белый Медведь=-
****


Профиль
Группа: Комодератор
Сообщений: 4054
Регистрация: 24.4.2006
Где: г. Тверь

Репутация: 11
Всего: 109



Цитата(JusTalionis @  14.9.2008,  14:13 Найти цитируемый пост)
mihanik!!!  
Вы у нас тут специалист,  сертифицированный Микрософт; разъясните, пожалуйста, как же все-таки следует правильно писать имена портов: \\.\COM10, \\\\.\\COM10 или \.\\COM1 ?
И с какой, вообще, стати в именах портов появилась непонятная куча слэшей?


А что сразу я-то?  smile 
Я сертифицированный специалист в области ОС Windows XP, а не программер?
(Хотя VB6 немного знаю...)

Думаю, что это как-то связано с организацией работы API... 
Цитата

APPLIES TO
• Microsoft Win32 Application Programming Interface, when used with: 


(Вы заметили парность слешей, если их больше 1?)


Это сообщение отредактировал(а) mihanik - 14.9.2008, 15:13


--------------------
Программистами не рождаются, - это родовая травма...
user posted imageuser posted image
PM MAIL WWW ICQ   Вверх
JusTalionis
Дата 14.9.2008, 15:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 576
Регистрация: 11.7.2006

Репутация: 6
Всего: 17



нет, не заметил. Там их по три штуки есть.  И все-таки сколько их должно быть-то? Три или шесть? (хотя бы у двузначных COM-ов)? Я что-то не въезжаю, что в Микрософтовской цитате рекомендовано.

PM MAIL   Вверх
mihanik
Дата 14.9.2008, 17:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


-=Белый Медведь=-
****


Профиль
Группа: Комодератор
Сообщений: 4054
Регистрация: 24.4.2006
Где: г. Тверь

Репутация: 11
Всего: 109



Цитата(JusTalionis @  14.9.2008,  15:36 Найти цитируемый пост)
Там их по три штуки есть

Где?
Если это
Цитата(mihanik @  14.9.2008,  15:12 Найти цитируемый пост)
\\.\

то это не считается. Это не 3, а 2 и 1.

Цитата(JusTalionis @  14.9.2008,  15:36 Найти цитируемый пост)
Я что-то не въезжаю, что в Микрософтовской цитате рекомендовано.

Ну... Там сказамо, что если ты обращаешься к порту 10 и выше, то стоит использовать такую вот странную нотацию.
Кроме того сказано, что и для портов с номерами от 1 до 9 эта нотация также работает...



--------------------
Программистами не рождаются, - это родовая травма...
user posted imageuser posted image
PM MAIL WWW ICQ   Вверх
JusTalionis
Дата 14.9.2008, 20:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 576
Регистрация: 11.7.2006

Репутация: 6
Всего: 17



А какую именно: \\.\ или \\\\.\\ ?

PM MAIL   Вверх
mihanik
Дата 14.9.2008, 21:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


-=Белый Медведь=-
****


Профиль
Группа: Комодератор
Сообщений: 4054
Регистрация: 24.4.2006
Где: г. Тверь

Репутация: 11
Всего: 109



Цитата

If the name of the port is \\.\COM10, the correct way to specify the serial port in a call to CreateFile() is as follows:    CreateFile(
      "\\\\.\\COM10",     // address of name of the communications device
      fdwAccess,          // access (read-write) mode
      0,                  // share mode
      NULL,               // address of security descriptor
      OPEN_EXISTING,      // how to create
      0,                  // file attributes
      NULL                // handle of file with attributes to copy
   );


Вольный перевод

Цитата

Если имя порта - это "\\.\COM10", правильный(корректный) способ определить порт в вызове процедуры CreateFile() является следующим
CreateFile(
      "\\\\.\\COM10",     // адрес имени комуникационного устройства
      fdwAccess,          // способ доступа (read-write)
      0,                  // режим шары
      NULL,               // адрес дискриптора безопасности
      OPEN_EXISTING,      // как создавать
      0,                  // атрибуты файла
      NULL                // хэндл файла с атрибутами для копирования
   );




Ну... Как-то так...

Добавлено через 2 минуты и 19 секунд
JusTalionis, изучай не только VB6, но и английский...  ;-)


Это сообщение отредактировал(а) mihanik - 14.9.2008, 21:23


--------------------
Программистами не рождаются, - это родовая травма...
user posted imageuser posted image
PM MAIL WWW ICQ   Вверх
JusTalionis
Дата 15.9.2008, 08:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 576
Регистрация: 11.7.2006

Репутация: 6
Всего: 17



Пасиб за пожелание относительно английского; этот вольный перевод и у меня получился таким же, но меня смутило вот что: "ЕСЛИ имя порта - это "\\.\COM10". А если просто COM10? Тогда как?.. Ведь у Derks заработало \.\\COM1 а не \\.\COM1.

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


PM MAIL   Вверх
mihanik
Дата 15.9.2008, 22:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


-=Белый Медведь=-
****


Профиль
Группа: Комодератор
Сообщений: 4054
Регистрация: 24.4.2006
Где: г. Тверь

Репутация: 11
Всего: 109



JusTalionis, это как твоя аватара.
Кто-то видит саксофониста, а кто-то прекрасную девушку...
Я бы поступил так, если номер порта 1-9, то использовал бы одну нотацию, если 10-... , то другую.
Оператор If ещё не отменили...

 smile 



--------------------
Программистами не рождаются, - это родовая травма...
user posted imageuser posted image
PM MAIL WWW ICQ   Вверх
JusTalionis
Дата 16.9.2008, 08:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 576
Регистрация: 11.7.2006

Репутация: 6
Всего: 17



If без проблем. Но не в этом же дело. А дело в том, чтобы получить исправно рабочий код.
В реальности ни я, ни кто другой, не в состоянии в ручную проверить работоспособность кода на ВСЕХ компах, которые могут существовать на свете.
Для этого существуют стандарты и правила. Их соблюдение гарантирует работоспособность в оговоренных условиях. Например путь C:\WINDOWS гарантированно приведет нас в папку, если таковая существует.

Мне нет проблемы добавить два или 4 слэша. И посмотреть, заработает или нет. Но это "шаманство", потому что у меня - всё заработает, а на твоем компе - фиг знает. Код, который я выше писал, работал на двух машинах у меня, работал под '95 и '98 на работе, работал под Вистой.
А вот у  Derks не заработал. Я добавлю слэши так и эдак - и у скольких людей тогда код перестанет работать и начнет глючить? Не можешь сказать? Вот поэтому и надо придерживаться в написаннии правил, которые обеспечивают работоспособность.
А правило не может быть двусмысленным, как моя аватара. Кстати, на ней, имхо, Че Гевара в молодости, а не девушка))))))

И в данном случае мне непонятно, что же тогда считается правильным "именем порта"? Я в простоте душевной полагал, что в программировании "правильным" является именно то имя, которое фигурирует в вызове, а не в устной речи.
В тексте же "именем порта" названо одно, а в вызове - другое. Вот такое правило мне не понятно, разъясните кто-нибудь мне, старому дураку!

PM MAIL   Вверх
Akina
Дата 16.9.2008, 09:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20570
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 34
Всего: 453



Цитата(JusTalionis @  16.9.2008,  09:38 Найти цитируемый пост)
правило не может быть двусмысленным

Оно и не является дувусмысленным.

UNC-путь должен начинаться двумя слешами, если указывается имя компьютера, и одним - если не указывается. В записи \\.\COM10 в начале два слеша - значит, компьютер указан, а раз там точка - путь указывает на текущий компьютер. Кстати, допустима запись типа \\?\Resource\Folder\Filename - вернее, как раз в данном случае, когда ресурс есть устройство (COM10), недопустима, а вот для файлового ресурса не только допустима, но и предпочтительна.
Цитата(Derks @  13.9.2008,  23:51 Найти цитируемый пост)
Все заработало когда заменил "COM1" на "\.\\COM1". 

Нотация с ошибочным количеством слешей сработала просто потому, что все происходит локально. Но не факт, что это будет на всех компьютерах - особенности ОС могут привести к проблемам. А вот указанный в документации вариант \\.\COM10 сработает всегда.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
JusTalionis
Дата 16.9.2008, 11:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 576
Регистрация: 11.7.2006

Репутация: 6
Всего: 17



Akina:
С учетом выше сказанного Вами, будет ли безусловно верен следующий (развернутый) перевод? -

"Если номер COM-порта превышает 9, то к нему следует обращаться как к сетевому даже в том случае, когда он находится непосредственно на текущем компьютере, то есть сетевое имя его например \\.\COM10
При вызове функции CreateFile() в адресе следует добавить слэши следующим образом: 
Код
 CreateFile(
      "\\\\.\\COM10",     // адрес имени комуникационного устройства
      fdwAccess,          // способ доступа (read-write)
      0,                  // режим шары
      NULL,               // адрес дискриптора безопасности
      OPEN_EXISTING,      // как создавать
      0,                  // атрибуты файла
      NULL                // хэндл файла с атрибутами для копирования
   ); 

Этот способ работает также и для портов 1 - 9."
?


Derks:
Пробовали ли Вы использовать в точности микрософтовский вариант вызова "\\\\.\\COM1" ? Заработал ли такой синтакисис?
И почему Вы остановились на "\.\\COM1" ?



PM MAIL   Вверх
Akina
Дата 16.9.2008, 13:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20570
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 34
Всего: 453



Цитата(JusTalionis @  16.9.2008,  12:02 Найти цитируемый пост)
будет ли безусловно верен следующий (развернутый) перевод?

Термин "сетевой" в данном случае неверен. Правильнее использовать термин "UNC-путь".


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
RA3PKJ
Дата 18.6.2011, 10:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 2
Регистрация: 9.10.2008

Репутация: нет
Всего: нет



Всё работает отлично. Спасибо за код. Но есть замечание. После закрытия порта следует обнулить переменную ComNum, т.е. вписать ComNum = 0. Ни кто за нас это не сделает. Ещё раз говорю - Спасибо.
PM MAIL   Вверх
cardinal
Дата 18.6.2011, 11:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Инженер
****


Профиль
Группа: Экс. модератор
Сообщений: 6003
Регистрация: 26.3.2002
Где: Германия

Репутация: 19
Всего: 99



Цитата(RA3PKJ @  18.6.2011,  08:03 Найти цитируемый пост)
После закрытия порта следует обнулить переменную ComNum, т.е. вписать ComNum = 0. Ни кто за нас это не сделает.

Зачем?


--------------------
Немецкая оппозиция потребовала упростить натурализацию иммигрантов
В моем блоге: Разные истории из жизни в Германии

"Познание бесконечности требует бесконечного времени, а потому работай не работай - все едино".  А. и Б. Стругацкие
PM   Вверх
ZeroNull
Дата 25.3.2017, 13:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 25.3.2017

Репутация: нет
Всего: нет



Цитата(JusTalionis @ 20.5.2008,  14:00)
Во исполнение моего обещания, здесь данного cardinalу, рассказываю, как я все-таки добил задачу, и выкладываю готовый проект.

Я испробовал много вариантов. Во-первых, должен отметить, что использование контрола в данном случае дает настолько большие облегчения в работе, что я попытался временно отказаться от своего принципа не применять контролы. И тут же налетел на другую проблему: на моей машине все работало легко и просто, но принес экзешник на работу - и на той машине сразу вылетело сообщение, что в системе установлен неподходящий контрол,- и точка. Я писал об этом в соседней темке. Попробовал переименовать файл контрола; пробовал даже сменить внутри контрола все имена - не вышло, все равно запускался либо тот, что в ........

Я , конечно ,  извиняюсь за некрофилию но  у меня малость проблема с работой этого кода

данный код не хочет работать если номер компорта больше 9 

в строке
 
Код

   ComNum = CreateFile(("COM" + Trim(Str$(com))), &HC0000000, 0, 0&, &H3, 0, 0)



ComNum  возврашщает -1 при  com>9 
 smile 
 ой, туплю, все .. smile  топик выше прочитал ))

Это сообщение отредактировал(а) ZeroNull - 25.3.2017, 13:43
PM MAIL   Вверх
Guest45
Дата 21.5.2017, 18:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 199
Регистрация: 24.5.2009

Репутация: нет
Всего: нет



После того, как порт закрыт,  число, хранимое в ComNum теряет всякую ценность.
Хочешь его обнуляй, хочешь не обнуляй, это ни на что уже не влияет.
smile

Добавлено через 5 минут и 13 секунд
Цитата(ZeroNull @ 25.3.2017,  13:37)
 ComNum  возвращает -1 при  com>9 
 Там где-то в середине разбиралось. Когда номер порта двузначный, Микрософт предлагает использовать написание его имени со слэшами.

Добавлено через 13 минут и 45 секунд
А про начальный вопрос темы все как-то и забыли.
Ведь автор хотел организовать событие по приходу данных?
(без контрола)

PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "VB6"
Akina

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по VB обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • Используйте теги [code=vb][/code] для подсветки кода. Используйтe чекбокс "транслит" (возле кнопок кодов) если у Вас нет русских шрифтов.


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Akina.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | VB6 | Следующая тема »


 




[ Время генерации скрипта: 0.3529 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.