您的位置:首页 > 其它

WinForm:怎么创建一个Form的

2008-09-14 10:54 267 查看
又是新生入学,想起去年毕业后也是差不多这个时候开始学习WinForm

从刚开始的拖拉控件照抄DEMO,到后来的学习别人的源码,到后来的参与项目,到后来修改别人的BUG,到后来指导新生开始学习WinForm

在这个标签里,我也记录一下自已得到的一些C、C++的知识吧,或者C相比于C#来说,更能让我们明白创建一个WINDOWS程序

 

先来一个经典的例子:创建一个窗体(代码源自于windows程序设计)

WINFORM是:

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

}

}

Application.Run(new Form1());

 

而经典C++呢?

#include <windows.h>

#include "sysmets.c"

 

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
  //是不是也感觉这个函数名很熟。。。。。。。

 

int WINAPI WinMain(HINSTANCE
hInstance,HINSTANCE hPrevinstance,PSTR szCmdLine,int iCmdShow)

{

static TCHAR szAppName[]
=TEXT("HelloWin");

HWND hwnd;

MSG msg;

WNDCLASS wndClass;   //以下,是创建一个窗体的属性,这在孙鑫老师的教程里就已详细的描述

wndClass.style=CS_HREDRAW|CS_VREDRAW;

wndClass.lpfnWndProc=WndProc;

wndClass.cbClsExtra=0;

wndClass.cbWndExtra=0;

wndClass.hInstance=hInstance;

wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);

wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);

wndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);

wndClass.lpszMenuName=NULL;

wndClass.lpszClassName=szAppName;

//注册一个窗体内

if(!RegisterClass(&wndClass))

{

MessageBox(NULL,TEXT("This program
requires windows NT!"),szAppName,MB_ICONERROR);

return 0;

}

//成功后则可以分配内存了。。。。

hwnd =CreateWindow(szAppName,  
//window class name

TEXT("The Hello Program"),
   //window caption

WS_OVERLAPPEDWINDOW,      
   //Window style

CW_USEDEFAULT,        
       //INITIAL X Position

CW_USEDEFAULT,        
       //INITIAL X Position

CW_USEDEFAULT,        
       //INITIAL X Position

CW_USEDEFAULT,        
       //INITIAL X Position

NULL,          
              //Parent window handle

NULL,          
              //window menu handle

NULL,          
         // program instance handle

NULL          
               //creaion parameters

);

//接着就是ShowWindow,是不是可以理解相当于我们一句new Form,则是C#帮我们做了以上的事情

//而此时才是.show()

ShowWindow(hwnd,iCmdShow);

UpdateWindow(hwnd);

//接下来这一段,则是在C#里未曾见过的,老的WIN32
CODER应该很熟,这里也即是WINDOWS的消息循环机制,除非是退出,否则GetMessage永选返回大于0的数

while(GetMessage(&msg,NULL,0,0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hwnd,UINT
message,WPARAM wParam,LPARAM LParam)

{

static int cxChar,cxCaps,cyChar;

int i;

PAINTSTRUCT ps;

TCHAR szBuffer[10];

TEXTMETRIC tm;

HDC hdc;

//PAINTSTRUCT ps;

RECT  rect;

 

switch(message)

{

case WM_CREATE:

PlaySound(TEXT("helloWin.wav"),NULL,SND_FILENAME|SND_ASYNC);

hdc=GetDC(hwnd);

GetTextMetrics(hdc,&tm);    
                 //调用系统,获取默认字体

cxChar=tm.tmAveCharWidth;

cyChar=tm.tmHeight+tm.tmExternalLeading;
     //将高度包括间距,还有宽度保存起来

ReleaseDC(hwnd,hdc);

return 0;

case WM_PAINT:

hdc=BeginPaint(hwnd,&ps);

GetClientRect(hwnd,&rect);

DrawText(hdc,TEXT("Hello,windows
98"),-1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);

EndPaint(hwnd,&ps);

return 0;

case WM_DESTROY:

PostQuitMessage(0);  此时才是返回0

return 0;

}

return
DefWindowProc(hwnd,message,wParam,LParam);

}

这是一个很简单的窗体,代码源于windows程序设计第五版,在这里,你是否感觉C#的方便呢,帮我们做了太多事,这C80行代码==c#2行,可却让我们有的新手迷茫起来?或许你也问过这问题.为什么两行代码就可以做SHOW一个窗体了,创建一个窗体必须要有什么,通过上面的一些API函数,你应该清楚了点吧啦。。。

在刘小石 BLUEDOG先生的博客中有这么一段:

仔细来看看到底在Application.Run中发生了什么?

public static void Run(Form
mainForm){

      Application.ThreadContext.FromCurrent().RunMessageLoop(-1, new ApplicationContext(mainForm));}

可以看到实际上调用了Application内部定义的类ThreadContext的RunMessageLoop方法,而ApplicationContext是有关应用程序线程的上下文信息,而RunMessageLoop调用了下面的内部方法:

private void RunMessageLoopInner(int reason, ApplicationContext
context)

这个函数很长,我们只列出其中有关的部分(代码有删节)

if (reason == -1)

{

   this.applicationContext = context;

   this.applicationContext.ThreadExit += new EventHandler(this.OnAppThreadExit);

   if (this.applicationContext.MainForm != null)

   { 

this.applicationContext.MainForm.Visible = true; 

}

}

if (context != null)

{

    this.currentForm = context.MainForm;

}

 

try

{

 

flag2 = this.LocalModalMessageLoop(this.currentForm);      
}

}

finally



   
        this.Dispose(); 

}

可以看到它完成了两个部分,一是将窗体设为可见,另一个是呼叫LocalModalMessageLoop,嗯,好象有那么点意思了。是不是对应了经典程序中的ShowWindow和消息泵呀,那我们再看看LocalModalMessageLoop是不是起到了消息泵的作用呢,还是来看源码。

bool flag2 = true;

while (flag2)

{

UnsafeNativeMethods.GetMessageW(out msg1, NativeMethods.NullHandleRef, 0,
0);//还有一些判断代码

{

   
UnsafeNativeMethods.TranslateMessage(out msg1);

   
UnsafeNativeMethods.DispatchMessageW(ref msg1);

}

}

同样上面的代码是一个小部分,但是关键部分,清楚地看到跟原来的处理方式是一样的。需要说明的是实际上CLR考虑了在非Unicode的Windows系统上调用不同的函数如DispatchMessageA之类的。

 

到此,咱们完全可以看出,Windows编程原理都是一致的,无论是C#
WINFOR还是c++。再把基础好好把握下吧。。。。。。

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: