Find answers for the most frequently asked questions
Is there any way to get detailed error information for Win32 errors when using Platform Invoke?
Yes, you can use the FormatMessage Win32 API. Sample projects for C# and VB.NET are enclosed. This is how the declaration looks like:
[DllImport(''Kernel32.dll'')]
publicstaticexternintFormatMessage(int flags, IntPtr source, int messageId, int languageId, StringBuilder
buffer, int size, IntPtr arguments );
Called like so:
// You can call FormatMessage to get a descriptive error message
StringBuilder sbFormatMessage = new StringBuilder(1024);
retVal = Interop.FormatMessage(Interop.FORMAT_MESSAGE_FROM_SYSTEM, IntPtr.Zero, Marshal.GetLastWin32Error(), 0, sbFormatMessage,
sbFormatMessage.Capacity, IntPtr.Zero);
We have two suggestions with sample projects how you host a WebBrowser control inside a form and display HTML contents and listen to events such as NavigateComplete or BeforeNavigate. Of course there are many other ways to do this.
Download htmlviewer.zip for two sample projects for the suggestions discussed below.
1) The first suggestion is to generate an ActiveX wrapper for shdocvw using the aximp tool.
The command line for this tool should be as follows:
Now you can reference these dlls in your project and use AxWebBrowser. In the attached HtmlViewer2 sample we have derived a HtmlControl class from AxWebBrowser and added some properties that let you specify a CSS Stylesheet and the Html content as a string.
2) Our second sample lets you bypass the generation of a ActiveX wrapper. You don’t have to include and ship shdocvw.dll and axshdocvw.dll. In the attached HtmlViewer sample, we derived from AxHost and attached our own IWebBrowserEvents interface by overriding the CreateSink, AttachInterfaces and DetachSink methods.
You can use HtmlControl in your form and specify HTML content by assigning a HTML string to HtmlControl. A cascading style sheet can be specified by assigning a path name to the CascadingStyleSheet property. The sample demonstrates how to use a CSS style sheet that has been embedded as a resource in the assembly.
Allen Weng gives the following explanation in a post on the microsoft.public.dotnet.framework.windowsforms newgroup.
If what you are looking for is just to intercept and handle generic Windows messages such as WM_NCPAINT or alike, you can override WndProc (). You don’t need to use the hook procedure. Here is some code that does this:
publicenum WinMsg
{
WM_KEYDOWN = 256,
WM_KEYUP = 257,
WM_PAINT = 15,
WM_CREATE = 1
.......
.......
};
protectedoverridevoidWndProc(ref System.Windows.Forms.Message m)
{
..............
if (m.Msg == (int) WinMsg.WM_PAINT)
{
m.Result = new IntPtr(0); // no further processing is needed.
.......
.......
}
..............
base.WndProc(ref m);
}
But if you need to use a hook procedure, be cautious since they might interfere with normal execution of other applications. In some extreme cases, they might bring the whole system down if not processed correctly. Here is the code snippet that shows you how to do implement and use the hook procedure in .NET:
publicclassWin32Hook
{
[DllImport('kernel32')]
publicstaticexternintGetCurrentThreadId();
[DllImport( 'user32', CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
publicstaticexternintSetWindowsHookEx( HookType idHook,
HOOKPROC lpfn,
int hmod,
int dwThreadId
);
publicenum HookType
{
WH_KEYBOARD = 2
}
publicdelegateintHOOKPROC(int nCode, int wParam, int lParam);
private HOOKPROC hookProc; //private field with class scopepublicvoidSetHook()
{
// set the keyboard hook
hookProc = new HOOKPROC(this.MyKeyboardProc);
SetWindowsHookEx(HookType.WH_KEYBOARD, hookProc, 0,
GetCurrentThreadId());
}
publicintMyKeyboardProc(int nCode, int wParam, int lParam)
{
return0;
}
}
How do I hit a web page from within a button handler in my Windows Forms application
Use the Process class found in the System.Diagnostics namespace.
Process proc = new Process();
proc.StartInfo.UseShellExecute = true;
proc.StartInfo.FileName = @'http://www.microsoft.com';
proc.Start();
// or just put it all as one statement//System.Diagnostics.Process.Start(@'http://www.microsoft.com');
You have to get a handle to the desktop and draw on the desktop. This means that whatever you draw will not be automatically refreshed when another window is dragged over it.
Normally when you make a Form visible by setting the Visible property to true, it will show the form and set the focus too. In some cases however, you do not want it to take focus until the user clicks on it. To get this behavior, do the following utility code:
When you want to show a form without activating it:
UtilFuncs.SetVisibleNoActivate(myForm, true); // true to show.
When you want to hide it:
UtilFuncs.SetVisibleNoActivate(myForm, false); // false to hide.
How do I use an exported function (extern ‘C’) from a legacy DLL
Use the DllImport attribute that is a member of the System.Runtime.InteropServices namespace. Assume your exported function found in MyDLL.dll has a signature:
intMyFunction( LPCTSTR lpCaption, UINT uType);
The code below shows how you can access this function from within C#.
using System;
using System.Runtime.InteropServices;
classHelloWorld
{
[DllImport('mydll.dll')]
publicintMyFunction(string title, int type);
publicstaticvoidMain()
{
int nReturnValue = MyFunction('some string', 14);
}
}
Is there any way to get to the Edit control or the editHandle of a ComboBox using safe code
Bill Zhang (Microsoft) responds to this question in a posting on microsoft.public.dotnet.frameworks.windowsforms newsgroup.
The Frameworks classes use P/Invoke to call the GetWindow API to get the HWND internally - there is no exposed way to dothis. If you wish to get the Win32 HWND, here’s the code to do it, but there is no way to get a
System.Windows.Forms.Edit control fromthis.
[DllImport('user32.dll', ExactSpelling=true, CharSet=CharSet.Auto)]
publicstaticextern IntPtr GetWindow(IntPtr hWnd, int uCmd);
publicconstint GW_CHILD = 5;
if (combo.DropDownStyle != ComboBoxStyle.DropDownList) {
IntPtr hwnd = GetWindow(combo.Handle, NativeMethods.GW_CHILD);
if (hwnd != IntPtr.Zero) {
editHandle = hwnd;
}
}
To maximize the main window, you can get the handle of the main window in the new process, and then send a SC_MAXIMIZE system command message to it. You can get the handle through the Process.MainWindowHandle property. To send a message you should use the DllImportAttribute attribute to import the API function. This is a sample code:
publicclassWinAPI
{
publicconstint WM_SYSCOMMAND = 0x0112;
publicconstint SC_MAXIMIZE = 0xF030;
[DllImportAttribute ('user32.dll')]
publicstaticexternintSendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
}
Process p = new Process();
p.StartInfo.FileName = @'D:\Program Files\test.exe';
p.Start();
WinAPI.SendMessage(p.MainWindowHandle, WinAPI.WM_SYSCOMMAND, WinAPI.SC_MAXIMIZE,0);
How can I capture output from an arbitrary console application from within my Window Form application
Use the Process class found in the System.Diagnostic namespace.
Process proc = new Process();
// test.exe is a console application generated by VC6
proc.StartInfo.FileName = @'C:\test\test.exe';
proc.StartInfo.Arguments = '';
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.Start();
string output = proc.StandardOutput.ReadToEnd();
//output now holds what text.exe would have displayed to the console
Share with