dotnet调用win32 API创建窗口

  • 标准的win32窗口程序

相信熟悉windows编程的朋友,对于使用win32 api开发窗口应用程序一定不陌生。 下面的程序是从资源文件中加载一个图片并显示在窗口中。

#include <windows.h>
#include "resource.h"

TCHAR szClassName[] = TEXT("WIN32TEST");
HBITMAP hBmp;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{

case WM_NCHITTEST:

return HTCAPTION;

case WM_LBUTTONDOWN:

break;

case WM_PAINT:

hdc = BeginPaint (hWnd, &ps);

if (hBmp)

{

BITMAP bm;

GetObject(hBmp, sizeof(bm), &bm);

HDC memdc = CreateCompatibleDC(NULL);

HBITMAP h = (HBITMAP)SelectObject(memdc, hBmp);

BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, memdc, 0, 0, SRCCOPY);

SelectObject(memdc, h);

}

EndPaint (hWnd, &ps);

break;

case WM_KEYDOWN:

if (wParam != VK_ESCAPE)

break;

case WM_DESTROY:

PostQuitMessage(0);

break;

default:

return (DefWindowProc(hWnd, message, wParam, lParam));

}
return (0);
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
WNDCLASS wc;
HWND hWnd;
MSG msg;
hBmp = :oadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP2));
if (hBmp)
{

ZeroMemory(&wc, sizeof(wc));

wc.style         = CS_HREDRAW | CS_VREDRAW;

wc.lpszClassName = szClassName;

wc.lpfnWndProc   = (WNDPROC)WndProc;

wc.hInstance     = hInstance;

if (RegisterClass(&wc))

{

BITMAP bm;

GetObject(hBmp, sizeof(bm), &bm);

hWnd = CreateWindow(szClassName, NULL, WS_POPUP, 0, 0, bm.bmWidth, bm.bmHeight, NULL, NULL, hInstance, NULL);

if (hWnd)

{

ShowWindow(hWnd, nCmdShow);

UpdateWindow(hWnd);

// Main message loop:

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

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return (msg.wParam);

}

}

}
return -1;
}
如何将上边这个程序改写成dotNET呢,只需要照猫画虎把这段代码转换成dotNET就可以了。
需要了解的知识点:
Win32中的名柄(如:HWND,HDC, HINSTANCE)等等在dotnet都用IntPtr来表示。
窗口回调函数
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 使用dotnet中的代理来解决
delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
需要事先声明的结构可以在 www.pinvoke.net网站中查询一下,复制过来即可。

2. 我们用到的几个主要结构

Win32 dotNET
typedef struct tagBITMAP
  {
    LONG        bmType;
    LONG        bmWidth;
    LONG        bmHeight;
    LONG        bmWidthBytes;
    WORD        bmPlanes;
    WORD        bmBitsPixel;
    LPVOID      bmBits;
  }
internal struct BITMAP
        {
            public int bmType;
            public int bmWidth;
            public int bmHeight;
            public int bmWidthBytes;
            public ushort bmPlanes;
            public ushort bmBitsPixel;
            public IntPtr bmBits;
        }
typedef struct tagPAINTSTRUCT {
    HDC         hdc;
    BOOL        fErase;
    RECT        rcPaint;
    BOOL        fRestore;
    BOOL        fIncUpdate;
    BYTE        rgbReserved[32];
}
internal struct PAINTSTRUCT
        {
            public IntPtr hdc;
            public bool fErase;
            public UnsafeNativeMethods.RECT rcPaint;
            public bool fRestore;
            public bool fIncUpdate;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
            public byte[] rgbReserved;
        }

struct tagWNDCLASSEXW {
    UINT        cbSize;
    /* Win 3.x */
    UINT        style;
    WNDPROC     lpfnWndProc;
    int         cbClsExtra;
    int         cbWndExtra;
    HINSTANCE   hInstance;
    HICON       hIcon;
    HCURSOR     hCursor;
    HBRUSH      hbrBackground;
    LPCWSTR     lpszMenuName;
    LPCWSTR     lpszClassName;
    /* Win 4.0 */
    HICON       hIconSm;
}

internal struct WNDCLASSEX
        {
            public uint cbSize;
            public uint style;
            public UnsafeNativeMethods.WndProc lpfnWndProc;
            public int cbClsExtra;
            public int cbWndExtra;
            public IntPtr hInstance;
            public IntPtr hIcon;
            public IntPtr hCursor;
            public IntPtr hbrBackground;
            public string lpszMenuName;
            public string lpszClassName;
            public IntPtr hIconSm;
        }




3.在vs2008中创建 wpf 应用程序,然后将自动生成的代码都删除掉。
4. 新建一个类Win32Methods,将需要用的win32 API函数在此声明。
5. 新建类Win32IndotNET类,在此实现与上面列出标准win32的实现。

声明回调函数、名柄、图片的资源ID等等。
public class Win32IndotNET
{
    //回调窗口
    private Win32Methods.WndProc wndProcCallback;
    private IntPtr hInst = IntPtr.Zero;
    private int resID;
    private IntPtr hBmp = IntPtr.Zero;
private Win32Methods.BITMAP bm;

}
在构造函数中初始化窗口回调。
public Win32IndotNET(Module module, int resID)
    {
        hInst = Marshal.GetHINSTANCE(module);
        this.resID = resID;
        this.wndProcCallback = new Win32Methods.WndProc(this.WindowProcedure);
    }

创建窗口并显示
public void CreateWindow()
    {
        IntPtr hWnd;
        hBmp = Win32Methods.LoadBitmap(hInst, new IntPtr(resID));
        if (hBmp != IntPtr.Zero)
        {
            Win32Methods.WNDCLASSEX lpwcx = new Win32Methods.WNDCLASSEX();
            lpwcx.cbSize = (uint)Marshal.SizeOf(typeof(Win32Methods.WNDCLASSEX));
            lpwcx.cbClsExtra = 0;
            lpwcx.cbWndExtra = 0;
            lpwcx.hbrBackground = IntPtr.Zero;
            lpwcx.hCursor = IntPtr.Zero;
            lpwcx.hIcon = IntPtr.Zero;
            lpwcx.hIconSm = IntPtr.Zero;
            lpwcx.hInstance = hInst;
            lpwcx.lpfnWndProc = this.wndProcCallback;
            lpwcx.lpszClassName = "MyWin";
            lpwcx.lpszMenuName = null;
            lpwcx.style = 0;
            if (Win32Methods.RegisterClassExW(ref lpwcx) != 0)
            {
                int cb = Marshal.SizeOf(typeof(Win32Methods.BITMAP));
                IntPtr lpvObject = Marshal.AllocCoTaskMem(cb);
                Win32Methods.GetObject(hBmp, cb, lpvObject);
                bm = (Win32Methods.BITMAP)Marshal.PtrToStructure(lpvObject, typeof(Win32Methods.BITMAP));
                Marshal.FreeCoTaskMem(lpvObject);

                hWnd = Win32Methods.CreateWindowEx(0, "MyWin", "", Win32Methods.WS_POPUP, 0, 0, bm.bmWidth, bm.bmHeight, IntPtr.Zero, IntPtr.Zero, hInst, IntPtr.Zero);
                if (hWnd != IntPtr.Zero)
                {
                    Win32Methods.ShowWindow(hWnd, Win32Methods.SW_SHOW);
                    Thread thread = new Thread(new ThreadStart(this.ThreadMethod));
                    thread.IsBackground = true;
                    thread.Start();
                }
            }
        }
    }

消息循环
private void ThreadMethod()
    {
        MSG msg = new MSG();
        while (Win32Methods.GetMessage(ref msg, IntPtr.Zero, 0, 0) > 0)
        {
            Win32Methods.TranslateMessage(ref msg);
            Win32Methods.DispatchMessage(ref msg);
        }

        GC.KeepAlive(this);
    }

窗口回调函数
在WM_PAINT消息中将图片绘制到窗口
ESC键即出处理
窗口拖动处理
private IntPtr WindowProcedure(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
    {
        switch (msg)
        {
            case Win32Methods.WM_PAINT:
                {
                    Win32Methods.PAINTSTRUCT lpPaint = new Win32Methods.PAINTSTRUCT();
                    IntPtr hdc = Win32Methods.BeginPaint(hWnd, out lpPaint);

                    if (hBmp != IntPtr.Zero)
                    {

                        IntPtr ptr = Win32Methods.CreateCompatibleDC(hdc);
                        IntPtr hgdiobj = Win32Methods.SelectObject(ptr, this.hBmp);
                        Win32Methods.BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, ptr, 0, 0, Win32Methods.SRCCOPY);
                        Win32Methods.SelectObject(ptr, hgdiobj);
                        Win32Methods.DeleteDC(ptr);

                    }

                    Win32Methods.EndPaint(hWnd, ref lpPaint);
                    return IntPtr.Zero;
                }
            case Win32Methods.WM_NCHITTEST:
                {
                    return new IntPtr(Win32Methods.HTCAPTION);
                }

            case Win32Methods.WM_KEYDOWN:
                {
                    if (wParam.ToInt32() == 0x1B)
                        Win32Methods.PostQuitMessage(0);
                }
                break;

        }
        return Win32Methods.DefWindowProc(hWnd, msg, wParam, lParam);
    }

6. 创建启动代码
static void Main(string[] args)
        {
            Win32IndotNET win32 = new Win32IndotNET(typeof(App).Module, 2008);
            win32.CreateWindow();
            new Application().Run();
        }

7.创建资源文件
使用记事本创建 resource.rc文件,内容如下:

2008    BITMAP    "pic.bmp"

(Pic.bmp 和 resource.rc 在同一目录)

在命令行窗口使用 rc 命令编译资源文件 生成 .res文件。

rc.exe resource.rc

右键单击项目属性在Resource File 中指定编译好的 res文件。

8. 生成并运行。


一般dotNET的程序运行时第一次加载的时候会很慢,所以可以利用win32api来制作启动屏幕是一个不错的选择。

程序代码下载http://dev.mjxy.cn/a-dotnet-call-the-win32-API-to-create-a-window.aspx


posted @ 2011-07-12 00:45  敏捷学院  阅读(643)  评论(1编辑  收藏  举报