пятница, 23 сентября 2011 г.

Простейшая Windows программа

Простейшая Windows программа

(как смог, так и перевел http://relisoft.com/win32/winnie.html)

Перед тем как начать думать о программировании в Windows, вы должны понять, как работает простая программа.

Вызовы Windows API выделены синим, а определенные в Windows типы данных показаны зеленым. Я буду обычно ставить двойное двоеточие в API вызовах. В C++, это просто способ вызова глобальных функций, на случай избегания двусмысленностей.

Для проверки работоспособности кода надо создать проект типа Win32 Application.

Во-первых, в Windows программе, вы должны определить класс окна, которое будет отображено вашим приложением (не C++ класс). В нашем случае будет отображено только одно окно, но мы должны передать Windows некоторый минимум информации о классе окна. Очень важная часть оконного класса – это адрес процедуры обратного вызова или оконной процедуры. Windows вызывает эту процедуру, передавая тем самым сообщения вашей программе.

Объявление оконной процедуры (WindowProcedure). Windows вызывает ее с дескриптором окна (handle), сообщением (message) и двумя переменными (данные сообщения) связанными с сообщением, параметры типа WPARAM и LPARAM.

В WinClass мы определяемся с некоторыми вещами, такими как дескриптор экземпляра приложения HINSTANCE, курсор мыши (загружается стандартная стрелка), кисть закраски фона окна (выбран цвет кисти по умолчанию), и имя нашего класса.

Как только все поля WINDCLASS заполнены, мы регистрируем класс в системе Windows.

#include <windows.h>
 
 
LRESULT CALLBACK WindowProcedure
    (HWND hwnd, unsigned int message, WPARAM wParam, LPARAM lParam);
 
class WinClass
{
public:
    WinClass (WNDPROC winProc, char const * className, HINSTANCE hInst);
    void Register ()
    {
        ::RegisterClass (&_class);
    }
private:
    WNDCLASS _class;
};
 
WinClass::WinClass
    (WNDPROC winProc, char const * className, HINSTANCE hInst)
{
    _class.style = 0;
    _class.lpfnWndProc = winProc; // обязательная оконная процедура
    _class.cbClsExtra = 0;
    _class.cbWndExtra = 0;
    _class.hInstance = hInst;         // владелец класса
    _class.hIcon = 0;
    _class.hCursor = ::LoadCursor (0, IDC_ARROW); // опция
    _class.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); // опция
    _class.lpszMenuName = 0;
    _class.lpszClassName = className; // обязательно имя класса окна
}

Как только класс окна зарегистрирован мы можем создать окно. Это делается вызовом CreateWindow, принимающим следующие аргументы:

 имя класса окна, которое мы зарегистрировали; заголовок окна; стиль окна;  позиция; размер; экземпляр приложения. Эта часть программы может также быть заключена в C++ класс, WinMaker.

class WinMaker
{
public:
    WinMaker (): _hwnd (0) {}
    WinMaker (char const * caption, 
              char const * className,
              HINSTANCE hInstance);
    void Show (int cmdShow)
    {
        ::ShowWindow (_hwnd, cmdShow);
        ::UpdateWindow (_hwnd);
    }
protected:
    HWND _hwnd;
};
 
WinMaker::WinMaker (char const * caption, 
                    char const * className,
                    HINSTANCE hInstance)
{
    _hwnd = ::CreateWindow (
        className,            // имя зарегистрированного класса окна
        caption,              // заголовок окна
        WS_OVERLAPPEDWINDOW,  // стиль окна
        CW_USEDEFAULT,        // x позиция
        CW_USEDEFAULT,        // y позиция
        CW_USEDEFAULT,        // ширена
        CW_USEDEFAULT,        // высота
        0,                    // дескриптор родительского окна
        0,                    // дескриптор меню
        hInstance,            // дескриптор экземпляра приложения
        0);                   // данные окна
}

Windows программа управляется событиями. Это означает, что вы, как программист, должны построить оборону. Поскольку, пользователь бомбардирует Windows различными действиями ввода, а Windows будет бомбардировать вашу программу сообщениями соответствующими этим действиям. Всё, что вы можете – это отвечать на эти сообщения. На рисунке схематично показано как это происходит.

Windows обрабатывает различные события от клавиатуры, мыши, портов и т.д. Каждое событие быстро конвертируется в сообщение. Windows доставляет сообщения в соответствующие окна. Все сообщения клавиатуры идут в окно, которое в настоящее время имеет фокус ввода (активное окно). Сообщения мыши посылаются в соответствии с позицией курсора мыши. Они обычно поступают в окно, которое прямо под курсором.

Все эти сообщения выстраиваются в очередь сообщений. Windows создает очередь сообщений для каждого запущенного приложения (фактически для каждого потока). Ваша обязанность отлавливать сообщения одно за другим в петле (цикле) сообщений. Ваша программа содержит вызов GetMessage извлекающий сообщение из очереди. Потом вы вызываете DispatchMessage передовая его обратно в Windows. Может ли Windows выполнятся дальше без задержки и доставки всех этих своих сообщений? В принципе это возможно, но петля сообщений дает вашей программе шанс посмотреть их и может быть совершать какие-либо дополнительные действия перед их отправкой. Или нет …

Каждое сообщение адресовано особому окну. Когда вы говорите Windows доставлять какое-либо сообщение, то это предполагает некоторый уникальный класс окна, поиск соответствующей оконной процедуры, и вызов ее. Каждый сигнал сообщение, посланное вашему окну, будет направлено вашей оконной процедуре. Которая будет отвечать на сообщение. Стоит ли отвечать на каждый возможный тип сообщения Windows? Сообщений может быть сотни. Так или иначе, мы передаем управление Windows, по умолчанию используя DefWindowProc.





 

Давайте взглянем на WinMain. Исполняемая в Windows программа не стартует с main, она стартует с WinMain. В нашей WinMain, мы создаем WinClass и регистрируем его. Потом мы создаем окно (класс которого только что зарегистрировали) и показываем его. Фактически, WinMain вызывается с соответствующей директивой показа, пользователь может захотеть стартовать приложение минимизированным или максимизированным. Далее, мы определяем петлю сообщений и продолжаем посылку сообщений до тех пор, пока GetMessage не вернет 0. В этом месте wParam сообщения будет содержать возвращаемый код программы в целом.

 

int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst,
            char * cmdParam, int cmdShow)
{
    char className [] = "Winnie";
 
    WinClass winClass (WindowProcedure, className, hInst);
    winClass.Register ();
 
    WinMaker win ("Hello Windows!", className, hInst);
    win.Show (cmdShow);
 
    MSG  msg;
    int status;
 
    while ((status = ::GetMessage (& msg, 0, 0, 0)) != 0)
    {
        if (status == -1)
            return -1;
        ::DispatchMessage (& msg);
    }
 
    return msg.wParam;
}

 

Другая важная часть каждой Windows программы – это оконная процедура. Помните, Windows будет вызывать ее для всех типов сообщений. Все сообщения могут быть проигнорированы вашим приложением вызовом DefWindowProc, которым мы как бы говорим, чтоб Windows обработала сообщение сама. Сообщение WM_DESTROY посылаемое Windows, когда пользователь решает закрыть окно (немедленное закрытие посредством кнопки в меню заголовка). Стандартный ответ WM_DESTROY – это уведомление о выходе и возвращает ноль.

 

// Оконная процедура вызываемая Windows
 
LRESULT CALLBACK WindowProcedure
    (HWND hwnd, unsigned int message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_DESTROY:
            ::PostQuitMessage (0);
            return 0;
 
    }
    return ::DefWindowProc (hwnd, message, wParam, lParam );
}

 

 

воскресенье, 3 июля 2011 г.

Model-View-Controller (MVC) + wxWidgets



Интерфейс "Наблюдатель" (Observer)



1 #ifndef OBSERVER_H
2 #define OBSERVER_H 1
3 class Observer
4 {
5 public:
6 virtual void update(){}
7 };
8 #endif




Описание модели (Model)



1 #ifndef MODEL_H
2 #define MODEL_H 1
3
4 #include <wx/string.h>
5 #include <set>
6
7 #include "Observer.h"
8
9 class Model
10 {
11 public:
12 Model(int d);
13 void setData(const int d);
14 int getData()const;
15 ~Model(){};
16 private:
17 int d_;
18 std::set<Observer*> registry;
19 public:
20 void attach(Observer*s);
21 void detach(Observer*s);
22 void notify();
23 // void clearRegistry();
24 };
25 #endif




Определение модели



1 #include "Model.h"
2
3 Model::Model(int d):d_(d) {};
4
5 void Model::setData(const int d)
6 {
7 d_=d;
8 notify();
9 }
10
11 int Model::getData()const
12 {
13 return d_;
14 }
15
16 void Model::attach(Observer*s)
17 {
18 registry.insert(s);
19 }
20
21 void Model::detach(Observer*s)
22 {
23 registry.erase(s);
24 }
25
26 void Model::notify()
27 {
28 std::set<Observer*>::iterator it;
29 for (it=registry.begin(); it!=registry.end(); it++)
30 (*it)->update();
31 }
32
33




Обобщенное представление (View)



1 #ifndef VIEW_H
2 #define VIEW_H 1
3 class Controller;
4 #include "Observer.h"
5 #include "Model.h"
6 #include "Controller.h"
7 class View: public Observer
8 {
9 protected:
10 Model *myModel;
11 Controller *myController;
12 public:
13 View(Model *m);
14 virtual ~View();
15 virtual void update();
16 virtual void draw();
17 virtual void initialize();
18 virtual Controller* makeController();
19 Model* getModel();
20 Controller *getController();
21 public:
22 virtual void setConroller(Controller *ctrl);
23 };
24 #endif




Определения методов класса View



1 #include "View.h"
2
3 View::View(Model *m):myModel(m),myController(0)
4 {
5 myModel->attach(this);
6 }
7
8 View::~View()
9 {
10 myModel->detach(this);
11 }
12
13 void View::initialize()
14 {
15 myController=makeController();
16 }
17
18 Controller* View::makeController()
19 {
20 return new Controller(this);
21 }
22
23 Model* View::getModel()
24 {
25 return myModel;
26 }
27
28 Controller * View::getController()
29 {
30 return myController;
31 }
32
33 void View::update()
34 {
35 this->draw();
36 }
37
38 void View::draw() {}
39
40 void View::setConroller(Controller *ctrl)
41 {
42 myController=ctrl;
43 }




Контроллер (Controller)



1 #ifndef CONTROLLER_H
2 #define CONTROLLER_H 1
3 #include <wx/event.h>
4 class View;
5 #include "Observer.h"
6 #include "View.h"
7 #include "Model.h"
8 typedef wxCommandEvent Event;
9 class Controller : public Observer
10 {
11 public:
12 virtual void handleEvent(Event *);// default = no op
13
14 Controller(View* v) ;
15 Controller() ;
16 virtual ~Controller();
17 virtual void update(); // default = no op
18 protected:
19 Model *myModel;
20 View *myView;
21 };
22 #endif




Определения методов контроллера



1 #include "Controller.h"
2 void Controller::handleEvent(Event *) {}
3 Controller::Controller(View* v) : myView(v)
4 {
5 myModel = myView->getModel();
6 myModel->attach(this);
7 }
8
9 Controller::~Controller()
10 {
11 myModel->detach(this);
12 }
13
14 void Controller::update() {}




Описание класса представления TextViewVal, реализующего отображение данных на основе wxStaticText



1 #ifndef TEXTVIEWVAL_H
2 #define TEXTVIEWVAL_H 1
3 #include <wx/stattext.h>
4 #include "View.h"
5 #include "TextControllerVal.h"
6 class TextViewVal:
public View ,public wxStaticText
7 {
8 public:
9 TextViewVal(wxWindow *parent,wxWindowID id,Model *m, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize,
long style=0, const wxString &name=wxStaticTextNameStr);
10 ~TextViewVal() ;
11 virtual void draw();
12 virtual Controller *makeController();//+
13 };
14 #endif




Определения методов класса TextViewVal



1 #include "TextViewVal.h"
2 TextViewVal::TextViewVal(wxWindow *parent,wxWindowID id,Model *m, const wxPoint &pos, const wxSize &size,
long style, const wxString &name):View(m),wxStaticText(parent,id, wxString::Format(wxT("%d"),m->getData()), pos,size,style,
name) {}
3
4 TextViewVal::~TextViewVal() {}
5
6 void TextViewVal::draw()
7 {
8 SetLabel(wxString::Format(wxT("%d"),myModel->getData()));
9 }
10
11 Controller* TextViewVal::makeController()
12 {
13 return new TextControllerVal(this->GetParent(), -1,this);
14 }




Контроллер для связи Модели с Отображением



1 #ifndef TEXTCONTROLLERVAL_H
2 #define TEXTCONTROLLERVAL_H 1
3 #include <wx/textctrl.h>
4 #include "Controller.h"
5 #include "TextViewVal.h"
6 class TextViewVal;
7 class TextControllerVal : public Controller,public wxTextCtrl
8 {
9 public:
10 TextControllerVal(wxWindow* parent, wxWindowID id,TextViewVal *tv, const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, long style = 0, const wxValidator& validator = wxDefaultValidator,
const wxString& name = wxTextCtrlNameStr) ;
11 virtual void handleEvent(Event *e);
12 };
13 #endif




Определения методов класса TextControllerVal



1 #include "TextControllerVal.h"
2 TextControllerVal::TextControllerVal(wxWindow* parent, wxWindowID id,TextViewVal *tv, const wxPoint& pos,
const wxSize& size , long style, const wxValidator& validator, const wxString& name ):Controller((View*)tv),wxTextCtrl(parent,
id, wxString::Format(wxT("%d"),tv->getModel()->getData()), pos, size, style , validator , name){}
3
4 void TextControllerVal::handleEvent(Event *e)
5 {
6 myModel->setData(wxAtoi(e->GetString().c_str()));
7 }




Описание класса диалога для размещения Представлений и Контроллера



1 #ifndef TEXTDLGVAL_H
2 #define TEXTDLGVAL_H 1
3 #include <wx/dialog.h>
4 #include "TextViewVal.h"
5 class TextDlgVal : public wxDialog
6 {
7 public:
8 TextDlgVal(wxDialog* parent,wxString& title,Model* m);
9 virtual ~TextDlgVal();
10 protected:
11 enum
12 {
13 ID_TXTVAL=1000
14 };
15
16 Model* model_;
17 TextViewVal * view_;
18 TextViewVal * view2_;
19 TextControllerVal *controller_;
20
21 private:
22 void OnClose(wxCloseEvent &event);
23 void OnText(wxCommandEvent &event);
24
25 DECLARE_EVENT_TABLE()
26 };
27 #endif




Определения класса диалога для размещения Контроллера и двух экземпляров класса Представления



1 #include "TextDlgVal.h"
2 BEGIN_EVENT_TABLE(TextDlgVal, wxDialog)
3 EVT_CLOSE(TextDlgVal::OnClose)
4 EVT_TEXT(ID_TXTVAL, TextDlgVal::OnText)
5 END_EVENT_TABLE()
6
7 TextDlgVal::TextDlgVal(wxDialog* parent,wxString& title,Model* m):wxDialog(parent,-1,title),model_(m),view_(0),controller_(0)
8 {
9 this->SetSizeHints(wxDefaultSize, wxDefaultSize);
10 wxBoxSizer* bSizer1;
11
12 bSizer1 = new wxBoxSizer(wxVERTICAL);
13
14 view_=new TextViewVal(this,-1,m);
15 view2_=new TextViewVal(this,-1,m);
16
17 view_->initialize();//Инициализируем дл� нашего пред�тавлени� контроллер
18 controller_=(TextControllerVal*) view_->getController();//
19 controller_->SetId(ID_TXTVAL);//Делаем возможным обработку �обытий от контроллера
20
21 //Св�жем пред�тавление view2_ � контроллером
22 view2_->setConroller(controller_);
23
24 bSizer1->Add(view_, 0, wxALL|wxEXPAND, 5);
25 bSizer1->Add(view2_, 0, wxALL|wxEXPAND, 5);
26
27 bSizer1->Add(controller_, 1, wxEXPAND, 5);
28
29 this->SetSizer(bSizer1);
30 this->Layout();
31 bSizer1->Fit(this);
32 }
33
34 TextDlgVal::~TextDlgVal(){}
35
36 void TextDlgVal::OnClose(wxCloseEvent &event)
37 {
38 Destroy();
39 }
40
41 void TextDlgVal::OnText(wxCommandEvent &event)
42 {
43 controller_->handleEvent(&event);
44 }
45




Класс приложения wxWidgets



1 #ifndef MVC_TAPP_H
2 #define MVC_TAPP_H
3 #include <wx/app.h>
4 class MVC_TApp : public wxApp
5 {
6 public:
7 virtual bool OnInit();
8 };
9 #endif // MVC_TAPP_H




Определение приложения



1 #ifdef WX_PRECOMP
2 #include "wx_pch.h"
3 #endif
4
5 #ifdef __BORLANDC__
6 #pragma hdrstop
7 #endif //__BORLANDC__
8
9 #include "MVC_TApp.h"
10 #include "TextDlgVal.h"
11
12 IMPLEMENT_APP(MVC_TApp);
13
14 bool MVC_TApp::OnInit()
15 {
16 Model* m_=new Model(10);
17 wxString stro=wxT("MVC TEST");
18
19 TextDlgVal* v1_ = new TextDlgVal(0L,stro,m_);
20 v1_->Show();
21
22 return true;
23 }




Модуль для прекомпиляции (можно и без него обойтись)



1 #ifndef WX_PCH_H_INCLUDED
2 #define WX_PCH_H_INCLUDED
3
4 // basic wxWidgets headers
5 #include <wx/wxprec.h>
6
7 #ifdef __BORLANDC__
8 #pragma hdrstop
9 #endif
10
11 #ifndef WX_PRECOMP
12 #include <wx/wx.h>
13 #endif
14
15 #ifdef WX_PRECOMP
16 // put here all your rarely-changing header files
17 #endif // WX_PRECOMP
18
19 #endif // WX_PCH_H_INCLUDED



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

Настройка CodeBlocks для компиляции wxWidgets / Win32 приложений для Windows компилятором Mingw32 из под Linux/FreeBSD

Установка CodeBlocks из портов:

portinstall codeblocks


Запускаем CodeBlocks, далее меню "Settings" -> "Compiler and Debugger" -> "Selected compiler"
"GNU GCC Compiler" -> "Copy"
задаем имя компилятора "MinGW32 Compiler"

Для этого компилятора задаём:
в "#defines"

WINVER=0x0400
__WIN95__
__GNUWIN32__
STRICT
HAVE_W32API_H
__WXMSW__
__WINDOWS__

в "Toolchain executables" пропишем
"Compiler's installation directory" ~/mingw-cross-env/usr или что там у вас.








"C compiler:"i686-pc-mingw32-gcc
"C++ compiler:"i686-pc-mingw32-g++
"Linker for dynamic libs:"i686-pc-mingw32-g++
"Linker for static libs:" i686-pc-mingw32-ar
"Debugger:"i686-pc-mingw32-gdb
"Resorce compiler:"i686-pc-mingw32-windres
"Make program:"make

По поводу i686-pc-mingw32-gdb, надо создать скрипт ~/mingw-cross-env/usr/bin/i686-pc-mingw32-gdb

cd ~/mingw-cross-env
make gdb
touch ~/mingw-cross-env/usr/bin/i686-pc-mingw32-gdb
echo '#!/bin/csh' >> ~/mingw-cross-env/usr/bin/i686-pc-mingw32-gdb
echo 'wine ~/mingw-cross-env/usr/i686-pc-mingw32/bin/gdb.exe "$@"' >> ~/mingw-cross-env/usr/bin/i686-pc-mingw32-gdb
chmod +x ~/mingw-cross-env/usr/bin/i686-pc-mingw32-gdb



Да и ещё, некоторые общие настройки, хотя и без них wxWidgets приложение соберется, прописать в
"Other Linker Options":
-lstdc++
-lgcc
-lodbc32
-lwsock32
-lwinspool
-lwinmm
-lshell32
-lcomctl32
-lctl3d32
-lodbc32
-ladvapi32
-lodbc32
-lwsock32
-lopengl32
-lglu32
-lole32
-loleaut32
-luuid

Прописать в "Search directories"
Для Compiler путь к include: ~/mingw-cross-env/usr/i686-pc-mingw32/include
Для Linker путь к lib: ~/mingw-cross-env/usr/i686-pc-mingw32/lib
Для Resource compiler: ~/mingw-cross-env/usr/i686-pc-mingw32/include

Жмём "OK"

Из под su, делал так:
ln -s /usr/local/bin/wine /usr/local/bin/wine-auto

При создании нового проекта, надо выбирать "MinGW32 Compiler"
Для новых wxWidgets проектов надо прописывать:
В "Project build options" пропишем
в "Other options":

`i686-pc-mingw32-wx-config --cxxflags`


в "Other linker options:"

`i686-pc-mingw32-wx-config --libs`



Если использовать мастер для создания проекта, то надо wx-config заменить на i686-pc-mingw32-wx-config, для этого можно открыть Ваш файл проекта CodeBlocks (*.cbp) в обычном текстовом редакторе, например, gedit и произвести замену.

Имеются некоторые проблемы при запуске программ после сборки из CodeBlocks, но в общем можно запустить с отладчиком, правда CodeBlocks 10.05 может "рухнуть", было один раз.

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

суббота, 30 апреля 2011 г.

Компилируем wxWidgets приложение для Windows из под FreeBSD

Можно скомпилировать приложение minimal из примеров, поставляемых вместе с wxWidgets.
Использовать будем mingw-cross-env, да к стати из портов можно установить mercurial, чтоб установить последнюю версию mingw-cross-env для этого запускаем:

hg clone http://hg.savannah.nongnu.org/hgweb/mingw-cross-env

Чтоб добыть обновления, запускаем:

hg pull -u


В общем после установки wxwidgets, т.е. после выполнения команд:

cd mingw-cross-env
gmake wxwidgets


В директории с кодом простого wxWidgets приложения выполним:

i686-pc-mingw32-g++ minimal.cpp -o minimal.exe `i686-pc-mingw32-wx-config --cxxflags --libs`

В текущей директории появляется minimal.exe, правда его размер несколько впечатляет почти 7 Мбайт. Можно его уменьшить командой:

i686-pc-mingw32-strip minimal.exe

Почти в два раза.

wine minimal.exe

При записке minimal.exe под Windows 98 , а также wine, при условии, что там в настройках (команда winecfg) стоит Windows 98, может вылести сообщение "wxWidgets Fatal Error\n This program uses Unicode and requires Windows NT/2000/XP ...". Ничего страшного, можно просто перекомпилировать minimal.cpp без поддержки Unicode.

i686-pc-mingw32-g++ minimal.cpp -o minimal.exe `i686-pc-mingw32-wx-config -nounicode --cxxflags --libs`


Об опциях i686-pc-mingw32-wx-config можно узнать командой:

i686-pc-mingw32-wx-config

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

суббота, 23 апреля 2011 г.

Компиляция для Windows из под FreeBSD

Ставил mingw32 из портов, результат не очень.
Но вот набрел на страницу http://mingw-cross-env.nongnu.org
Сделал:
В FreeBSD должно быть установлено: automake111 autoconf268 bash bison cmake flex gmake gsed intltool libtool openssl patch perl p5-XML-Parser pkg-config scons unzip wget yasm
И ещё wine для проверки работоспособности кода.

0. cd ~/mingw32
1. wget https://bitbucket.org/vog/mingw-cross-env/downloads/mingw-cross-env-2.20.tar.gz
2. tar -xzvf mingw-cross-env-2.20.tar.gz
3. cd mingw-cross-env-2.20
4. gmake download-gcc
Возможны проблемы с загрузкой этой командой, но можно и скачать обычным способом. То, что не сможет через скрипт скачать, можно подсмотреть в папке pkg, потестив архивы, можно ещё подсмотреть откуда качает в директории src , найдя соответствующий .mk файл
5. gmake gcc
можно приписать и другие порты после gcc, например, gmake gcc gdb и т.д.
6. редактирую ~/.cshrc , добавляю строку :
setenv PATH ~/mingw/mingw-cross-env-2.20/bin:$PATH
так как использую SHELL=csh,
для SHELL=bash в файле ~/.profile можно прописать:
export PATH = ~/mingw/mingw-cross-env-2.20/bin:$PATH
7. Компилить прогу написанную на Си можно так
i686-pc-mingw32-gcc -o main.exe main.c
8. А, запускать так
wine main.exe

вторник, 15 марта 2011 г.

Отображение кириллических символов в консоли

1. Вариант
Использовать широкие символы
Редактор кода настраивается на ввод символов в кодировке UTF-8
Settings -> Editor… -> General Settings -> Other settings -> Encoding и выбрать UTF-8.
Теперь в тексте программы один символ кодируется двумя байтами, тип которого соответствует wchar_t (тип данных стандарта ANSI/ISO C для представления широких символов). Теперь в программе надо использовать функции, которые умеют обрабатывать wchar_t символы и корректно выполнять ввод/вывод. Обычно имена функций работающих с wchat_t начинаются с символа ‘w’, стоящим перед именем аналогичной функции, но работающей с char, например,
int wprintf( const wchar_t *format [, argument]... ) ; /*аналогична printf */
int wscanf( const wchar_t *format [, argument]... ) ; /* scanf */

В Windows API, тип wchar_t имеет размер 16 бит.
В GNU/Linux тип wchar_t имеет размер 32 бита.

Пример:
/*Компилятор MinGW*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>

int main()
{
setlocale(0,".866");/*Локаль, без этой строки не будет работать*/
wprintf(L"Привет!\n"); /*L – указываем, что используются широкие символы в строке*/
return 0;
}

2. Вариант
Использовать Win32Api функцию CharToOem
Текст программы имеет кодировку WINDOWS-1251 или ANSI, функция CharToOem вызывается обычно перед выводом в консоль какого-либо текста с кириллическими символами.

Пример:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

int main()
{
char s[] = "Текст";
CharToOem(s,s);/*Перекодируем s, после этого вызова s меняет своё значение*/
printf("%s",s);
return 0;
}

3. Вариант
Использование шрифта Lucida Console в консоли
// установить вручную шрифт Lucida Console в свойствах окна консоли
// и запомнить это для всех окон с этим именем
// записать в начале программы строку
#include <windows.h>
// записать в начале функции main ()
// две следующих строки
SetConsoleCP(1251);
SetConsoleOutputCP(1251);

4. Вариант
Использовать опций компилятора для перекодировки текста программы из UTF-8 в CP866. Понятно, что можно использовать и другое направление перекодировки, типа WINDOWS-1251 в CP866. В консоли должна быть доступна команда iconv.
В командной строке делаем, например, так
gcc -finput-charset=UTF-8 -fexec-charset=CP866 main.c -o main

В CodeBlocks можно прописать эти опции в параметры компиляции для проекта
Project -> Build options -> Compiler settings -> Other options
Записываем строку:
-finput-charset=UTF-8 -fexec-charset=CP866

5. Вариант
Если используется компилятор от Microsoft (cl.exe), то достаточно прописать только локаль, строка в функции main():
setlocale(0,””);

пятница, 19 ноября 2010 г.

Вопрос претенденту на вакансию "Программист C++"

На нескольких сайтах, предлагающих вакансию программиста C++, встречаются одни и те же вопросы, например, на сайте вакансий yandex. Один из них такой:
Перечислите все проблемы, которые вы видите в данном коде:


1 class Foo
2 {
3 public:
4 Foo(int j) { i=new int[j]; }
5 ~Foo() { delete i; }
6 private:
7 int* i;
8 };
9
10 class Bar: Foo
11 {
12 public:
13 Bar(int j) { i=new char[j]; }
14 ~Bar() { delete i; }
15 private:
16 char* i;
17 };
18
19
20 void main()
21 {
22 Foo* f=new Foo(100);
23 Foo* b=new Bar(200);
24 *f=*b;
25 delete f;
26 delete b;
27 }



В результате медитации, получил следующий, несовершенный код, но все же отражающий моё понимание проблем:

1 class Bar;//Добавил, чтоб в классе Foo использовать имя класса Bar
2
3 class Foo
4 {
5 public:
6 Foo(int j)
7 {
8 i=new int[j];
9 }
10 Foo() {} //Добавил, т.к. нужен конструктор по умолчанию, если бы Foo(int),
» небыло, то он бы был сгенерирован компилятором

11 ~Foo()
12 {
13 delete[] i; //Изменил, добавив [], а то удалять будет не весь массив, а
» только первый элемент массива с индексом 0, т.е. получим утечку памяти

14 }
15
16 Foo operator=(const Bar& r_)//Добавил оператор присваивания, и по идее надо
» делать глубокое копирование по членам, но для этого обеспечить доступ к полю
» Bar::i, вариантов может быть несколько

17 {
18 //На самом деле дальше код должен быть более сложный
19 delete[] i; //в общем, то надо ещё поработать с динамической памятью,
» убрать, то, что там было создано конструктором Foo(int), а то будет утечка
» памяти

20 return Foo();//сделаем так для простоты
21 }
22
23
24
25 private://Возможно надо заменить private на protected, чтоб дочерний класс мог
» обращаться к полю Foo::i

26 int* i;
27 };
28
29 class Bar: public Foo //добавил public
30 {
31 public:
32 Bar(int j)
33 {
34 i=new char[j];
35 }
36 ~Bar()
37 {
38 delete[] i; //Изменил, добавив []
39 }
40
41 private:
42 char* i;
43 };
44
45
46 int main()
47 {
48 Foo* f=new Foo(100);
49 Foo* b= new Bar(200); //Нужно в классе определить присваивание и чтоб было
» открытое наследование

50 *f=*b; //Нужно в классе определить присваивание
51 delete f;
52 delete b;
53 }



Ах, да, похоже, что надо ещё создать конструктор копирования Foo(const Foo&), надо повозится с глубоким копированием, сделать проверки в операторе присваивания, чета стало лень копать дальше.