Simulate Mouse Event using SendInput and SetCursorPos

public class MouseSimulateForm : Form
{
    private Point _buttonPos = Point.Empty;
    public MouseSimulateForm()
    {
        Button bt = new Button { Text = "SetPos", Location = new Point(20, 20) };
        this.Controls.Add(bt);
        bt.Click += new EventHandler(bt_Click);

        bt = new Button { Text = "Test", Location = new Point(20, 60) };
        this.Controls.Add(bt);
        bt.Click += new EventHandler(test_Click);
    }

    void bt_Click(object sender, EventArgs e)
    {
        if (_buttonPos == Point.Empty)
            _buttonPos = Control.MousePosition;
        else
            MessageBox.Show("SB");
    }

    void test_Click(object sender, EventArgs e)
    {
        //Move the mouse to the button position
        SetCursorPos(_buttonPos.X, _buttonPos.Y);

        //Perform button click.
        INPUT structInput = new INPUT();
        structInput.type = SendInputEventType.InputMouse;
        structInput.mkhi.mi.dwFlags = MouseEventFlags.ABSOLUTE | MouseEventFlags.LEFTDOWN | MouseEventFlags.LEFTUP;
        structInput.mkhi.mi.dx = _buttonPos.X;
        structInput.mkhi.mi.dy = _buttonPos.Y;
        uint i = SendInput(1, ref structInput, Marshal.SizeOf(new INPUT()));
    }

    [DllImport("user32.dll")]
    static extern IntPtr GetMessageExtraInfo();

    [DllImport("user32.dll", SetLastError = true)]
    static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);

    [DllImport("user32.dll")]
    static extern bool SetCursorPos(int X, int Y);

    [Flags]
    public enum MouseEventFlags
    {
        LEFTDOWN = 0x00000002,
        LEFTUP = 0x00000004,
        MIDDLEDOWN = 0x00000020,
        MIDDLEUP = 0x00000040,
        MOVE = 0x00000001,
        ABSOLUTE = 0x00008000,
        RIGHTDOWN = 0x00000008,
        RIGHTUP = 0x00000010
    }

    /// <summary>
    /// The event type contained in the union field
    /// </summary>
    enum SendInputEventType : int
    {
        /// <summary>
        /// Contains Mouse event data
        /// </summary>
        InputMouse,
        /// <summary>
        /// Contains Keyboard event data
        /// </summary>
        InputKeyboard,
        /// <summary>
        /// Contains Hardware event data
        /// </summary>
        InputHardware
    }


    /// <summary>
    /// The mouse data structure
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    struct MouseInputData
    {
        /// <summary>
        /// The x value, if ABSOLUTE is passed in the flag then this is an actual X and Y value
        /// otherwise it is a delta from the last position
        /// </summary>
        public int dx;
        /// <summary>
        /// The y value, if ABSOLUTE is passed in the flag then this is an actual X and Y value
        /// otherwise it is a delta from the last position
        /// </summary>
        public int dy;
        /// <summary>
        /// Wheel event data, X buttons
        /// </summary>
        public uint mouseData;
        /// <summary>
        /// ORable field with the various flags about buttons and nature of event
        /// </summary>
        public MouseEventFlags dwFlags;
        /// <summary>
        /// The timestamp for the event, if zero then the system will provide
        /// </summary>
        public uint time;
        /// <summary>
        /// Additional data obtained by calling app via GetMessageExtraInfo
        /// </summary>
        public IntPtr dwExtraInfo;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct KEYBDINPUT
    {
        public ushort wVk;
        public ushort wScan;
        public uint dwFlags;
        public uint time;
        public IntPtr dwExtraInfo;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct HARDWAREINPUT
    {
        public int uMsg;
        public short wParamL;
        public short wParamH;
    }

    /// <summary>
    /// Captures the union of the three three structures.
    /// </summary>
    [StructLayout(LayoutKind.Explicit)]
    struct MouseKeybdhardwareInputUnion
    {
        /// <summary>
        /// The Mouse Input Data
        /// </summary>
        [FieldOffset(0)]
        public MouseInputData mi;

        /// <summary>
        /// The Keyboard input data
        /// </summary>
        [FieldOffset(0)]
        public KEYBDINPUT ki;

        /// <summary>
        /// The hardware input data
        /// </summary>
        [FieldOffset(0)]
        public HARDWAREINPUT hi;
    }

    /// <summary>
    /// The Data passed to SendInput in an array.
    /// </summary>
    /// <remarks>Contains a union field type specifies what it contains </remarks>
    [StructLayout(LayoutKind.Sequential)]
    struct INPUT
    {
        /// <summary>
        /// The actual data type contained in the union Field
        /// </summary>
        public SendInputEventType type;
        public MouseKeybdhardwareInputUnion mkhi;
    }       
}

Posted in UI | Leave a comment

C# COM Server and C++ COM Client Simple Sample

We need to call managed library in a native project sometimes. One usual method to solve this issue is to create a managed COM and consume it in a C++ project. Below are the detail steps:

1. Create a managed COM:

  1) Create a C# Class Library project.
  2) Change the ComVisible attribute’s value to true. It can be found in AssemblyInfo.cs as following:
        [assembly: ComVisible(true)]
  3) Check the ‘Register for COM interop’ CheckBox in the Build tab page. This will generate a .tlb file and registry the assembly as a COM. The .tlb file will be used in the C++ project later.
  4) Add a file named Calc.cs and fill in it with the code snippet below:

[Guid("F0DF58E5-50AB-40d7-A968-3F42EF6176B9")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ICalc
{
    [DispId(1)] long Factorial(int n);
}

[Guid("56CF9DA5-F899-49cc-B4EA-C7758D2CA8B4")]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(ICalc))]
[ProgId("MyCalc")]
public class Calc : ICalc
{
    long ICalc.Factorial(int n)
    {
        long fact = 1;
        for (int i = 1; i <= n; i++)
            fact *= i;
        return fact;
    }
}

      Attention: The class which implements the COM interface must be public. Otherwise it will generate the warning below and the .tlb file will not contain the information of the class.
      warning MSB3214: "C:\Users\v-shunli\Desktop\COMLib\COMLib\bin\Debug\COMLib.dll" does not contain any types that can be registered for COM Interop.

  5) Build the project to generate the assembly and .tlb file.

2. Create the C++ project which will consume the COM.

  1) Create a C++ console project.
  2) Add the import directive below and rebuild the C++ project:
       #import "../COMLib/bin/Debug/COMLib.tlb" named_guids
  3) Place the code below in the .cpp file which includes the main function:

#include "stdafx.h"
#import "../COMLib/bin/Debug/COMLib.tlb" named_guids
#include <comutil.h>

int _tmain(int argc, _TCHAR* argv[])
{
    CoInitialize(NULL);

    COMLib::ICalcPtr pCalc;

    HRESULT hRes = pCalc.CreateInstance(__uuidof(COMLib::Calc));
    if(FAILED(hRes))
        printf("ICalcPtr::CreateInstance failed w/err 0x%08lx\n", hRes);
    else
    {
        printf("%d\n", pCalc->Factorial(10));
    }

    CoUninitialize();
    return 0;
}

  4) Build and run the C++ project. We will see the factorial of 10 in the console.

References: http://www.codeproject.com/KB/cs/ManagedCOM.aspx

The solution can downloaded from:
http://cid-b5038e2897597982.office.live.com/self.aspx/.Public/COMLib.zip

Posted in COM | Leave a comment

Stream Iterator tutorial

#include <iostream>
#include <iterator>
#include <iomanip>
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include <numeric>
#include <limits>

using namespace std;

int main()
{
    vector<int> numbers;
    cout << "Enter integers:" << endl;

    istream_iterator<int> numbersInput(cin), numbersEnd;    
    while(numbersInput != numbersEnd)
        numbers.push_back(*numbersInput++);

    cout << "The sum of the input integers is:  "
        << accumulate(numbers.begin(),numbers.end(),0) << endl;

    string data("2.4 3.5 6.7 4.0");
    istringstream input(data);
    istream_iterator<double> begin(input), end;
    cout << "The sum of the doubles is:  " 
        << accumulate(begin,end,0.0) << endl;

    cin.clear();
    cin.ignore(numeric_limits<streamsize>::max(), '\n');

    typedef map<string, int>::const_iterator Iter;

    map<string, int> words;
    cout << "Enter some words:" << endl;

    istream_iterator<string> beginning(cin), ending;

    while(beginning != ending)
        words[*beginning++]++;

    cout << endl << "The count of each word is:" << endl;
    for(Iter iter = words.begin(); iter != words.end(); ++iter)
        cout << setw(5) << iter->second << " " << iter->first << endl;

    return 0;
}

Posted in C++ | Leave a comment

Generate Luck Numbers

#include <cstdlib>
#include <iostream>
using namespace std;

int index = 0;
int count = 0;

void AddNumber(char* number, int width)
{    
    ++index;

    if(index > count)
    {
        cout << "Do you want to exit(y or n)?" << endl;
        char c;
        cin >> c;
        if(c == 'y' || c == 'Y')
            exit(0);
    }

    cout << index << ':';
    for(int i = 0; i < width; i++)
        cout << number[i];
    cout << endl;    
}

int main()
{    
    cout << "Please input the total count of numbers need to generate:";
    cin >> count;    
    for(int width = 5;;width++)
    {
        char* number = new char[width];

        //case 1: all the numbers are the same
        for (char d = '1'; d <= '9'; d++)
        {
            for(int i = 0; i < width; i++)
                number[i] = d;
            AddNumber(number,width);            
        }

        //case 2: increment sequence.
        int len = 9 - width + 1;
        for (char start = '1'; start <= '0' + len ; start++)
        {
            for(int i = 0; i < width; i++)
            {
                number[i] = start + i;
            }
            AddNumber(number,width);
        }

        //case 3: decrement sequence.
        for (char start = '9'; start >= '9' - len ; start--)
        {
            for(int i = 0; i < width; i++)
            {
                number[i] = start - i;
            }
            AddNumber(number,width);
        }

        //case 4: the digits except the first are all 0
        for(char start = '1'; start <= '9'; start++)
        {
            number[0] = start;
            for(int i = 1; i < width; i++)
                number[i] = '0';
            AddNumber(number,width);
        }

        delete[] number;
    }

    return 0;
}

Posted in Algorithm | Leave a comment

Cancel Validating while Closing In WinForm

Sometimes, we will show dialogs or MessageBoxes during validation. This cause a side effect: The validation will be done 
when closing the window and the MessageBoxes will be shown before closing. To solve the issue, we can cancel the closing
at first, disable validation and then close the form again.
Protected Overrides Sub OnClosing(ByVal e As System.ComponentModel.CancelEventArgs)
        MyBase.OnClosing(e)

        If Me.CausesValidation Then
            e.Cancel = False
            Me.CausesValidation = False
            Me.Close()
        End If
        
    End Sub

    Private Sub TextBox1_Validating(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles TextBox1.Validating
        MessageBox.Show("alala")
    End Sub

Posted in WinForm | Leave a comment

Traverse Binary Trees in python

from Stack import Stack

#Binary Node definition
class BinaryNode:
    value = None
    leftChild = None
    rightChild = None
    def __init__(self, val, lChild = None, rChild = None):
        self.value = val
        self.leftChild = lChild
        self.rightChild = rChild

class BinaryTree:
    root = None
    def __init__(self,rootNode):
        self.root = rootNode    
    
    @staticmethod
    def _visit(node):
        print node.value

    @staticmethod
    def preorderTraverse(rootNode):
        s = Stack()
        p = rootNode
        while(p or (not s.empty())):
            if p:
                BinaryTree._visit(p)
                if p.rightChild:
                    s.push(p.rightChild)
                p = p.leftChild
            else:
                p = s.pop()

    @staticmethod
    def inorderTraverse(rootNode):
        s = Stack()
        p = rootNode
        while(p or (not s.empty())):
            if p:
                s.push(p)
                p = p.leftChild
            else:
                p = s.pop()
                BinaryTree._visit(p)
                p = p.rightChild

    @staticmethod
    def postorderTraverse(rootNode):
        s = Stack()
        p = rootNode
        lastVisit = None
        s.push(p)
        while(not s.empty()):
            p = s.top()
            #case1: the right child is visited, so left child must be visited
            #case2: left and right child are all null
            #case3: the left child is visited and the right child is null
            if (p.rightChild == lastVisit) \
            or (p.rightChild == None and p.leftChild == None) \
            or (p.rightChild == None and p.leftChild == lastVisit):
                BinaryTree._visit(p)
                lastVisit = p
                s.pop()
            else:
                if(p.rightChild):
                    s.push(p.rightChild)
                if(p.leftChild):
                    s.push(p.leftChild)
                  
    def preorderWalk(self):
        BinaryTree.preorderTraverse(self.root) 

    def inorderWalk(self):
        BinaryTree.inorderTraverse(self.root)

    def postorderWalk(self):
        BinaryTree.postorderTraverse(self.root)

b = BinaryNode(1,BinaryNode(2,BinaryNode(4),BinaryNode(5,BinaryNode(8))), \
BinaryNode(3,BinaryNode(6),BinaryNode(7,None,BinaryNode(9))))

t = BinaryTree(b)
print "preorder"
t.preorderWalk()

print "inorder"
t.inorderWalk()

print "postorder"
t.postorderWalk()


Posted in Algorithm | Leave a comment

Walk all the subdirectories and files of a directory top down and calculate its total size in python

import os,sys

#file system manager class
class FileSystem:

    @staticmethod
    def _printItem(name,depth):
        print '\t' * depth, name

    #list the child directories and files recursively
    @staticmethod
    def listAll(itemPath = "C:", depth = 0):
        #print the item
        FileSystem._printItem(os.path.basename(itemPath),depth)
        #if it is a directory, traverse recursively
        if(os.path.isdir(itemPath)):            
            for l in os.listdir(itemPath):
                fullpath = os.path.join(itemPath,l)
                FileSystem.listAll(fullpath, depth + 1)
    
    @staticmethod
    def _printItemSize(itemName, itemSize, depth):
        print('%s%s(%d)' % ('\t'*depth, itemName, itemSize))

    #calculate the total size of the directory and show the details if isShown is true
    @staticmethod
    def size(itemPath = "C:", isShown = True, depth = 0):
        #initialize the size of the item
        totalSize = os.path.getsize(itemPath)
        #show the detail if it needs to show
        if(isShown):
            FileSystem._printItemSize(os.path.basename(itemPath),totalSize,depth)

        #if it is a directory, traverse recursively
        if(os.path.isdir(itemPath)):
            for l in os.listdir(itemPath):
                fullpath = os.path.join(itemPath,l)
                totalSize += FileSystem.size(fullpath, isShown, depth + 1)
        #return the total size
        return totalSize


dirName = raw_input("Type a directory:")
FileSystem.listAll(dirName,0)
size = FileSystem.size(dirName)
print('The total size is %d.' % size)

Posted in Algorithm | Leave a comment

My Win32 Simple Graphic Framework

I have built a simple Graphic Framework using Win32 API functions. The framework includes a common dialog which is all the parent class of all the drawing window. It has a OnPaintBackground and OnPaint method which can be overridden to draw custom things. Below is the detail code snippets.

The basic base class
BasicDialog.h:

#pragma once

#include <Windows.h>
#include <WinUser.h>
#include <map>
#include "resource.h"

class CBasicDialog
{
public:
    CBasicDialog(HWND hParent, LPCTSTR lpTemplate = NULL);
    virtual ~CBasicDialog(void);
    
    static void Init(HINSTANCE instance);
    static void Release();
    static CBasicDialog* GetCurrentDialog();

    void Show();

protected:
    virtual LRESULT DialogProc(
        HWND hwnd,
        UINT uMsg,
        WPARAM wParam,
        LPARAM lParam);

    virtual void InitDialog();

    virtual void OnResize();

    virtual void OnPaintBackground(HDC dc);
    virtual void OnPaint(HDC dc);

    COLORREF m_cBackColor;
    HWND m_hWnd;
    RECT m_rClientRectangle;
private:
    static LRESULT CALLBACK WinProc(HWND hwnd,
        UINT uMsg,
        WPARAM wParam,
        LPARAM lParam);
    static const COLORREF WHITE_COLOR = RGB(255,255,255);

    static std::map<HWND,CBasicDialog*> Dialogs;
    static CBasicDialog* CurrentDialog;

    static HINSTANCE HInstance;
};


BasicDialog.cpp:

#include "BasicDialog.h"


CBasicDialog::CBasicDialog(HWND hParent, LPCTSTR lpTemplate) : m_cBackColor(RGB(255, 0, 0))
{
    if(HInstance)
    {
        if(lpTemplate == NULL)
            lpTemplate = MAKEINTRESOURCE(IDD_DIALOG_BASIC);

        m_hWnd = CreateDialog(HInstance,lpTemplate, hParent, (DLGPROC)WinProc);

        if(GetWindowRect(m_hWnd, &m_rClientRectangle))
        {
            m_rClientRectangle.left = 0;
            m_rClientRectangle.right = 0;
            m_rClientRectangle.top = 0;
            m_rClientRectangle.bottom = 0;
        }

        if(m_hWnd && NULL == CurrentDialog)
        {
            CurrentDialog = this;
            Dialogs[m_hWnd] = this;
        }
    }    
}


CBasicDialog::~CBasicDialog(void)
{

}

void CBasicDialog::Show()
{
    ShowWindow(m_hWnd, SW_SHOW);
    UpdateWindow(m_hWnd);
}

void CBasicDialog::InitDialog()
{
    //Do something here to initialize the dialog
}

void CBasicDialog::OnResize()
{
    //Do something here to adjust the layout.
}

LRESULT CBasicDialog::DialogProc(
    HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam)
{
    switch(uMsg)
    {    
    case WM_INITDIALOG:
        this->InitDialog();
        break;;
    case WM_SHOWWINDOW:
        GetWindowRect(m_hWnd, &m_rClientRectangle);
        break;
    case WM_SIZE:    
        GetWindowRect(m_hWnd, &m_rClientRectangle);
        this->OnResize();
        break;
    case WM_ERASEBKGND:
        RedrawWindow(m_hWnd, NULL, NULL, RDW_INVALIDATE);
        break;
    case WM_MOVE:
        GetWindowRect(m_hWnd, &m_rClientRectangle);
        break;
    case WM_PAINT:
        if(m_hWnd)
        {
            PAINTSTRUCT ps;
            HDC dc = BeginPaint(m_hWnd,&ps);
            this->OnPaintBackground(dc);
            this->OnPaint(dc);
            EndPaint(m_hWnd,&ps);
        }
        break;
    case WM_CLOSE:
        if(m_hWnd)
        {
            CloseWindow(m_hWnd);
        }
        break;
    default:
        break;
    }

    return FALSE;
}

void CBasicDialog::OnPaintBackground(HDC dc)
{
    //Draw custom background here
}

void CBasicDialog::OnPaint(HDC dc)
{
    //Draw some custom graphics here
}

HINSTANCE CBasicDialog::HInstance = NULL;
CBasicDialog* CBasicDialog::CurrentDialog = NULL;
std::map<HWND,CBasicDialog*> CBasicDialog::Dialogs;

CBasicDialog* CBasicDialog::GetCurrentDialog()
{
    return CurrentDialog;
}

LRESULT CALLBACK CBasicDialog::WinProc(HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam)
{
    if(uMsg == WM_ACTIVATE && wParam == WA_ACTIVE)
        CurrentDialog = Dialogs[hwnd];

    if(CurrentDialog)
    {
        CurrentDialog->DialogProc(hwnd, uMsg, wParam, lParam);
    }

    return FALSE;
}

void CBasicDialog::Init(HINSTANCE instance)
{
    HInstance = instance;
}
void CBasicDialog::Release()
{
}

 

A simple child class
MyDialog.h

#pragma once

#include "basicdialog.h"

class CMyDialog :
    public CBasicDialog
{
public:
    CMyDialog(HWND hParent, LPCTSTR lpTemplate = NULL);
    virtual ~CMyDialog(void);

protected:

    virtual void OnPaintBackground(HDC dc);
    virtual void OnPaint(HDC dc);
};



MyDialog.cpp:

#include "MyDialog.h"


CMyDialog::CMyDialog(HWND hParent, LPCTSTR lpTemplate) : CBasicDialog(hParent,lpTemplate)
{
}


CMyDialog::~CMyDialog(void)
{
}

void CMyDialog::OnPaintBackground(HDC dc)
{
    RECT r;
    r.left = r.top = 0;
    r.right = m_rClientRectangle.right - m_rClientRectangle.left;
    r.bottom = m_rClientRectangle.bottom - m_rClientRectangle.top;

    HBRUSH hBackBrush = CreateSolidBrush(m_cBackColor);
    FillRect(dc, &r, hBackBrush);
    DeleteObject(hBackBrush);
}

void CMyDialog::OnPaint(HDC dc)
{
    //Do some custom painting here.
    HPEN hPen, hPenOld;
    HBRUSH hBrush, hBrushOld;

    //Initial colors
    BYTE bRed = 0;
    BYTE bGreen = 0;
    BYTE bBlue = 0;

    //Pen color
    COLORREF cPen = RGB(bRed, bGreen, bBlue);
    //Set the brush color based on the pen color. It is purple partial to blue.
    COLORREF cBrush = RGB(233,GetGValue(cPen), 255);
    //Create the pen.
    hPen = CreatePen(PS_SOLID, 10, cPen);
    //Create the brush.
    hBrush = CreateSolidBrush(cBrush);
    //Select the pen and brush. Just like set the drawing arguments.
    hPenOld = (HPEN)SelectObject(dc, hPen);
    hBrushOld = (HBRUSH)SelectObject(dc, hBrush);

    //Draw a triangle
    MoveToEx(dc, 30, 10, NULL);
    LineTo(dc, 10, 50);
    LineTo(dc, 50, 50);
    LineTo(dc, 30, 10);
    //Use the old pen
    SelectObject(dc,hPenOld);
    //Draw and fill an ellipse
    Ellipse(dc, 10, 60, 110, 160);

    //Release the resources
    DeleteObject(hPen);
    SelectObject(dc, hBrushOld);
    DeleteObject(hBrush);
}

Testing code and the main function

main.cpp:

#include "MyDialog.h"

BOOL InitApplication(HINSTANCE hInstance);

BOOL InitMainWindow(HINSTANCE hInstance, HWND* pWnd);

LRESULT CALLBACK MainWindowProc(HWND hwnd,
    UINT uMsg,WPARAM wParam,LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR    lpCmdLine,
    int       nCmdShow)
{
    HWND mainWindow;
    if(!InitApplication(hInstance))
        return FALSE;

    if(!InitMainWindow(hInstance, &mainWindow))
        return FALSE;

    ShowWindow(mainWindow,nCmdShow);
    UpdateWindow(mainWindow);

    CBasicDialog::Init(hInstance);
    CMyDialog mainDialog(mainWindow);
    mainDialog.Show();

    MSG msg;
    BOOL fGotMessage;

    while((fGotMessage = GetMessage(&msg, NULL, 0, 0)) != 0 && fGotMessage != -1)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    CBasicDialog::Release();

    return msg.wParam;
}

BOOL InitApplication(HINSTANCE hInstance)
{
    WNDCLASSEX wcx;

    wcx.cbSize = sizeof(wcx);
    wcx.style = CS_HREDRAW | CS_VREDRAW;
    wcx.lpfnWndProc = MainWindowProc;
    wcx.cbClsExtra = 0;
    wcx.cbWndExtra = 0;
    wcx.hInstance = hInstance;
    wcx.hIcon = LoadIcon(NULL,MAKEINTRESOURCE(IDI_ICON_MAIN_WINDOW));
    wcx.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_NODROP));
    wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wcx.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
    wcx.lpszClassName = L"MainClass";
    wcx.hIconSm = (HICON)LoadImage(hInstance,
        MAKEINTRESOURCE(IDI_ICON_MAIN_WINDOW),
        IMAGE_ICON,
        GetSystemMetrics(SM_CXSMICON),
        GetSystemMetrics(SM_CYSMICON),
        LR_DEFAULTCOLOR);

    return RegisterClassEx(&wcx);
}

BOOL InitMainWindow(HINSTANCE hInstance, HWND* pWnd)
{
    HWND hwnd;

    hwnd = CreateWindow(
        TEXT("MainClass"),
        TEXT("Main Window"),
        WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUPWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        800,
        600,
        NULL,
        LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU1)),
        hInstance,
        NULL);

    *pWnd = hwnd;

    if(!hwnd)
        return FALSE;

    return TRUE;
}

LRESULT CALLBACK MainWindowProc(HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_CREATE:
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        break;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

Posted in C++ | Leave a comment

Modify Control without Refreshing

(tableLayoutPanel1 as ISupportInitialize).BeginInit();
tableLayoutPanel1.SuspendLayout();
//modify a control
tableLayoutPanel1.ResumeLayout();
(tableLayoutPanel1 as ISupportInitialize).EndInit();

Posted in WinForm | Leave a comment

Develop OpenGL with EditPlus and g++

There are so many packages including g++ compiler. Since I often play with regular expressions with perl, so I choose Strawberry perl as the develop environment. This package includes g++ compiler, c++ and  OpenGL header files and the corresponding libraries. You could download it from:
http://strawberryperl.com/

After installation, we can add the directory including g++ compiler to the path environment variable. Then we are able to compile a c++ source code in command line.

With all these done, we can start to configure the EditPlus to support OpenGl developing:
1. Open the preference dialog by select menu: Tools –> Configure User Tools…
2. Select Group 1 and click the Group Name button and type ‘C++’.
3. Click the ‘Add Tool >>’ button and type ‘Run’ as the ‘Menu Text’ of the tool.
4. Set Command to ‘$(FileNameNoExt).exe’ and Initial directory to ‘$(FileDir)’.
5. Click the ‘Add Tool >>’ button again and type ‘g++ opengl’ as the ‘Menu Text’ of the tool.
6. Set Command to ‘g++’ and Argument to ‘$(FileName) -o $(FileNameNoExt).exe -lglut32 -lglu32 -lopengl32 -lwinmm -lgdi32’, Initial directory is still ‘$(FileDir)’.

Then we can write a OpenGl program to test as following:

#include <windows.h>
#define GLUT_DISABLE_ATEXIT_HACK
#include <GL/glut.h>

void init2D(float r, float g, float b)
{
    glClearColor(r,g,b,0.0);  
    glMatrixMode (GL_PROJECTION);
    gluOrtho2D (0.0, 200.0, 0.0, 150.0);
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0, 0.0, 0.0);

    //draw two points
    glBegin(GL_POINTS);
    for(int i = 0; i < 10; i++)
    {
        glVertex2i(10+5*i,110);
    }
    glEnd();

    //draw a line
    glBegin(GL_LINES);
        glVertex2i(10,10);
        glVertex2i(100,100);
    glEnd();

    glFlush();
}

int main(int argc,char *argv[])
{
    glutInit(&argc,argv);
    glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize (500, 500);
    glutInitWindowPosition (100, 100);
    glutCreateWindow ("points and lines");
    init2D(0.0,0.0,0.0);
    glutDisplayFunc(display);
    glutMainLoop();

    return 0;
}

 

Comment 1: The following macros should be placed before the glut including, otherwise the glut will not be linked correctly:
    #include <windows.h>
    #define GLUT_DISABLE_ATEXIT_HACK

Comment 2: If you do not use glut, you can add a –mwindows option to the gcc command. This will cause the generated executable not show a command window.

Comment 3: Some dlls might need to be copied to the same directory as the executable file, such as opengl32.dll. This is unnecessary on my machine.

Posted in OpenGL | Leave a comment