`

C# - PInvoke, gotchas on the RegisterClassEx and the CreateWindowEx

阅读更多

I get an exception message like "cannot find window class" with the following code snippet. 


            bool bRet;
            WNDCLASS wc;
            lpszCmdLine = null;
            hInstance = System.Diagnostics.Process.GetCurrentProcess().Handle;
            WNDCLASSEX wndClass = new WNDCLASSEX();
            wndClass.cbSize = Marshal.SizeOf(typeof(WNDCLASSEX));

            string szName =  "HelloWin";
            wndClass.style = (int) (ClassStyles.HorizontalRedraw | ClassStyles.VerticalRedraw);


            wndClass.lpfnWndProc = Marshal.GetFunctionPointerForDelegate((WndProc)((hWnd, message, wParam, lParam) =>
            {
                IntPtr hdc;
                PAINTSTRUCT ps;
                RECT rect;
                switch ((WM)message)
                {
                    case WM.PAINT:
                        hdc = WinAPI.BeginPaint(hWnd, out ps);
                        WinAPI.GetClientRect(hWnd, out rect);
                        WinAPI.DrawText(hdc, "Hello, Windows 98!", -1, ref rect, Win32_DT_Constant.DT_SINGLELINE | Win32_DT_Constant.DT_CENTER | Win32_DT_Constant.DT_VCENTER);
                        WinAPI.EndPaint(hWnd, ref ps);
                        return IntPtr.Zero;
                        break;
                    case WM.DESTROY:
                        WinAPI.PostQuitMessage(0);
                        return IntPtr.Zero;
                        break;
                }

                return WinAPI.DefWindowProc(hWnd, (WM)message, wParam, lParam);
            }
            ));

            wndClass.cbClsExtra = 0;
            wndClass.cbWndExtra = 0;
            wndClass.hInstance = hInstance;
            wndClass.hIcon = WinAPI.LoadIcon(
                IntPtr.Zero, new IntPtr((int)SystemIcons.IDI_APPLICATION));
            //wndClass.hCursor = WinAPI.LoadCursor(IntPtr.Zero, (int)IdcStandardCursor.IDC_ARROW);
            wndClass.hCursor = WinAPI.LoadCursor(IntPtr.Zero, (int)Win32_IDC_Constants.IDC_ARROW);
            wndClass.hbrBackground = WinAPI.GetStockObject(StockObjects.WHITE_BRUSH);
            wndClass.lpszMenuName = null;
            wndClass.lpszClassName = szName;

            //WindowStyleEx.WS_EX_OVERLAPPEDWINDOW
            ushort regResult = (ushort)WinAPI.RegisterClassEx(ref wndClass); // change the varie RegisterClassEx2
            

            if (regResult == 0)
            {
                int lastError = Marshal.GetLastWin32Error();
                string errorMessage = new Win32Exception(lastError).Message;

                WinAPI.MessageBox(IntPtr.Zero, "This program requires windows NT!",
                    szName, (int) MessageBoxOptions.IconError);
            }

            // this varie of CreateWindowEx do no work 
            IntPtr hwnd = WinAPI.CreateWindowEx(
                0,
                szName,
                "The Hello Program",
                WindowStyles.WS_OVERLAPPEDWINDOW,
                Win32_CW_Constant.CW_USEDEFAULT,
                Win32_CW_Constant.CW_USEDEFAULT,
                Win32_CW_Constant.CW_USEDEFAULT,
                Win32_CW_Constant.CW_USEDEFAULT,
                IntPtr.Zero,
                IntPtr.Zero,
                hInstance,
                IntPtr.Zero);

			if (hwnd == IntPtr.Zero)
            {
                int lastError = Marshal.GetLastWin32Error();
                string errorMessage = new Win32Exception(lastError).Message;
            }
			            WinAPI.ShowWindow(hwnd, ShowWindowCommands.Normal);
            WinAPI.UpdateWindow(hwnd);
            WinAPI.UpdateWindow(hwnd);
            MSG msg;
            while (WinAPI.GetMessage(out msg, IntPtr.Zero, 0, 0) != 0)
            {
                WinAPI.TranslateMessage(ref msg);
                WinAPI.DispatchMessage(ref msg);
            }
			
				

 

The error happens at this block of code. 

            if (hwnd == IntPtr.Zero)
            {
                int lastError = Marshal.GetLastWin32Error();
                string errorMessage = new Win32Exception(lastError).Message;
            }

 

Why this is failing, we are creating a WNDCLASSEX, and initialize the ClassName to "HelloWin",  and then we try to create a windows by that name "HelloWin", but it told us that "Cannot find the window class"? why ?

Check on the refernces, and MSDN on the CreateWindowEx function

MSDN 写道
lpClassName [in, optional]
Type: LPCTSTR
A null-terminated string or a class atom created by a previous call to the RegisterClass or RegisterClassEx function. The atom must be in the low-order word of lpClassName; the high-order word must be zero. If lpClassName is a string, it specifies the window class name. The class name can be any name registered with RegisterClass or RegisterClassEx, provided that the module that registers the class is also the module that creates the window. The class name can also be any of the predefined system class names.

 

it seems there is a known issue regarding the null terminated string represented clas name to the CreateWindowEx function, so we SHOULD use the ATOM variant of the CreateWindowEx function. So we will revise the RegisterClassEx and the CreatWindowEx call as such.

UInt16 regRest = WinAPI.RegisterClassEx2(ref wndClass); 

 and 

            IntPtr hwnd = WinAPI.CreateWindowEx2(
                0,
                regRest,
                "The hello proram",
                WindowStyles.WS_OVERLAPPEDWINDOW,
                Win32_CW_Constant.CW_USEDEFAULT,
                Win32_CW_Constant.CW_USEDEFAULT,
                Win32_CW_Constant.CW_USEDEFAULT,
                Win32_CW_Constant.CW_USEDEFAULT,
                IntPtr.Zero,
                IntPtr.Zero,
                hInstance,
                IntPtr.Zero);

 

So, as you can see the result of the RegisterClassEx call - the ATOM value is passed to the CreateWindowEx2 function.. 

In order to support this kind of call, we have to declare variant of the RegisterClassEx or CreateWindowEx as such.

        // To use CreateWindow, just pass 0 as the first argument.
        [DllImport("user32.dll", SetLastError = true, EntryPoint="CreateWindowEx")]
        public static extern IntPtr CreateWindowEx(
           WindowStylesEx dwExStyle,
           string lpClassName,
           string lpWindowName,
           WindowStyles dwStyle,
           int x,
           int y,
           int nWidth,
           int nHeight,
           IntPtr hWndParent,
           IntPtr hMenu,
           IntPtr hInstance,
           IntPtr lpParam);

        // Create a window, but accept a atom value.
        [DllImport("user32.dll", SetLastError = true, EntryPoint="CreateWindowEx")]
        public static extern IntPtr CreateWindowEx2(
           WindowStylesEx dwExStyle,
           UInt16 lpClassName,
           string lpWindowName,
           WindowStyles dwStyle,
           int x,
           int y,
           int nWidth,
           int nHeight,
           IntPtr hWndParent,
           IntPtr hMenu,
           IntPtr hInstance,
           IntPtr lpParam);

 

so we have import the CreateWindowEx method which accepts a String class name just as the CreateWndowEx, and the method which takes ATOM value as the class name and rename it to CreateWindowEx2..

 

and because return type denote a ATOM value, you may have the following RegisterClassEx calls .

        [DllImport("user32.dll")]
        //public static extern short RegisterClassEx([In] ref WNDCLASS lpwcx);
        public static extern short RegisterClassEx([In] ref WNDCLASSEX lpwcx);

        [DllImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassEx")]
        public static extern UInt16 RegisterClassEx2([In] ref WNDCLASSEX lpwcx);

 

An ATOM value is a UInt16 idenfier. The RegisterClassEx2 function has given a  different name RegisterClassEx2.

 

References:

Problems with p/Invoke CreateWindowEx() and RegisterEx()

CreateWindowEx function

 

 

分享到:
评论

相关推荐

    c# 利用C# PInvoke显示系统自带动画资源

    本教程将深入探讨如何利用C#的PInvoke特性来显示系统自带动画资源。 首先,理解PInvoke的概念至关重要。PInvoke是.NET Framework提供的一种机制,允许C#代码调用非托管(即C/C++编写的)动态链接库(DLL)中的函数...

    c#-FFMpeg-AutoGen.zip

    2. **PInvoke 技术**:由于 FFmpeg 主要是用 C/C++ 编写的,为了在 C# 中使用,开发者可能利用 PInvoke(Platform Invoke)技术,通过DllImport特性导入 FFmpeg 的动态链接库(DLL),使得 C# 能够调用 C/C++ 的函数...

    人工智能-项目实践-C#-基于 C# WPF 的 地震预警 软件.zip

    c 使用 ...Vanara.PInvoke.Kernel32: https://github.com/dahall/Vanara SharpGIS.NmeaParser: https://github.com/dotMorten/NmeaParser NAudio: https://github.com/naudio/NAudio GuerrillaNtp

    使用Signature Tool自动生成PInvoke调用Windows API的C#函数声明

    标题中的“使用Signature Tool自动生成PInvoke调用Windows API的C#函数声明”是指一种高效的方法,用于在C#中调用Windows API函数。PInvoke(Platform Invoke)是.NET框架提供的一种机制,允许托管代码(如C#)直接...

    Interop Without PInvoke - Consuming Native Libraries in C#.-StaticLib

    "Interop Without PInvoke - Consuming Native Libraries in C#.-StaticLib" 主题探讨了一种替代方法,即如何在不使用P/Invoke的情况下,在C#中消费静态链接库(StaticLib)。 首先,理解C#中的互操作性(Interop)...

    Interop Without PInvoke - Consuming Native Libraries in C#.-DynamicLib

    "Interop Without PInvoke - Consuming Native Libraries in C#.-DynamicLib"探讨了一种替代方法,即使用C#的动态编程功能来消费本地库,以实现更简洁且灵活的交互。 C#中的`System.Runtime.InteropServices....

    PInvoke Interop Assistant.rar

    标题 "PInvoke Interop Assistant.rar" 暗示了这是一个关于C#与C++之间互操作(Interop)的工具包,特别关注P/Invoke技术。P/Invoke是.NET框架提供的一种机制,允许托管代码(C#)调用非托管代码(通常为C或C++编写...

    C#通过PInvoke调用c++函数的备忘录的实例详解

    目前知道的情况被调用的C/C++函数只能是...PInvoke assistant工具可以辅助生成C#和VB的引入声明,还可以查看常见的常量枚举 能否调用重载的c++函数导出还没有试验,目前找到的信息看还是不行 字符串只支持C里的char* w_

    PInvoke.net官方提供的VS API插件

    标题中的“PInvoke.net官方提供的VS API插件”是指一个专为Visual Studio(VS)设计的插件,它由PInvoke.net网站开发并提供。PInvoke.net是一个知名的资源库,致力于收集、整理和分享有关在.NET Framework中进行平台...

    VS PInvoke插件 RedGate.PInvokeExtension VS平台调用插件 PInvoke.NET 最新 最全

    PInvoke插件 RedGate.PInvokeExtension VS平台调用插件 PInvoke 平台调用 调用C++ 调用系统 C#调C++, Search Module: Directory Constants Delegates Enums Interfaces Structures Desktop ...

    自动生成PInvoke调用Windows API的C#函数声明.rar

    这个压缩包文件“自动生成PInvoke调用Windows API的C#函数声明.rar”提供了一个工具,帮助开发者自动创建必要的PInvoke声明,使得C#能够与Windows API进行交互。PInvoke(Platform Invoke)是.NET框架提供的一种机制...

    Audio Compression Manager pInvoke for C#.NET

    Audio Compression Manager pInvoke for C#.NET Function: acmStreamOpen..... Structure: WAVEFORMATEX....

    RedGate PInvoke Visual Studio 2008 Add-in

    RedGate官方提供的PInvoke Visual Studio Add-in免费插件,只支持vs2003和vs2005,实际上组件也是支持vs2008的,所以我修改了AddIn文件,增加了一个注册表导入文件,方便大家使用。安装源程序,用附件中的...

    CANUSB Library written in C#-开源

    该包装器使用“ PInvoke”(例如peek / poke)来“托管”从托管代码到非托管代码的调用。 听起来很复杂,确实如此。 它也是完全不必要的。 为什么不将DLL作为托管代码? 为什么不简单地在项目中引用该库并仅调用其...

    .netPInvoke逆向调用

    .NET PInvoke逆向调用是.NET Framework提供的一种技术,它允许托管代码(如C#编写的程序)调用非托管代码,通常是操作系统提供的系统API函数。这种技术在处理与硬件交互、利用底层操作系统功能或者使用旧版库时非常...

    C#查找窗口句柄的方法

    - Pinvoke.net: 一个关于P/Invoke签名的在线数据库,可以快速查找和学习API函数的C#实现。 - CodeProject: 包含许多C#与Windows API交互的实例项目和技术文章。 总结,C#查找窗口句柄是通过调用Windows API实现的,...

    PInvoke Interop Assistant.7z

    Microsoft 推出的 P/Invoke Interop Assistant#C/C++ API 转 C# 工具 找资源不易,限定5个积分

    VS自带API查询器

    edit and add PInvoke* signatures, user-defined types, and any other information related to calling Win32 and other unmanaged APIs from managed code (written in languages such as C# or VB.NET). ...

Global site tag (gtag.js) - Google Analytics