Go geek!

Our Victory Is Imminent

Archiwum kategorii ‘Cpp

[C++] Statyczna metoda klasy jako punkt wejścia aplikacji w C++

Skomentuj »

W tym wpisie chciałem napisać o pewnej właściwości linkera MS – punktem wejścia aplikacji może być dowolna funkcja o odpowiedniej sygnaturze – w tym także statyczna metoda klasy! W przypadku aplikacji okienkowej i wykorzystaniu Unicode odpowiednia sygnatura sygnatura wygląda tak

int __stdcall EntryPt(
     HINSTANCE hInstance, 
     HINSTANCE hPrevInstance,
     WCHAR* lpCmdLine,
     int nCmdShow)

Wystarczy poinformowac o tym linker. W przypadku produktu Microsoftu

link ${OBJS} /SUBSYSTEM:WINDOWS  /ENTRY:EntryPt ${LIBS}

Jak już wspomniałem punktem wejścia może być statyczna metoda klasy

struct WinApp {
     static int __stdcall wWinMain(
          HINSTANCE hInstance, 
          HINSTANCE hPrevInstance,
          WCHAR* lpCmdLine,
          int nCmdShow);
}

Oto mały przykład okienkowej aplikacji Win32 której punktem wejścia jest statyczna metoda metoda klasy

#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

/**
cl -c winapp.cpp

link  winapp.obj /SUBSYSTEM:WINDOWS  /ENTRY:WinApp::wWinMain  kernel32.lib user32.lib gdi32.lib
**/
struct WinApp {
    static int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, WCHAR* lpCmdLine, int nCmdShow);
    static LRESULT __stdcall WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
};



int WINAPI WinApp::wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, WCHAR* lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc = { 
        sizeof(WNDCLASSEX), CS_CLASSDC, WinApp::WndProc, 0L, 0L, 
        GetModuleHandle(NULL), NULL,
        LoadCursor( NULL, IDC_ARROW ), 
        ( HBRUSH )( COLOR_WINDOW ), NULL,
        "WinApp", NULL };
    RegisterClassEx( &wc );
    HWND hWnd = CreateWindow(
        "WinApp",
        "«Jarosław Przygódzki» Statyczna metoda klasy jako punkt wejścia aplikacji w C++",
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 600, 400,
        GetDesktopWindow(), NULL, wc.hInstance, NULL);
    ShowWindow(hWnd, SW_SHOW);
    MSG msg = {0};
    while( GetMessage(&msg, NULL, 0, 0 ))
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }

    return 0;
}

LRESULT __stdcall WinApp::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{
    switch(uMsg) {
        case WM_CLOSE:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0L;
}

Proces kompilacji i linkowania nie jest skomplikowany

cl -c winapp.cpp
link winapp.obj /SUBSYSTEM:WINDOWS /ENTRY:WinApp::wWinMain kernel32.lib user32.lib
PS

CALLBACK i WINAPI to właśnie aliasy na konwencję wywołania __stdcall

// WinDef.h
#define CALLBACK    __stdcall
#define WINAPI      __stdcall

Deklaracje mogą więc wyglądać następująco

struct WinApp {
     static int WINAPI wWinMain(
          HINSTANCE hInstance, 
          HINSTANCE hPrevInstance,
          WCHAR* lpCmdLine,
          int nCmdShow);
    static LRESULT CALLBACK WndProc(
         HWND hWnd,
         UINT uMsg, 
         WPARAM wParam, 
         LPARAM lParam)
}

I najczęściej tak właśnie wyglądają.

Written by Jarek Przygódzki

Styczeń 19, 2010 at 6:46 pm

[C++] Uniwersalny ekstraktor i inserter dla strumieni binarnych

Skomentuj »

#include <istream>
#include <ostream>
template<class T>
std::istream& read(std::istream& is, T& t) {
        is.read((char*)&t, sizeof(T));
        return is;
}

template<class T>
std::ostream& write(std::ostream& os, const T& t) {
		os.write((char*)&t, sizeof(T));
        return os;
}
template<class T>
std::ostream& operator << (std::ostream& os, const T& t) {
	return write<T>(os,t);
}

template<class T>
std::istream& operator >> (std::istream& is, T& t) {
	return read<T>(is,t);
}

I mały przykład
#include <cstring>
#include <fstream>
struct Superheroine {
		Superheroine(const char* name_ = "", const char* publisher_ = "") {
			strcpy(name,  name_);
			strcpy(publisher, publisher_);
		}
        char name[32];
        char publisher[32];
};
//...
std::ofstream ofs;
ofs.open("data.bin", std::ios::out | std::ios::binary | std::ios::trunc);
Superheroine
	silverFox("Silver Fox","Marvel Comics"),
	natashaIrons("Natasha Irons", "DC Comics");
write<Superheroine>(ofs, silverFox); // write<T>
ofs << natashaIrons; // operator << 
ofs.close();
ifs.open("data.bin", std::ios::in | std::ios::binary);
Superheroine heroine;
ifs >> heroine; // operator >> 
// ...
read<Superheroine >(ifs,heroine); // read<T>

Written by Jarek Przygódzki

Grudzień 17, 2009 at 1:37 pm

Napisane w Cpp, Programming

[C++] Użycie freopen do przekierowania standardowych strumieni

Skomentuj »

Za pomocą funkcji

#include <cstdio>
FILE *freopen(const char *filename, const char *mode, FILE *stream);

możemy dokonac przekierowania standardowych strumieni (stdin, stdout, stderr), co w pewnych sytuacjach może byc bardzo pomocne.

freopen("stdout.txt", "w", stdout);
freopen("stderr.txt", "w", stderr);

Written by Jarek Przygódzki

Lipiec 16, 2009 at 6:11 am

Napisane w Cpp, Programming

Tagi:

Właściwości w C++

Skomentuj »

No coż, w standardzie ich po prostu nie ma. Niektóre kompilatory, jak np mój ulubiony MSVC oferują je za pomocą rozszerzeń, inne nie oferują ich wcale. Wspomniany już kompilator MS wspiera je jednak znakomicie.

Składnia jest prosta

__declspec (property (get=nameOfGetFunction, put=nameOfSetFunction)) type propertyName;

np

class Renderer {
private:
     ID3D10Device* m_pDevice;
     ID3D10Device& GetDevice(){ return *m_pDevice;}
public:
     __declspec (property (get=GetDevice)) ID3D10Device& Device;
}

Szablony? Oczywiście.

template<class T>
class vec3 {
public:
    inline T get_x() const { return m_v[0]; }
    inline T get_y() const { return m_v[1]; }
    inline T get_z() const { return m_v[2]; }

    inline void set_x(T value) { m_v[0] = value; }
    inline void set_y(T value) { m_v[1] = value; }
    inline void set_z(T value) { m_v[2] = value; }

    __declspec(property(get=get_x,put=set_x)) T x ;
    __declspec(property(get=get_y,put=set_y)) T y ;
    __declspec(property(get=get_z,put=set_z)) T z ;
private:
    T m_v[3];
}

Właściwości wirtualne?


struct Shape {
     float computeArea()=0;
     __declspec(property(get=computeArea)) float Area;
}

struct Rect :  Shape {
    Rect(float w, float h): m_w(w),m_h(h) {}
    float computeArea() {
        return m_w * m_h;
    }
private:
    float m_w, m_h;
}

struct Circle : Shape {
    Circle(float r) : m_radius(r) {}
    float computArea() {
        return M_PI * m_radius * m_radius;
    }
private:
    float m_radius;
}

//...
Shape& s = *new Circle(1.0f);
float area = s.Area;

Oczywiście, świat nie jest idealny, więc i rozszerzenie kompilatora __declspec(property) nie jest, m.in
właściwości nie mogą być statyczne a i z szablonami nie zawsze wszystko działa.
Jeśli ktoś potrzebuje rozwiązań nie ograniczonych do jednego kompilatora, rozwiazanie stanowi biblioteka STLSoft Properties .

STLSoft Getting Started

MSDN property(C++)

Written by Jarek Przygódzki

Czerwiec 4, 2009 at 12:09 pm

Projektowanie klasy wektora 3D w C++

Skomentuj »

Written by Jarek Przygódzki

Kwiecień 28, 2009 at 1:41 pm

Napisane w Cpp, Programming

Follow

Otrzymuj każdy nowy wpis na swoją skrzynkę e-mail.