Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Языки программирования С, С++

.pdf
Скачиваний:
136
Добавлен:
01.05.2014
Размер:
1.43 Mб
Скачать

Тонкости и хитрости в вопросах и ответах

hCom = INVALID_HANDLE_VALUE;

}

//

int __fastcall TComPort::Open(int n)

{

bool ierr; AnsiString ComName;

ComName = "\\\\.\\COM"+IntToStr(n);

if(hCom != INVALID_HANDLE_VALUE) Close();

hCom = CreateFile(ComName.c_str(),

GENERIC_READ|GENERIC_WRITE, 0, 0,

OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0);

if (hCom == INVALID_HANDLE_VALUE) throw Exception

("Невозможно открыть порт COM"+IntToStr(n)); SetupComm(hCom, 2048, 2048);

GetCommTimeouts(hCom, &Timeouts); Timeouts.ReadIntervalTimeout = MAXDWORD; Timeouts.ReadTotalTimeoutMultiplier = 0; Timeouts.ReadTotalTimeoutConstant = 0; Timeouts.WriteTotalTimeoutMultiplier = 0; Timeouts.WriteTotalTimeoutConstant = 0; ierr = SetCommTimeouts(hCom, &Timeouts);

if(!ierr) throw Exception

("Ошибка инициализации порта COM"+IntToStr(n));

GetCommState(hCom, &dcbBuf); dcbBuf.BaudRate = iBaudRate; dcbBuf.fBinary = true; dcbBuf.fParity = false; dcbBuf.ByteSize = 8; dcbBuf.Parity = 0; dcbBuf.StopBits = 0;

ierr = SetCommState(hCom, &dcbBuf);

617

Тонкости и хитрости в вопросах и ответах

if(!ierr) throw Exception

("Ошибка инициализации порта COM"+IntToStr(n));

ierr = SetCommMask(hCom, EV_RXCHAR);

if(!ierr) throw Exception

("Ошибка инициализации порта COM"+IntToStr(n));

return iComNumber = n;

}

//

int __fastcall TComPort::Open(void)

{

return Open(iComNumber);

}

//

void __fastcall TComPort::Close(void)

{

CloseHandle(hCom);

hCom = INVALID_HANDLE_VALUE;

}

//

void __fastcall TComPort::FlushBuffers(void)

{

PurgeComm(hCom, PURGE_TXABORT|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_RXCLEAR);

}

//

DWORD __fastcall TComPort::WriteBlock(void *buf, int count)

{

DWORD realCount;

WriteFile(hCom, buf, count, &realCount, &OverlappedStructure);

return realCount;

}

//

DWORD __fastcall TComPort::ReadBlock(void *buf, int count)

{

DWORD realCount;

bool bResult = ReadFile(hCom, buf, count, &realCount, &OverlappedStructure);

618

Тонкости и хитрости в вопросах и ответах

// if there was a problem, or the async. operation's still pending ...

if(!bResult)

{

// deal with the error code switch(GetLastError())

{

case ERROR_HANDLE_EOF:

{

//we're reached the end of the file

//during the call to ReadFile

//code to handle that throw Exception("1");

}

case ERROR_IO_PENDING:

{

//asynchronous i/o is still in progress

//do something else for a while Sleep(100);

//check on the results of the asynchronous read

bResult = GetOverlappedResult(hCom, &OverlappedStructure, &realCount,

false);

//if there was a problem ...

if(!bResult)

{

//deal with the error code switch(GetLastError())

{

case ERROR_HANDLE_EOF:

{

//we're reached the end of the file //during asynchronous operation throw Exception("2");

}

//deal with other error cases default:

{

throw Exception("3");

619

Тонкости и хитрости в вопросах и ответах

}

}

}

}// end case

//deal with other error cases default:

{

throw Exception("4");

}

}// end switch

}// end if

return realCount;

}

//

void __fastcall TComPort::SetBaudRate(int b)

{

GetCommState(hCom, &dcbBuf); dcbBuf.BaudRate = b; SetCommState(hCom, &dcbBuf);

}

//

DWORD __fastcall TComPort::ClearError(void)

{

COMSTAT stCom; DWORD ierr;

ClearCommError(hCom,&ierr,&stCom); return ierr;

}

Как отследить запуск второй копии приложения?

1.Воспользоваться функцией FindWindow(). Ее использование затруднительно если меняется заголовок окна или есть другое окно с таким же заголовком и классом окна.

2.Воспользоваться RxLib овской функцией ActivatePrevInstance, которая в конце концов тоже использует эту функцию. Однако ActivatePrevInstance так же выполняет некоторые полезные действия (активизация предыдущей копии приложения).

620

Тонкости и хитрости в вопросах и ответах

3. Можно создавать семафоры, мутексы, но тогда при некорректном завершении программы, ты ее больше не запустишь.

Пример использования мутекса:

HANDLE hMutex=CreateMutex(NULL, FALSE, "YourMutexName"); if(GetlastError()==ERROR_ALREADY_EXISTS )

{

//здесь надо бы активизировать предыдущую копию приложения.

//как это сделать, см. ActivatePrevInstance().

}

else

{

try

{

Application >Initialize(); Application >CreateForm(__classid(TForm1), &Form1); Application >Run();

}

catch (Exception &exception)

{

Application >ShowException(&exception);

}

CloseHandle(hMutex);

}

4. Можно получить имя исполняемого файла для каждого из запущенных процессов, после чего сравнить его с именем .exe вашего процесса... Недостатки способа:

a) Две копии приложения могут быть запущены из разных

мест.

б) Различные методы получения списков запущенных процессов для '9x и NT.

Пример для '9x:

#include <tlhelp32.h> #include <dos.h>

USERES("Project1.res"); USEFORM("Unit1.cpp", Form1);

//

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)

621

Тонкости и хитрости в вопросах и ответах

{

HANDLE hSnapshot=CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);

PROCESSENTRY32 pe; pe.dwSize=sizeof(pe); bool Running=false;

DWORD CurrentProc=GetCurrentProcessId(); if(Process32First(hSnapshot, &pe))

do

{

if(CurrentProc!=pe.th32ProcessID && strcmpi(pe.szExeFile, _argv[0])==0)

{

Running=true;

break;

}

}while(Process32Next(hSnapshot, &pe));

CloseHandle(hSnapshot);

if(Running) return 1;

try

{

Application >Initialize(); //......

5. Использовать временный файл:

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)

{

HANDLE hFile = CreateFile("c:\\tempfile.tmp", GENERIC_WRITE, 0,

NULL, CREATE_ALWAYS,

FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL);

if(hFile == INVALID_HANDLE_VALUE) return 1;

try

{

Application >Initialize();

622

Тонкости и хитрости в вопросах и ответах

Application >CreateForm(__classid(TForm1), &Form1); Application >Run();

}

catch (Exception &exception)

{

Application >ShowException(&exception);

}

CloseHandle(hFile);

return 0;

}

Это, в принципе, универсальный способ, устойчивый к некорректному завершению программы, основным недостатком которого является появление «лишнего» файла на диске.

Как на C++ выглядит паскалевский is? dynamic_cast<...>(...);

Пример:

Паскаль:

if Screen.Forms[I] is FormClass then begin

C++:

if (dynamic_cast<FormClass*>(Screen >Forms[I])){

Как сделать окно как у WinAMP?

Установки формы:

= Object Inspector = BorderIcons=[] BorderStyle=bsNone

Если таскаем за TLabel, то поместить на форму один Label и 3 кнопки SpeedButton (свернуть, развернуть, закрыть), в процедуре на событие onMouseDown поместить следующие строчки:

void __fastcall TForm1::Label1MouseDown(TObject *Sender, TMouseButton Button,

TShiftState Shift, int X, int Y)

{

const int SC_DRAGMOVE = 0xF012; if(WindowState!=wsMaximized)

// чтобы не таскать развернутое окно

623

Тонкости и хитрости в вопросах и ответах

{

ReleaseCapture(); Perform(WM_SYSCOMMAND, SC_DRAGMOVE, 0);

}

}

//на кнопки в событии onClick

//свертывание формы

void __fastcall TForm1::SpeedButton1Click(TObject *Sender)

{

Perform(WM_SYSCOMMAND,SC_MINIMIZE,0);

}

// развертывание/восстановление формы

void __fastcall TForm1::SpeedButton2Click(TObject *Sender)

{

if(WindowState==wsMaximized)

//тут не плохо бы сменить рисунок на кнопке Perform(WM_SYSCOMMAND,SC_RESTORE,0);

else Perform(WM_SYSCOMMAND,SC_MAXIMIZE,0);

}

// закрытие формы

void __fastcall TForm1::SpeedButton3Click(TObject *Sender)

{

Perform(WM_SYSCOMMAND,SC_CLOSE,0);

}

Все объекты могут находиться на панели (TPanel) — но проще поместить Bevel на форму.

Почему не работает код:

Variant v = Variant::CreateObject("Excel.Application"); v.OlePropertySet("Visible",true);

Из за особенностей реализации OLE сервера Excel русской локализации.

624

Тонкости и хитрости в вопросах и ответах

В Borland`s examples сказано, что примеры с OLE работают, только если у вас стоит английская версия Word или Excel.

Необходимо использовать библиотеку типов Excel.

Как показать ProgressBar на StatusBar'е?

Предположим, что вы хотите показать CProgressCtrl на весь

StatusBar.

Для этого необходимо проделать следующее:

Выберите пункт меню View Resource Symbols. Нажмите кнопку New и добавьте новое имя, в нашем примере это будет ID_PROGRBAR.

В файле MainFrm.cpp найдите объявление массива indicators (он находится сразу после END_MESSAGE_MAP) и отредактируйте его к следующему виду:

static UINT indicators[] =

{

ID_PROGRBAR };

В файле MainFrm.h создайте protected переменную m_bCreated типа BOOL и public переменную m_progress типа CProgressCtl.

В файле MainFrm.cpp отредактируйте конец функции int

CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) таким образом:

if (!m_wndStatusBar.Create(this ) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof (UINT)))

{

TRACE0("Failed to create status bar\n" ); return 1; // fail to create

}

добавьте следующую строку: else {

m_wndStatusBar.SetPaneInfo(0,ID_PROGRBAR,SBPS_STRETCH,10);

}

Кроме того, добавьте инициализацию нашей переменной m_bCreated:

625

Тонкости и хитрости в вопросах и ответах

.........

m_bCreated=FALSE;

..........

Теперь мы можем использовать ProgressBar в строке статуса, естественно не забыв создать этот объект. Предположим, у нас есть функция CMainFrame::OnWork(). Она будет выглядеть примерно так:

void CMainFrame::OnWork()

{

RECT rc; m_wndStatusBar.GetItemRect(0,&rc);

if (m_bCreated==FALSE)

{

// создаем m_progress m_progress.Create(WS_VISIBLE|WS_CHILD, rc,&m_wndStatusBar,

1);

//Устанавливаем размер от 0 до 100 m_progress.SetRange(0,100);

m_progress.SetStep(1); m_bCreated=TRUE;

}

for (int I = 0; I < 100; I++)

{

Sleep(20); m_progress.StepIt();

}

}

Если откомпилировать проект на этой фазе, то все будет работать, но при изменении размера окна линейка ProgressBar'а размеры менять не будет, поэтому необходимо перекрыть событие OnSize:

void CMainFrame::OnSize(UINT nType, int cx, int cy)

{

CFrameWnd::OnSize(nType, cx, cy); if (m_bCreated)

{

RECT rc; m_wndStatusBar.GetItemRect(0,&rc);

m_progress.SetWindowPos(&wndTop, rc.left, rc.top,

626