воскресенье, 9 января 2011 г.

Неименованные каналы в windows


/* Программа клиент */
#include "stdafx.h"
#include "windows.h"
#include "conio.h"
#include "string.h"
#include "iostream"
#include "vector"
#define STOP -1 // Завершение цикла
using namespace std;
/*!
* Функция для проверки верности байт
*\param byteFirst - первое количество байт
*\param byteSecond - второе количество байт
*\return - 1 - количество байт совпадает, 0 - количество байт не совпадает
*/
bool checkByte(DWORD & byteFirst,DWORD & byteSecond)
{
if(byteFirst!= byteSecond)
return false;
return true;
}
int main(int argc, char* argv[])
{
// Если есть параметры у клиента(дескриптор на чтеление из канала)
if(argc<1)
{
// Завершение программы
cout << "Arrguments not enter" << endl;
_getch();
return -1;
}
int command = 0;
DWORD byteRead; // количество байт на чтение
DWORD byteNeedRead; // реальное количество прочитанах байт
// перевод аргумента из строковой формы в HANDLE
HANDLE hRead = (HANDLE)atoi(argv[0]);
// количесто байт на чтение
byteRead = sizeof(int);
// цикл до команды завершение цикла(-1)
while(command!=STOP)
{
// чтение данных из канала и проверка на верное считывание
if(ReadFile(hRead,(void*)&command,byteRead,&byteNeedRead,NULL) == FALSE || checkByte(byteRead,byteNeedRead) == false || byteNeedRead == 0)
{
// если даные не считались или считались неполностью
cout << "Fail with read" << endl;
_getch();
return -1;
}
// вывод считанных данныхх
cout << command << endl;
}
_getch();
return 0;
}


/* Программа сервер */
#include "stdafx.h"
#include "winsock2.h"
#include "windows.h"
#include "conio.h"
#include "string.h"
#include "iostream"
#include "vector"
#define STOP -1
using namespace std;
/*!
* Функция для проверки верности байт
*\param byteFirst - первое количество байт
*\param byteSecond - второе количество байт
*\return - 1 - количество байт совпадает, 0 - количество байт не совпадает
*/
bool checkByte(DWORD & byteFirst,DWORD & byteSecond)
{
if(byteFirst!= byteSecond)
return false;
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hWrite; // дескриптор для записи
STARTUPINFO si;
PROCESS_INFORMATION pi;
HANDLE hRead; // дескриптор для чтения
int count = 0; // количество цифр для ввода
int *number; // цифры
wchar_t buffer[10]; // буфер для дискриптора
DWORD writeByte; // количество байт которые запишутся в канал
DWORD needWrite; // количество байт которые нужно записать в канал
SECURITY_ATTRIBUTES attr;
attr.bInheritHandle = TRUE; // наследуемый дескриптор
attr.lpSecurityDescriptor = NULL;
attr.nLength = sizeof(SECURITY_ATTRIBUTES);
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Создание неименновоного канала
if(!CreatePipe(&hRead,&hWrite,&attr,1024))
return -1;
// Перевод дескриптора на чтение в строковую форму
_itow((int)hRead,buffer,10);
// Создание нового процесса
// Параметром командной строки является дескриптор на чтение
if(!CreateProcess(L"child.exe",buffer,NULL,NULL,TRUE,CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi))
{
// в случае ошибка закрытие дескрипторы на чтение и на запись
CloseHandle(hRead);
CloseHandle(hWrite);
printf( "CreateProcess failed (%d)\n", GetLastError() );
_getch();
return -1;
}
// Ввод количество цифр и самих цифр
cout << "Enter count number: ";
scanf("%d", &count);
number = (int*)calloc(sizeof(int),count);
for(int i = 0 ; i < count; i++)
cin >> number[i];
writeByte = sizeof(int); // количество байт которые будут записываться в канал
// Если произошла запись в канал, записалось нужное количество байт и они записались
if(WriteFile(hWrite,(void*)&count,writeByte,&needWrite,NULL) == FALSE || checkByte(writeByte,needWrite) == false || needWrite ==0)
{
// если была ошибка
cout << "Data was break" << endl;
goto exit;
}
// запись чисел в канал и проверка как и в прошлом комментарии
for(int i = 0 ; i < count ; i++)
if(WriteFile(hWrite,(void*)&number[i],writeByte,&needWrite,NULL) == FALSE || checkByte(writeByte,needWrite) == false || needWrite ==0)
{
cout << "Data was break" << endl;
break;
}
// после отправки всех чисел отправка комманды на завершение,так же с проверкой
count = -1;
if(WriteFile(hWrite,(void*)&count,writeByte,&needWrite,NULL) == FALSE || checkByte(writeByte,needWrite) == false || needWrite ==0)
{
cout << "Data was break" << endl;
goto exit;
}
exit:
// Завершение всех процесов и закрытие программы
free(number);
FlushFileBuffers(hRead);
FlushFileBuffers(hWrite);
CloseHandle(hRead);
CloseHandle(hWrite);
_getch();
return 0;
}

вторник, 28 декабря 2010 г.

TLS. Локальное хранилище потока.

Идея проста.Если нужна использовать глобальные переменные для потока,то как решить проблему использование одной и той же памяти разными потоками.Есть решение - TLS.
В небольшом примере всё будет видно.

#include "stdafx.h"
#include "iostream"
#include "string.h"
#include "windows.h"
using namespace std;

// Глобальные переменные
int tls_int;
char simple_char[25];
DWORD tls_char;
/*!
* Потоковая функция
* \param param - параметр потоковой функции
* \return - результат работы потоковой функции
*/
DWORD WINAPI ThreadFunc(LPVOID param);
/*!
* Потоковая функция использующая технологию TLS
* \param param - параметр потоковой функции
* \return - результат работы потоковой функции
*/
DWORD WINAPI ThreadFuncTls(LPVOID param);
/*!
* Главная функция программы
*/
int _tmain(int argc, _TCHAR* argv[])
{
char variant[20];
DWORD threadId;
cout << "Enter method - ";
cin >> variant;
if (!strcmp(variant,"simple"))
{
CreateThread(NULL,0,ThreadFunc,(LPVOID)1,0,&threadId);
CreateThread(NULL,0,ThreadFunc,(LPVOID)2,0,&threadId);
Sleep(10000);
}
if (!strcmp(variant,"tls"))
{
/*
Прототип
DWORD WINAPI TlsAlloc(void);
TlsAlloc - резервирует свободный блок памяти
который будет принаджежать только потоку внутри
которого она вызывалась.
Возвращает индекс ячейки зарезервированной памяти,
если память невозможно выделить возвращает TLS_OUT_OF_INDEXES .
*/
tls_int = TlsAlloc();
tls_char = TlsAlloc();
CreateThread(NULL,0,ThreadFuncTls,(LPVOID)1,0,&threadId);
CreateThread(NULL,0,ThreadFuncTls,(LPVOID)2,0,&threadId);
Sleep(10000);
TlsFree(tls_int);
TlsFree(tls_char);
}
return 0;
}
DWORD WINAPI ThreadFunc(LPVOID param)
{
// юзаем глобальные переменные
tls_int = (int)param;
strcpy(simple_char,"array symbol");
Sleep(tls_int);
cout << "Parameter = " << tls_int << endl;
cout << "string : " << simple_char << endl;
return 0 ;
}
DWORD WINAPI ThreadFuncTls(LPVOID param)
{
/*
Прототип
BOOL WINAPI TlsSetValue(
__in DWORD dwTlsIndex,
__in LPVOID lpTlsValue
);
TlsSetValue - Можно догадаться функция заносит
в выделеную локальную память потока значение.
Первым параметром является индекс выделенной ячейки памяти,
т.е то что нам вернула функция TlsAlloc.
Вторым же значение которое надо занясти в память.
*/
TlsSetValue(tls_int,param);
char buffer[25];
strcpy(buffer,"array symbol");
TlsSetValue(tls_char,buffer);
/*
Прототип
LPVOID WINAPI TlsGetValue(__in DWORD dwTlsIndex);
TlsGetValue - Функция возвращает значение из заразервированной
ячейки памяти.
Параметром является индекс зарезервированной ячейки памяти.
*/
Sleep((DWORD)TlsGetValue(tls_int));
cout << "Parametr = " << (DWORD)TlsGetValue(tls_int) << endl;
cout << "string : " << (char *)TlsGetValue(tls_char)<< endl;
return 0;
}

воскресенье, 28 ноября 2010 г.

Функция с переменным количеством параметров

Hi!Для операционных систем для реализации синхронизации разных запросов,используется разные фишки: мьютексы,семафоры,событи и т.д. Я выбрал события,и для разных функций использовалось переменное количество переменных для синхронизации секций.И решать проблему не хочется Ctrl+c, Ctrl+v)Решил написать функцию с переменным количеством параметров:)

HANDLE * hmains(HANDLE handle,...)
{
va_list par; //лист с параметрами*
int count = -1; // количество переменных
int size; // вспомогательная переменная
HANDLE *cp = &handle; // Начало в памяти для всех переменных функции
va_start(par,handle); // присваиваем листу начало для переменных
while(cp = va_arg(par,HANDLE*)) // подсчёт количество переменных
count++;
size = count;
va_start(par,handle);
HANDLE *hmain = new HANDLE[count]; // Память под массив переменных
hmain[0] = handle; // Первая переменная в массиве
while(cp = va_arg(par,HANDLE *)) // Заполняем массив оставшимися переменными
{
if(size==1)
break;
hmain[count - size +1] = cp; // непосредственно заполнение
size--;
}
return hmain; // Возвращаем массив переменных
}

Конечно можно придраться к реализации или с умничать по каждой строчке,но статья для возможности показать вариант реализации,а уж каждый сможет его как хочет изменять и модифицировать)

суббота, 13 ноября 2010 г.

Использование потоковых функций в классе

Итак я столкнулся с 1 проблемой,что у меня был класс Server,который работал всего с 1 клиентом.Но это не нормально когда сервер всего для 1 клиента,поэтому пришлось сделать потоковую функция для обработки запросов клиентов:)А т.к при вызове функции CreateThread протокол у функции должен быть иным,чем у функции класса,происходил FAIL.Пришлось выкручиваться.
Покажу реализацию на простом примере.
Простой класс.

class Data;
struct dataStruct
{
Data *data;
HANDLE handle;
};
class Data
{
public:
Data()
:xData(10),
yData(10)
{

}
~Data()
{

}
int & x(){return this->xData;}
int & y(){return this->yData;}
int sum()const{return xData+yData;}
/*Запиливаем потоковую функцию*/
friend DWORD WINAPI thread(void *param)
{
dataStruct *data = (dataStruct*)param;
int count = data->data->sum();
for(int i=0;i< count ; i++)
{
Sleep(100);
cout << data->data->sum() << endl;
data->data->x()++;
data->data->y()++;
}
return 0;
}
private:
int xData;
int yData;
};

А теперь просто в main будем запускать.

void main()
{
for(int i = 0; i<10; i++)
{
Data data;
dataStruct rec;
rec.data = &data;
Sleep(1000);
rec.handle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)thread,(LPVOID)&rec ,0,0);
}
Sleep(10000);
}

вторник, 2 ноября 2010 г.

Qt + MySQL

Начали проходить БД, и дело, конечно, не обошлось без MySQL:) Так как я любитель Qt, То GUI конечно хотелось бы написать на нём и соответственно взаимодействие с БД осуществить с помощью этой библиотеки.
Все, я думаю, читали, что для использования возможностей API MySQL надо просто подключить нужный драйвер, в нашем случае это QMYSQL. Делается это очень просто.
QSqlDatabase  & db = QSqlDatabase::addDatabase("QMYSQL","base");

Но при запуске может возникнуть проблема - библиотека говорит нам, что драйвер QMYSQL не найден. А ведь действительно, откуда qt знает, где наш sql  Как говорится – «телепаты в отпуске» :)
Что же нам делать в этом случае? Ответ вполне прост, надо нам собрать qt с нужными для нас модулями, в частности для mysql. Делать мы это будем в любимой всеми командной строке.
Так как я не любитель стандартной консоли в windows, то пользуюсь программой “Console”. Название вполне оригинальное:)
Итак, что там нужно: во-первых, собираться будем для visual studio 2008, поэтому будем пользоваться её утилитой Visual Studio 2008 Command Prompt.
Или можно ввести в консоли следующее:
%comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"" x86



p.s путь к батнику у вас может быть иным .
Итак, теперь осталось верно собрать кутишечку:)
Для этого переходим в консоли в папку с Qt и набираем:
configure –debug-and-release –platform win32-msvc2008 –qt-sql-mysql



Дальше пойдёт сборка



После окончания сборки, мы радостные по идее должны зайти в src\sql и выполнить nmake, но не тут-то было:) Нам скажут , что он не понимает где лежат сами либы. Придётся прикручивать всё вручную, ну как обычно:)
Находим либы и инклуды в папке с MySQL. По идее, они должны лежать в MySQL\MySQL Server\lib .
Так вот, смысл в том, что мы вручную указываем в исходниках qt путь до этой папки с файлом mysql.h.
В моём случае получилось так :



Теперь снова заходим в src\sql и делаем nmake



Теперь всё должно пройти нормально:)
Удачи. Если что пишите на почту chexov34@gmail.com по возможности отвечу.
Отдельное спасибо Мамонтову Дмитрию http://vkontakte.ru/id6925882. Он просто мегамозг и задрот :)

вторник, 15 июня 2010 г.

Visual Studio 2010 + Qt

Здравствуйте! После выхода Visual Studio 2010 всем конечно же захотелось проверить это чудо для разработки ПО :) Есть было небольшое "но". Коснулось это "но" не всех конечно же, надеюсь не у многих такая проблема. Эта проблема именно с интеграцией Qt библиотеки в студию. Хотя какая тут проблема, тут целый трабл,т.к самой интеграциии нет. Как раз особо упорным эта тема будет полезна) Воспользоваться всеми возможностями Qt мы не сможем конечно же, но базовыми функциями вполне,так что не надейтесь собрать исходники QWebKit или QtCreator :)

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

У меня установлена qt 4.6.3 ( скачать можно её тут http://qt.nokia.com/downloads/windows-cpp-vs2008 ). Путь : c:\Qt\4.6.3, в дальнейшем QTDIR .
(Объяснения для русской версиии Visual Studio 2010 )

1. Созадать простейший проект
2. Проект -> Свойство проекта -> Каталоги VC++ :
2.1. в пункте "Каталоги исполняемых файлов" добавляем путь : QTDIR\bin;
2.2. в пункте "Каталоги включеня" добавить путь : QTDIR\include;
2.3. в пункте "Каталоги библиотек" добавить путь : QTDIR\lib;
2.4. в пункте "Каталоги исходного кода" добавить путь : QTDIR\include;
3. Проект -> Свойства проекта -> Компоновщик -> Ввод:
3.1 В пункте "Дополнительные зависимости" добавляем библиотеки которые нам нужны самые важные : QtCore4.lib,QtCored4.lib,qtmain.lib.Если QTDIR не прописан в переменных средах или в PATH не указан путь до папки с проектом то указать надо полный путь до библиотеки , т.е c:\Qt\4.6.3\lib\QtCore4.lib.
Собственно и всё:)Работа над компиляции GUI программ ведётся , ждите новых статей :)

Обработка xml файлов с помощью библиотеки Qt

Статья QtXml)

Обработка xml файлов с помощью библиотеки Qt.

Я расскажу самый быстрый способ, когда не нужно создавать свои классы и структуры для хранения информации из xml.Мы будем пользоваться qt функциями.
Обработка будет производиться методам DOM.

void readXml (QDomNode *node);
void main(int argc, char*argv[])
{
if(argc>2)
{
QFile xml(argv[1]); // Наш файлик загружен
QDomDocument domDoc;
if(domDoc.setContent(&xml)) // Вот и само считывание впринципи
{
QDomElement domElement= domDoc.documentElement(); // Получаем главный корень дерева xml
readXml(&domElement); // Парсинг
}
}
}
void readXml (QDomNode *node)
{
QDomNode child=node->firstChild();
while(!child.isNull()) // Если есть узел
{
QDomElement element=node->toElement(); // Преобразуем данные узла
if(!element.isNull()) //
{
puts(qPrintable("tagName : " + element.tagName())); // распечатка тегов
puts(qPrintable("attribute name: " + element.attribute("name")); // распечатка атрибутов
}
readXml(&child); // Продолжаем парсить дерево
child=child.nextSibling(); // Переходим к следующему узлу
}
}
// На выходе будет распечатка всех тегов и их атрибутов :)