The code in this article is intended for educational purposes only. This program will create a very simple window that just says "Hello" but it does using just the Windows GUI API in C#. It does not use Windows Presentation Foundation or even Windows Forms; it only uses the "System" library of classes that is the default library for and required by C# . The program is a very simple C# program that introduces the basics of what a Windows programmer would do to write a Windows API program without .Net.
This article assumes you understand Platform Invoke (DllImport) and how to use it including how to convert a C header #include Windows API function definition to a DllImport. I provide the complete source code but you need to understand DllImport. I intend to use this sample program for future articles about the Windows API. Understanding the Windows API might help you if you are doing things like creating a User Control for WPF or Windows Forms. I assume that very little or none of this is useful for Windows Store (Windows 8) programming.
For the purpose of creating a project to start with, we will create a Windows Forms application however we will remove the form and everything related to it. I will assume you know how to create a Windows Forms application. Create the project then delete the form.
Next, in the references, you can delete all the references except the one for "system.dll". Deleting the references is not a requirement but it shows that we are not using anything except the system.dll part of .Net. Similarly, in the "Program.cs" file you can remove the "using" statements at the beginning of the file, except you can keep the "using System;".
Then add a using for InteropServices, as in "using System.Runtime.InteropServices;". Then delete the three lines in the "Main" function. We will replace the code in the "Main" function with code that does the following:
Use the following code for the "Main" function:
- Win32.MSG Msg = new Win32.MSG();
- int rv;
- if (Program.RegisterClass() == 0)
- return;
- if (Program.Create() == 0)
- return;
- // Main message loop:
- while ((rv = Win32.GetMessage(out Msg, IntPtr.Zero, 0, 0)) > 0)
- {
- Win32.TranslateMessage(ref Msg);
- Win32.DispatchMessage(ref Msg);
- }
- static string Hello = "Hello"; // Text to be drawn
- static string AppName = "DrawHello Program";
- static string ClassName = "DrawHelloClass";
- static IntPtr hWnd; // window handle
Then we need to add three methods to the Program class. First add the following method:
- public int RegisterClass()
- {
- Win32.WNDCLASSEX wcex = new Win32.WNDCLASSEX();
- wcex.style = Win32.ClassStyles.DoubleClicks;
- wcex.cbSize = (uint)Marshal.SizeOf(wcex);
- wcex.lpfnWndProc = WndProc;
- wcex.cbClsExtra = 0;
- wcex.cbWndExtra = 0;
- wcex.hIcon = Win32.LoadIcon(IntPtr.Zero, (IntPtr)Win32.IDI_APPLICATION);
- wcex.hCursor = Win32.LoadCursor(IntPtr.Zero, (int)Win32.IDC_ARROW);
- wcex.hIconSm = IntPtr.Zero;
- wcex.hbrBackground = (IntPtr)(Win32.COLOR_WINDOW + 1);
- wcex.lpszMenuName = null;
- wcex.lpszClassName = m_ClassName;
- if (Win32.RegisterClassEx(ref wcex) == 0)
- {
- Win32.MessageBox(IntPtr.Zero, "RegisterClassEx failed", m_AppName,
- (int)(Win32.MB_OK | Win32.MB_ICONEXCLAMATION | Win32.MB_SETFOREGROUND));
- return (0);
- }
- return (1);
- }
- Window Styles
- Window Procedure (extremely important)
- Icons
- Cursor
- Background Brush
- Menu
- Class name
All that is put into a WNDCLASSEX structure and then the Windows API function RegisterClassEx is called with that. The Window Styles, Window Procedure, Menu, Class Name and Background Brush will be explained in future articles.
Then add the following method:
- public int Create()
- {
- int usedefault = 250;
- m_hWnd = Win32.CreateWindowEx(0, m_ClassName, m_AppName, Win32.WS_OVERLAPPEDWINDOW | Win32.WS_VISIBLE,
- usedefault, usedefault, usedefault, usedefault, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
- if (m_hWnd != IntPtr.Zero)
- return (1);
- Win32.MessageBox(IntPtr.Zero, "CreateWindow failed", m_AppName,
- (int)(Win32.MB_OK | Win32.MB_ICONEXCLAMATION | Win32.MB_SETFOREGROUND));
- return (0);
- }
That function calls the Windows API function CreateWindowEx to create the window. Then add the following function, which is the last function to be added:
- private static IntPtr WndProc(IntPtr hWnd, uint message, IntPtr wParam, IntPtr lParam)
- {
- switch (message)
- {
- case Win32.WM_PAINT:
- {
- IntPtr hDC;
- Win32.PAINTSTRUCT ps = new Win32.PAINTSTRUCT();
- hDC = Win32.BeginPaint(hWnd, out ps);
- Win32.TextOut(hDC, 0, 0, Program.Hello, Program.Hello.Length);
- Win32.EndPaint(hWnd, ref ps);
- return IntPtr.Zero;
- }
- case Win32.WM_DESTROY:
- Win32.PostQuitMessage(0);
- return IntPtr.Zero;
- default:
- return (Win32.DefWindowProc(hWnd, message, wParam, lParam));
- }
- }
The WndProc method is very important, it is what is commonly called the Wndows Procedure. It processes the messages sent to the window. In this Wndows Procedure, only two messages are processsed; a paint message and a destroy message. For all other messages, the procedure just calls the Windows API function DefWindowProc to allow Windows to do default processing of the message. When a paint message is received, the Windows API function TextOut is called to write the text in Program.Hello to the window. The Windows API functions BeginPaint and EndPaint are called first and last, respectively, to process the paint message. All of this will be further explained in future articles.

Hashim ShafiqPosted Aug 21, 2015, 10:14 PM
Nice
asdf fdsaPosted Apr 8, 2015, 9:39 AM
Thanks :)