Статьи по Assembler

       

Main.cpp для mycall (c++)


Это основной файл приложения MyCall на C++. Этот файл в текстовом формате вместе со всеми остальными файлами, необходимыми для компиляции приложения MyCall, содержится в zip-файле mycallcb.zip (13192 байта). Имеется также Инструкция программиста.

Для получения комментариев щелкaйте по тексту или пользуйтесь групповым управлением:

if(dhtml){document.write("Все комментарии: [+][-]    Открывать: [несколько]");}

//Включение заголовочных файлов

//Здесь windows.h и ras.h - стандартные из пакета MS Visual C++,

//а main.h - заголовочный файл приложения MyCall

#include "windows.h"

#include "ras.h"

#include "main.h"

//ГЛАВНАЯ ФУНКЦИЯ ПРИЛОЖЕНИЯ

/////////////////////////////////////////////////////////////// WinMain

int WINAPI WinMain(HINSTANCE hinst,HINSTANCE prev_hinst,LPSTR command_line,int cmd_show){

//Получение дескриптора экземпляра приложения



//Необходимое действие, так как предполагается компиляция приложения без

//подключения runtime-библиотеки. Подробнее...

hinst=GetModuleHandle(NULL);

//Создание главного окна

//Обычное действие, с которого начинаются большинство приложений.

//Единственное отличие в том, что в качестве главного окна в MyCall

//используется окно диалога, описанного в файле ресурсов

//Регистрируется класс главного окна:

WNDCLASSEX mw_class;

mw_class.cbSize=sizeof(WNDCLASSEX);

mw_class.style=NULL;

mw_class.lpfnWndProc=superprocedure;

mw_class.cbClsExtra=0;

mw_class.cbWndExtra=DLGWINDOWEXTRA;

mw_class.hInstance=hinst;

mw_class.hIcon=LoadIcon(hinst,MAKEINTRESOURCE(103));

mw_class.hIconSm=NULL;

mw_class.hCursor=LoadCursor(NULL,IDC_ARROW);

mw_class.hbrBackground=(HBRUSH)COLOR_WINDOW;

mw_class.lpszMenuName=NULL;

mw_class.lpszClassName="MainWindowClass";

if(!RegisterClassEx(&mw_class)){fatal(FATAL_MAIN_CLASS_REG);return EXIT_COMMON_ERROR;}

//Главное окно создается:

if(!(main_window=CreateDialog(hinst,MAKEINTRESOURCE(101),NULL,NULL))){fatal(FATAL_MAIN_CLASS_CREATE);return EXIT_COMMON_ERROR;}


// По состоянию списка conn_window формируются остальные списки

change_con();//

//ЦИКЛ ОЖИДАНИЯ СООБЩЕНИЙ

//Неотъемлемый элемент приложений для Windows. В MyCall никаких особенностей не имеет

MSG loop_message;

while (GetMessage(&loop_message,NULL,0,0)){TranslateMessage(&loop_message);DispatchMessage(&loop_message);}

//ЗАВЕРШЕНИЕ РАБОТЫ ПРИЛОЖЕНИЯ

//Поскольку MyCall собирается без runtime-библиотеки, для завершения работы

//обязательно использовать функцию ExitProcess, при этом оператор return оказывается

//недостижимым, но необходим по требованиям синтаксиса. Подробнее...

ExitProcess(loop_message.wParam);

return 0;

}

//ОКОННАЯ ПРОЦЕДУРА

//Стандартный элемент приложений для Windows. В MyCall особенностей не имеет.

/////////////////////////////////////////////////////////////// Оконная процедура

LRESULT CALLBACK superprocedure(HWND window_from,UINT message,WPARAM w_param,LPARAM l_param){

//Разбор и обработка оконных сообщений

switch(message){

//Обработка сообщения WM_COMMAND, передаваемого элементами управления диалога

case WM_COMMAND:

//Обработка уведомления CBN_SELCHANGE, передаваемого списками при изменении позиции:

//1000: список соединений conn_window. Изменяет содержание phon_window и user_window

//1001: список телефонов phon_window. Устанавливает новый телефон для текущего соединения con_phone[current_con]

//1002: список логинов user_window. Устанавливает новый логин для текущего соединения con_user[current_con]

if(HIWORD(w_param)==CBN_SELCHANGE){

switch (LOWORD(w_param)){

case 1000:

current_con=SendMessage(conn_window,CB_GETCURSEL,0,0);

if(current_con==CB_ERR){current_con=0;}

change_con();

return 0;

case 1001:

con_phone[current_con]=SendMessage(phon_window,CB_GETCURSEL,0,0);

if(con_phone[current_con]==CB_ERR){con_phone[current_con]=0;}

return 0;

case 1002:

con_user[current_con]=SendMessage(user_window,CB_GETCURSEL,0,0);

if(con_user[current_con]==CB_ERR){con_user[current_con]=0;}

return 0;

default:

break;



}

return 0;

}

// Обработка уведомления BN_CLICKED, передаваемого кнопкой при клике:

//в состоянии online=TRUE прекращает дозвон (разрывает соединение) и включает списки

//в состоянии online=FALSE отключает списки и начинает дозвон

if((HIWORD(w_param)==BN_CLICKED)&&(LOWORD(w_param))==1003){

if(online){

EnableWindow(butt_window,FALSE);

ras_hangup();

EnableWindow(butt_window,TRUE);

disable_controls(FALSE);

}else{

disable_controls(TRUE);

ras_dial();

}

return 0;

}

break;

//Обработка сообщения WM_USER, используемого в MyCall нитью монитора разрыва.

//Обнаружив факт разрыва соединения, нить монитора передает WM_USER. Если был коннект,

//то включаются списки, в противном случает выполняется повторный дозвон

case WM_USER:

ras_hangup();

l_param?disable_controls(FALSE):ras_dial();

return 0;

//Обработка сообщения WM_MOVE: запоминание новой позиции окна

//для последующей записи ее в файл mycall.ini

case WM_MOVE:

RECT win_pos;

if(GetWindowRect(main_window,&win_pos)){

main_win_left=win_pos.left;

main_win_top=win_pos.top;

/div>

}else{

main_win_left=(int)LOWORD(l_param);

main_win_top=(int)HIWORD(l_param);

}

return 0;

//При завершении работы приложения записать файл mycall.ini,

//и освободить память

case WM_DESTROY:

save_ini();

if(dat_buffer){GlobalFree(dat_buffer);}

PostQuitMessage(EXIT_NORMAL);

return 0;

//При закрытии главного окна заблокировать кнопку

//и разорвать соединение

case WM_CLOSE:

EnableWindow(butt_window,FALSE);

if(online){ras_hangup();}

break;

}

//Обработка глобального оконного сообщения, используемого для

//взаимодействия экземпляров приложения. Получив это сообщение,

//экземпляр, запущенный первым, сообщает дескриптор своего главного окна.

//Сообщение, полученное вторым, принимает от первого дескриптор его главного окна,

//выводит его на первый план и завершается. Подробнее...

if(message==my_message){

if((HWND)w_param!=main_window){

if(l_param==0){

SendMessage(HWND_BROADCAST,my_message,(WPARAM)main_window,1);



}else{

SetForegroundWindow((HWND)w_param);

ExitProcess(EXIT_OVERLOADED);

}

}

return 0;

}

//Возврат необработанных сообщений системе

return DefWindowProc(window_from,message,w_param,l_param);

}

//ЗАГРУЗКА ФАЙЛА ИНИЦИАЛИЗАЦИИ

//Файл mycall.ini хранит состояние списков и положение главного окна на момент

//завершения предыдущего сеанса работы приложения

/////////////////////////////////////////////////////////////// Загрузка файла инициализации

void load_ini(){

//Инициализация глобальных переменных

main_win_left=MAIN_WIN_DEFAULT_LEFT;

main_win_top=MAIN_WIN_DEFAULT_TOP;

current_con=0;

for(int i=0;i<MAX_CON;i++){

con_phone[i]=0;

con_user[i]=0;

}

//Попытка загрузки файла mycall.ini

//В случае неудачи используются значения по умолчанию

HANDLE ini_file=CreateFile(INI_FILE,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

if(ini_file!=INVALID_HANDLE_VALUE){

//Чтение файла mycall.ini

BYTE buffer[INI_FILE_LENGTH];

DWORD bytes_read;

if(ReadFile(ini_file,buffer,INI_FILE_LENGTH,&bytes_read,NULL)){

//Приведение позиции окна к фактическим размерам экрана и запоминание

main_win_left=(((INT)buffer[1])<<8)|((INT)buffer[0]);

if(main_win_left>=GetSystemMetrics(SM_CXSCREEN)-10){main_win_left=MAIN_WIN_DEFAULT_LEFT;}

main_win_top=(((INT)buffer[3])<<8)|((INT)buffer[2]);

if(main_win_top>=GetSystemMetrics(SM_CYSCREEN)-10){main_win_top=MAIN_WIN_DEFAULT_TOP;}

//Запоминание позиций списков телефонов и логинов

current_con=(INT)buffer[4];

for(int i=0;i<MAX_CON;i++){

con_phone[i]=(INT)buffer[(i<<1)+5];

con_user[i]=(INT)buffer[(i<<1)+6];

}

}

CloseHandle(ini_file);

}

}

//СОХРАНЕНИЕ ФАЙЛА ИНИЦИАЛИЗАЦИИ mycall.ini

//В файле сохраняются положение главного окна на экране и позиции

//списков на момент завершения работы приложения

/////////////////////////////////////////////////////////////// Сохранение файла инициализации

void save_ini(){

HANDLE ini_file=CreateFile(INI_FILE,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);



if(ini_file!=INVALID_HANDLE_VALUE){

BYTE buffer[INI_FILE_LENGTH];

buffer[0]=(BYTE)main_win_left;

buffer[1]=(BYTE)(main_win_left>>8);

buffer[2]=(BYTE)main_win_top;

buffer[3]=(BYTE)(main_win_top>>8);

buffer[4]=(BYTE)current_con;

for(int i=0;i<MAX_CON;i++){

buffer[(i<<1)+5]=(BYTE)con_phone[i];

buffer[(i<<1)+6]=(BYTE)con_user[i];

}

DWORD bytes_written;

WriteFile(ini_file,buffer,INI_FILE_LENGTH,&bytes_written,NULL);

CloseHandle(ini_file);

}

}

//ЗАГРУЗКА ФАЙЛА ДАННЫХ mycall.dat

// Файл содержит имена соединений, телефоны и логины

/////////////////////////////////////////////////////////////// Загрузка файла данных

BOOL load_data(){

//Открытие файла, подготовка буфера для него и считывание файла в буфер

HANDLE dat_file=CreateFile(DAT_FILE,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

if(dat_file==INVALID_HANDLE_VALUE){fatal(FATAL_DAT_FILE_OPEN);return FALSE;}

DWORD dat_file_size=GetFileSize(dat_file,NULL);

if(dat_file_size==0xffffffff){CloseHandle(dat_file);fatal(FATAL_DAT_FILE_SIZE);return FALSE;}

dat_buffer=(LPBYTE)GlobalAlloc(GMEM_FIXED,dat_file_size+3);

if(dat_buffer==NULL){CloseHandle(dat_file);fatal(FATAL_DAT_BUF_ALLOC);return FALSE;}

DWORD bytes_read;

if(!ReadFile(dat_file,dat_buffer,dat_file_size,&bytes_read,NULL)){CloseHandle(dat_file);fatal(FATAL_DAT_FILE_READ);return FALSE;}

CloseHandle(dat_file);

//Замена слэшей, CR, LF и пробелов на 0h, добавление в конец 1h

ptr=dat_buffer;

for(DWORD i=0;i<dat_file_size;i++){

if((*ptr==0xd)||(*ptr==0xa)||(*ptr=='/')||(*ptr==' ')){*ptr=0;}

ptr++;}

dat_buffer[i]=0;dat_buffer[i+1]=0;dat_buffer[i+2]=1;

return TRUE;

}

//ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ

//Используются при разборе содержимого буфера данных:

//skip_nz - пропуск всех символов, пока не встретится 00h

//skip_nz2 - пропуск всех символов, пока не встретится 0000h

/////////////////////////////////////////////////////////////// Пропуски

VOID skip_nz(){

while(*ptr!=0){ptr++;}

ptr++;



}

VOID skip_nz2(){

while(*(LPWORD)ptr!=0){ptr++;}

ptr+=2;

}

//ИЗМЕНЕНИЕ СОЕДИНЕНИЯ

//Функция вызывается при выборе в списке соединений нового соединения

/////////////////////////////////////////////////////////////// Изменение соединения

VOID change_con(){

// Установка указателя на запись текущего соединения

INT sub_string=0;

INT cur_con=0;

ptr=dat_buffer;

while(*ptr!=1){

if(cur_con==current_con){break;}

if(*(LPWORD)ptr==0){

if(++sub_string==3){cur_con++;sub_string=0;}

ptr++;

}

ptr++;

}

skip_nz2();

//Формирование списка телефонов для данного соединения и установка его позиции

SendMessage(phon_window,CB_RESETCONTENT,0,0);

int number=0;

while(*ptr!=0){

SendMessage(phon_window,CB_ADDSTRING,0,(LPARAM)ptr);

number++;

skip_nz();

}

ptr++;

if(con_phone[current_con]>=number){con_phone[current_con]=0;}

SendMessage(phon_window,CB_SETCURSEL,(WPARAM)con_phone[current_con],0);

//Формирование списка логинов для данного соединения и установка его позиции

SendMessage(user_window,CB_RESETCONTENT,0,0);

number=0;

while(*ptr!=0){

SendMessage(user_window,CB_ADDSTRING,0,(LPARAM)ptr);

number++;

skip_nz();

skip_nz();

}

if(con_user[current_con]>=number){con_user[current_con]=0;}

SendMessage(user_window,CB_SETCURSEL,(WPARAM)con_user[current_con],0);

}

//АВАРИЙНОЕ ЗАВЕРШЕНИЕ ПРИЛОЖЕНИЯ

//Вызывается в случае, когда продолжение работы приложения невозможно

/////////////////////////////////////////////////////////////// Фатальный аборт

void fatal(int fatal_code){

LPCSTR fatal_text[]={

"Can't register main window class",

"Can't create main window",

"Can't open mycall.txt",

"Can't get size of mycall.txt",

"Can't allocate memory for mycall.txt",

"Can't read mycall.txt",

"Remote Access Service fatal error"};

MessageBox(NULL,fatal_text[fatal_code],"MyCall Error",MB_OK|MB_ICONERROR);

}

//В(Ы)КЛЮЧЕНИЕ ОРГАНОВ УПРАВЛЕНИЯ

//Меняет надпись на кнопке и активизирует списки в зависимости от того,



//находится приложение в режиме выбора или в режиме соединения

/////////////////////////////////////////////////////////////// В(ы)ключение органов управления

VOID disable_controls(BOOL disable){

SetWindowPos(main_window,NULL,NULL,NULL,win_width,win_height+(disable?12:0),SWP_NOMOVE|SWP_NOZORDER);

SendMessage(butt_window,WM_SETTEXT,0,(LPARAM)(disable?"HangUp":"Call"));

EnableWindow(conn_window,!disable);

EnableWindow(phon_window,!disable);

EnableWindow(user_window,!disable);

}

//ДОЗВОН

/////////////////////////////////////////////////////////////// Дозвон

VOID ras_dial(){

//Подготовка структуры RASDIALPARAMS

RASDIALPARAMS ras_dial_params;

ras_dial_params.dwSize=sizeof(RASDIALPARAMS);

ras_dial_params.szCallbackNumber[0]=0;

ras_dial_params.szDomain[0]=0;

ptr=dat_buffer;

for(int j=0;j!=current_con;j++){for(int k=0;k<3;k++){skip_nz2();}}

ras_dial_params.szEntryName[0]=0;

lstrcpy(ras_dial_params.szEntryName,(LPSTR)ptr);

skip_nz();

ras_dial_params.szPhoneNumber[0]=0;

lstrcpy(ras_dial_params.szPhoneNumber,(LPSTR)ptr);

skip_nz();ptr--;

while(*ptr==0){ptr++;}

for(j=0;j!=con_phone[current_con];j++){skip_nz();}

lstrcat(ras_dial_params.szPhoneNumber,(LPSTR)ptr);

skip_nz2();

for(j=0;j!=con_user[current_con];j++){skip_nz();skip_nz();}

ras_dial_params.szUserName[0]=0;

lstrcpy(ras_dial_params.szUserName,(LPSTR)ptr);

skip_nz();

ras_dial_params.szPassword[0]=0;

lstrcpy(ras_dial_params.szPassword,(LPSTR)ptr);

//Дозвон

ras_conn=NULL;

if(RasDial(0,0,&ras_dial_params,0,ras_dial_func,&ras_conn)){

ras_hangup();

fatal(FATAL_RAS);

ExitProcess(EXIT_RAS_ERROR);

}else{

online=TRUE;

}

}

//ФУНКЦИЯ КОНТРОЛЯ СОСТОЯНИЯ СОЕДИНЕНИЯ

/////////////////////////////////////////////////////////////// Контроль состояния соединения

VOID WINAPI ras_dial_func(UINT msg,RASCONNSTATE rasconnstate,DWORD error){

LPCSTR ras_state_text[]={

"OpenPort",

"PortOpened",

"ConnectDevice",

"DeviceConnected",



"AllDevicesConnected",

"Authenticate",

"AuthNotify",

"AuthRetry",

"AuthCallback",

"AuthChangePassword",

"AuthProject",

"AuthLinkSpeed",

"AuthAck",

"ReAuthenticate",

"Authenticated",

"PrepareForCallback",

"WaitForModemReset",

"WaitForCallback",

"Projected",

"StartAuthentication",

"CallbackComplete",

"LogonNetwork",

"SubEntryConnected",

"SubEntryDisconnected",

"Interactive",

"RetryAuthentication",

"CallbackSetByCaller",

"PasswordExpired",

"Connected",

"Disconnected",

"Unknown state"};

if(online){

//Показ состояния соединения в строке статуса

UINT ras_message_num=rasconnstate;

if(ras_message_num>=RASCS_Connected){ras_message_num-=RASCS_Connected-28;}

else{if(ras_message_num>=RASCS_Interactive){ras_message_num-=RASCS_Interactive-24;}}

if(ras_message_num>30){ras_message_num=30;}

SendMessage(stat_window,WM_SETTEXT,0,(LPARAM)ras_state_text[ras_message_num]);

//Если соединение установлено - запуск нити контроля

if(rasconnstate==RASCS_Connected){

CreateThread(NULL,0,ras_monitor_func,0,0,&ras_monitor_id);

//Если соединение не установлено - передача сообщения WM_USER для

//повтора дозвона

}else{

if(rasconnstate==RASCS_Disconnected){

PostMessage(main_window,WM_USER,0,0);

}

}

}

}

//НИТЬ МОНИТОРА РАЗРЫВА

// Каждые 200 мс опрашивает состояние установленного соединения.

//При обнаружении факта разъединения посылает сообщение WM_USER

//и завершается

//============================================================= Нить монитора разрыва

DWORD WINAPI ras_monitor_func(LPVOID param){

RASCONNSTATUS ras_connect_status;

while(online){

ras_connect_status.dwSize=sizeof(RASCONNSTATUS);

if(RasGetConnectStatus(ras_conn,&ras_connect_status)){break;}

if(ras_connect_status.rasconnstate==RASCS_Disconnected){break;}

Sleep(200);

}

PostMessage(main_window,WM_USER,0,1);

return 0;

}

//ПОЛОЖИТЬ ТРУБКУ

//Если происходит дозвон, или соединение установлено,

//дает команду на разрыв и ожидает, когда RAS ее выполнит

/////////////////////////////////////////////////////////////// Положить трубку

VOID ras_hangup(){

RASCONNSTATUS ras_connect_status;

online=FALSE;

if(ras_conn){

RasHangUp(ras_conn);

while(TRUE){

ras_connect_status.dwSize=sizeof(RASCONNSTATUS);

if(RasGetConnectStatus(ras_conn,&ras_connect_status)==ERROR_INVALID_HANDLE){break;}

Sleep(0);

}

ras_conn=0;

Sleep(1000);

}

}


Содержание раздела