C#: Don’t display the startup form.
Something that often seems to be a problem with beginning C# developers is the display of the initial form. Normally one would always want the startup form to be displayed as soon as possible–but sometimes the application lives in the tray, or should not initially display a window.
One may first think that an event in System.Windows.Forms.Form can be handled, and the form may be directed to Hide. Unfortunately, this won’t work as expected, the Form will always get the SW_SHOW message when Application.Run() is executed.
When creating a new project, Visual Studio will generate a Program.cs which looks similar to the following:
namespace CamOn { static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } }
When Application.Run is invoked with a Form parameter, it will create and show the window. The easiest way to override this behavior is to simply not call Application.Run with the form:
namespace CamOn { static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); new Form1(); Application.Run(); } } }
Form1 will still be created and pump messages – but it won’t initially be shown.
What is P/Invoke (PInvoke)?
P/Invoke, or Pinvoke stands for Platform Invocation Services. PInvoke is a feature of the Microsoft .NET Frameowrk that allows a developer to make calls to native code inside Dynamic Link Libraries (DLL’s). When Pinvoking, the .NET framework (or Common Language Routine) will load the DLL and handle the type conversions automatically. The most common use of P/Invoke is to use a feature of Windows that is only contained in the Win32 API. The API in Windows is extremely extensive and only some of the features are encapsulated in .NET libraries. For example, Form.Show(); is really a wrapper for the ShowWindow() API found in shell32.dll.
ShowWindow Declaration API for C#:
[DllImport("user32.dll")] static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
Note the use of the DllImport attribute. This attribute, coupled with extern tells the .NET CLR where it can find the native declaration for ShowWindow. shell32.dll must be registered on the system for this to work properly.
Note: Remember import the System.Runtime.InteropServices namespace! This is where the [DLLImport] attribute is found.
using System.Runtime.InteropServices;
How are P/Invoked methods called?
Methods that are loaded in using DLLImport are Pinvoked by simply treating them as native .NET functions, and calling them as you would call any other. Win32 API do tend to use data types that are not used often in .NET, for example – the IntPtr datatype, which is actually a pointer to an integer–in this case, a Window Handle. nCmdShow is an integer that represents the show command. But what values of nCmdShow mean what? These can either be found on MSDN, or PInvoke.net.
C# Constants for ShowWindow in shell32.dll:
const int SW_HIDE = 0; const int SW_SHOWNORMAL = 1; const int SW_NORMAL = 1; const int SW_SHOWMINIMIZED = 2; const int SW_SHOWMAXIMIZED = 3; const int SW_MAXIMIZE = 3; const int SW_SHOWNOACTIVATE = 4; const int SW_SHOW = 5; const int SW_MINIMIZE = 6; const int SW_SHOWMINNOACTIVE = 7; const int SW_SHOWNA = 8; const int SW_RESTORE = 9; const int SW_SHOWDEFAULT = 10; const int SW_FORCEMINIMIZE = 11; const int SW_MAX = 11;
These constants can be used to call ShowWindow(). So in our origional example of Form.Show(), the P/Invoked way of doing this would be:
ShowWindow(Form.Handle, SW_SHOW);
This isn’t nearly as clean as the Object-Oriented way of using Form.Show(), but this is what is actually happening under the hood of .NET.
Why would I ever want something so overly complicated?
ShowWindow is an example of an API that has been wrapped nicely by the .NET CLR, it is unlikely that you will ever need to import and call it. But something more useful might be: Deleting a file to the recycle bin.
What resources are out there for PInvoking?
The best resource I have found is PInvoke.net, which has declarations for both VB.NET and C# for commonly used Win32 API.
