日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【转】CreateWindowEx异常原因汇总

發布時間:2025/5/22 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】CreateWindowEx异常原因汇总 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉自http://blogs.msdn.com/b/dsui_team/archive/2012/11/05/troubleshooting-createwindowex-failures.aspx

四級翻譯水平,歡迎指正。

Several years back, my team was handling multiple issues where Windows Forms application would throw an exception while trying to create a new form, control, etc. While the description string that Windows Forms included in the exception ("Error creating window handle.") indicated that a call to CreateWindowEx failed, the exception did not provide any information on why the call failed. At the time, I wrote a small document that described the steps for debugging native and .NET applications to determine why a given CreateWindowEx call fails. One of my colleagues suggested creating a blog post with the information from that document, so here we go.

?幾年前,我們團隊在開發Windows窗體應用程序的時候,經常在創建一個新的窗體或控件時碰到異常。在調用CreateWindowEx的時候遇到異?!癊rror creating window handle.”表示調用失敗。調用失敗時并沒有提供更多的信息。那時候,我寫了一篇文檔描述調試的步驟,.Net應用導致了調用CreateWindowEx的失敗。我的一位同事建議我把這篇文檔的信息寫到博客上。我們開始吧。

The CreateWindowEx function(CreateWindowEx函數)

We should first discuss how the CreateWindowEx function works before diving into how to troubleshoot CreateWindowEx failures.Windows applications, including .NET applications that use Windows Forms or Windows Presentation Foundation, create their windows by calling the CreateWindowExA or CreateWindowExW functions. Both functions internally call a common USER32 function that will perform some?parameter validation, such as the window styles and handles specified in the call, handle creating a MDI child window if the WS_EX_MDICHILD extended window style is specified and processes the current activation context for the calling thread. If all is well on the USER32-side of the CreateWindowEx call, it then calls into the kernel-mode (WIN32K) implementation of CreateWindowEx.

我們在解決CreateWindowEx創建失敗原因之前先討論該函數的工作原理。Windows應用,包括使用Windows窗體的.Net應用,在創建窗體時都要調用CreateWindowExA或者CreateWindowExW函數。這些函數內部都調用了一個共同的USER32函數使一些參數生效(比如調用中指定的窗體風格和句柄),處理創建一個指明WS_EX_MDICHILD擴展窗體風格的MDI子窗體的創建過程,為調用的線程激活當前的設備環境。如果CreateWindowEx在調用USER32時一切正常,它將調用核心模式(WIN32K)來實現窗體的創建。

The kernel-side of the CreateWindowEx call will first check the following conditions:

CreateWindowEx調用的核心首先要檢查下面幾個條件:

  • Does the specified window class exist??指定的窗口類存在么?
  • Can the text for the atom be retrieved, if the caller specified an atom for the class name?
  • Was a parent window specified, if creating a child window?創建子窗體時,它的父窗體指定了嗎?
  • Will the new window exceed the nested window depth limit, if creating a child window or an owned window? The default limit?is 50 levels deep and can be configured via the USERNestedWindowLimit registry value.在創建子窗口時,嵌套窗口的個數有沒有超過限制?默認深度是50,可以通過USERNestedWindowLimit的注冊表的值來設置。
  • Does the parent/owner window belong to the same desktop as the calling thread?調用線程的父窗口屬于同一個桌面么?

Assuming that each of these checks pass, CreateWindowEx will perform the following tasks when attempting to?create a new window object:

假設這些檢查通過,CreateWindowEx 將會通過以下任務來完成新窗體的創建:

  • Determine if creating a handle for the new window?object will exceed the?User handle quota limit for the calling process.
  • Allocates memory for the new window object from the desktop's heap.在桌面堆中為新窗體分配內存。
  • Initializes the memory for the new window object為新窗體初始化內存。
  • Creates a handle for the new window object in the User handle table為新窗體在用戶句柄表中創建一個句柄。

Assuming that the window object was created successfully, CreateWindowEx will notify registered WinEvent and WH_CBT hooks that a new window object has been created, determine the location, size, z-order position, etc. of the new window, followed by calling the window's WndProc to process WM_NCCREATE and WM_CREATE window messages. CreateWindowEx then returns the handle of the new window object.

?假設窗體已經成功創建,CreateWindowEx將會通知注冊WinEvent和WH_CBT hooks,一個新窗體已經創建完成,決定位置、尺寸,z軸位置等。新窗體將會調用Window的WndProc函數處理WM_NCCREATE和WM_CREATE窗口消息,CreateWindowEx將返回新窗體的句柄。

Causes of CreateWindowEx failures(CreateWindowEx創建失敗的原因)

You may have noticed some of the conditions that will cause CreateWindowEx to fail from the previous section. Let's enumerate conditions that will cause CreateWindowEx to fail:

通過前面的章節你需要注意到引起CreateWindowEx創建失敗的原因。

  • The specified window class does not exist.
  • Using invalid window styles or extended window styles.
  • Using invalid User handles, such as window handles and menu handles.
  • Attempting to create a child window without specifying a parent window.
  • Attempting to create a child window or an owned window and the specified parent/owner belongs to a different desktop than the calling thread.
  • Creating a child or owned window will exceed the nested window limit.
  • Creating a new window object will exceed the handle quota for the calling process.
  • There is insufficient heap available in the desktop’s heap to allocate memory for the new window object.
  • There are no available entries in the User handle table.

Note that while?a new window object is successfully created, the CreateWindowEx function may still return NULL. How can this happed?

Recall that before returning, CreateWindowEx will call the window's WndProc to process a WM_NCCREATE and a WM_CREATE window message. The WndProc can stop the window creation by returning?0 when handling the WM_NCCREATE window message or by returning -1 when handling the WM_CREATE window message. CreateWindowEx handles this situation by destroying the window object and returning NULL.?Additionally, a WH_CBT hook?can stop the window creation by returning 0 from its hook procedure when handling the HCBT_CREATEWND notification.

?

CreateWindowEx failures and GetLastError

The Windows SDK documentation for the CreateWindowEx function states that extended error information can be obtained by calling GetLastError when CreateWindowEx returns NULL. But how useful is the error code returned by GetLastError?

The answer is that it depends on the error condition that caused CreateWindowEx to return NULL.

For example, GetLastError will return ERROR_CANNOT_FIND_WND_CLASS if the window class does not exist. On the other hand, GetLastError may return NOERROR or some error code that seems unrelated to calling CreateWindowEx?if the window's?WndProc stopped the window creation when handling the WM_NCCREATE or WM_CREATE messages.

?

Troubleshooting CreateWindowEx failures

Although GetLastError does not always return a valid error code on a CreateWindowEx failure, you should always check the error code as it may help diagnose the source of the failure. Current versions of the .NET Framework included the value returned by GetLastError when throwing a Win32Exception. Earlier versions of the .NET Framework did not include the error code when throwing?a Win32Exception.

Hitting the User handle quota limit for the process?should be pretty simple to identify. You can view the User object handle count for a process in Task Manager (taskmgr.exe) or by calling the GetGuiResources function. If the handle count is approaching the User handle quota limit, then Task Manager and GetGuiResources is likely reporting a value near the limit. Additionally, GetLastError should return ERROR_NO_MORE_USER_HANDLES. The default limit is 10,000 and can be configured via the USERProcessHandleQuota registry value.

Running out of desktop heap is a little more difficult to identify since there is no mechanism that ships with Windows to measure available desktop heap for a given desktop.?However, GetLastError should return ERROR_NOT_ENOUGH_MEMORY. You can find more information on desktop heap athttp://blogs.msdn.com/b/ntdebugging/archive/2007/01/04/desktop-heap-overview.aspx.

Then there are the scenarios where CreateWindowEx fails and GetLastError returns NOERROR or what appears to be an invalid error code.?Generally, in this scenario, the failure is caused by the window's WndProc stopping the window creation. There are some user-mode?troubleshooting options?that you can use?before you start stepping through the disassembly of the kernel side of the CreateWindowEx function.

One approach is to?set a?WH_CBT window hook on the thread calling CreateWindowEx to determine if a window object has been created for a given CreateWindowEx call. Recall that?WH_CBT hook procedures?are called with the HCBT_CREATEWND notification after?a window object has been created and before the window procedure is called to handle the WM_NCCREATE and WM_CREATE window?messages.

You can then set a WH_CALLWNDPROC window hook on the thread calling CreateWindowEx or set a breakpoint on the window's WndProc (if known)?to determine if the window's WndProc is called to handle the WM_NCCREATE and WM_CREATE window messages. You can also use the Spy++ tool included with Visual Studio to monitor when windows owned by a thread process WM_NCCREATE and WM_CREATE window messages.

?

Debugging CreateWindowEx with WinDBG

I tend to use the Debugging Tools for Windows for most of my debugging work, specifically WinDBG. The debugging tasks described below are from a 32-bit Windows?7 system using the version of WinDBG included with the Windows SDK for Windows?7 and the public Microsoft symbol server.

You may encounter a scenario where you are trying to troubleshoot a CreateWindowEx failure where you do not know the address of the window's WndProc, such as a third-party control. How do you set a breakpoint on the WndProc?

Recall that most of the work for creating a window is done in kernel mode, which includes calling the window's WndProc to process?WM_NCCREATE and WM_CREATE window messages. Since the kernel side of CreateWindowEx tries to call?a user mode function, Windows needs to transition back into user mode to call?the WndProc, which is done via the DispatchClientMessage function.

You can use a breakpoint on CreateWindowEx that enables a breakpoint on DispatchClientMessage and another breakpoint when CreateWindowEx returns that disables the breakpoint on DispatchClientMessage. This should allow you to determine if the window procedure of the window is being called.

Here are breakpoints that I used when debugging an instance of?Notepad:

0:000> bl
?0 e 75934ec3???? 0001 (0001)? 0:**** USER32!DispatchClientMessage ".echo ***** DispatchClientMessage *****;dd @esp+4 L4;g"
?1 e 7592ec7c???? 0001 (0001)? 0:**** USER32!CreateWindowExW ".echo ***** CreateWindowExW called *****;be 0;g"
?2 e 7592ecb0???? 0001 (0001)? 0:**** USER32!CreateWindowExW+0x34 ".echo ***** CreateWindowExW returned *****;bd 0;r @eax;g"

Breakpoint 0 is initially disabled. It will be enabled when CreateWindowEx is called and disabled when CreateWindowEx returns. When hit, the breakpoint will dump the parameters passed to the function and then resume execution. You could also set up the breakpoint to halt in the debugger where you could then step into the window procedure. Note in the debug output below that the last parameter to DispatchClientMessage is the address of the window procedure.

Breakpoint 1 displays a message that CreateWindowEx is being called, tries to display the class name passed to CreateWindowEx (which will fail if an atom is passed) and enables the breakpoint on DispatchClientMessage.

Breakpoint 2 displays a message that CreateWindowEx is returning, displays the value of the handle that it is returning and disables breakpoint 0.

Below is the debugger ouput from the first CreateWindowEx call in the process:

***** CreateWindowExW called *****
***** DispatchClientMessage *****
001bf504? 00b9fc18 00000081 00000000 001bf56c
***** DispatchClientMessage *****
001bf548? 00b9fc18 00000083 00000000 001bf594
***** DispatchClientMessage *****
001bf4d4? 00b9fc18 00000001 00000000 001bf53c
***** DispatchClientMessage *****
001bf554? 00b9fc18 00000005 00000000 00000000
***** DispatchClientMessage *****
001bf554? 00b9fc18 00000003 00000000 00000000
***** CreateWindowExW returned *****
eax=000602fe

Note the window messages that are being received by the window. WM_NCCREATE is 0x81 and WM_CREATE is 0x1. The other messages are also a part of normal window creation.

In the example above, you might have noticed that I skipped how I found the address of the return from CreateWindowEx in order to set breakpoint 2. The method that I used was to examine the disassembly of the CreateWindowExW function and looked for the return instruction, highlighted below.

0:000> u user32!CreateWindowExW L13
USER32!CreateWindowExW:
7592ec7c 8bff??????????? mov???? edi,edi
7592ec7e 55????????????? push??? ebp
7592ec7f 8bec??????????? mov???? ebp,esp
7592ec81 6800000040????? push??? 40000000h
7592ec86 ff7534????????? push??? dword ptr [ebp+34h]
7592ec89 ff7530????????? push??? dword ptr [ebp+30h]
7592ec8c ff752c????????? push??? dword ptr [ebp+2Ch]
7592ec8f ff7528????????? push??? dword ptr [ebp+28h]
7592ec92 ff7524????????? push??? dword ptr [ebp+24h]
7592ec95 ff7520????????? push??? dword ptr [ebp+20h]
7592ec98 ff751c????????? push??? dword ptr [ebp+1Ch]
7592ec9b ff7518????????? push??? dword ptr [ebp+18h]
7592ec9e ff7514????????? push??? dword ptr [ebp+14h]
7592eca1 ff7510????????? push??? dword ptr [ebp+10h]
7592eca4 ff750c????????? push??? dword ptr [ebp+0Ch]
7592eca7 ff7508????????? push??? dword ptr [ebp+8]
7592ecaa e8edfeffff????? call??? USER32!_CreateWindowEx (7592eb9c)
7592ecaf 5d????????????? pop???? ebp
7592ecb0 c23000????????? ret???? 30h

I then use the following syntax to set the breakpoint:

bp2 7592ecb0 ".echo ***** CreateWindowExW returned *****;bd 0;r @eax;g"

Alternately, you can set a conditional breakpoint when CreateWindowEx returns and use the !gle command to dump the value that will be returned by GetLastError if CreateWindowEx fails, where the EAX register is zero. In the scenario below, I created a simple Windows Forms application that repeatedly creates child windows until the User handle process quota is reached and CreateWindowEx fails.

I use the following command to set a conditional breakpoint on the return from CreateWindowExW that breaks in the debugger when the function fails:

bp 7592ecb0? "j (@eax==0) '.echo ***** CreateWindowExW failed. *****';'g'"

Once the debugger breaks on a CreateWindowEx failure, you can obtain the last error value with the !gle command:

0:000> !gle
LastErrorValue: (Win32) 0x486 (1158) - The current process has used all of its system allowance of handles for Window Manager objects.

You can also execute other debugger commands, including .NET debugger extension commands such as !clrstack:

0:000> .loadby sos clr
0:000> !clrstack
OS Thread Id: 0xea4 (0)
Child SP IP?????? Call Site
001ae9c4 7592ecb0 [InlinedCallFrame: 001ae9c4]?
001ae9a8 5e6c50ef DomainBoundILStubClass.IL_STUB_PInvoke(Int32, System.String, System.String, Int32, Int32, Int32, Int32, Int32, System.Runtime.InteropServices.HandleRef, System.Runtime.InteropServices.HandleRef, System.Runtime.InteropServices.HandleRef, System.Object)
001ae9c4 5e6a978c [InlinedCallFrame: 001ae9c4] System.Windows.Forms.UnsafeNativeMethods.IntCreateWindowEx(Int32, System.String, System.String, Int32, Int32, Int32, Int32, Int32, System.Runtime.InteropServices.HandleRef, System.Runtime.InteropServices.HandleRef, System.Runtime.InteropServices.HandleRef, System.Object)
001aea88 5e6a978c System.Windows.Forms.UnsafeNativeMethods.CreateWindowEx(Int32, System.String, System.String, Int32, Int32, Int32, Int32, Int32, System.Runtime.InteropServices.HandleRef, System.Runtime.InteropServices.HandleRef, System.Runtime.InteropServices.HandleRef, System.Object)
001aead0 5e6a8e9f System.Windows.Forms.NativeWindow.CreateHandle(System.Windows.Forms.CreateParams)
001aeb54 5e6a8b82 System.Windows.Forms.Control.CreateHandle()
001aebac 5e6a8921 System.Windows.Forms.Control.CreateControl(Boolean)
001aebe4 5e6a8818 System.Windows.Forms.Control.CreateControl()
001aebfc 5e6b1c31 System.Windows.Forms.Control+ControlCollection.Add(System.Windows.Forms.Control)
001aec38 5e6b1aab System.Windows.Forms.Form+ControlCollection.Add(System.Windows.Forms.Control)
001aec4c 5ef8f027 System.Windows.Forms.Control.set_ParentInternal(System.Windows.Forms.Control)
001aec58 5ebfd59a System.Windows.Forms.Control.set_Parent(System.Windows.Forms.Control)
001aec60 002903c3 WindowsFormsApplication1.Form1.button1_Click(System.Object, System.EventArgs)*** WARNING: Unable to verify checksum for WindowsFormsApplication1.exe
?[D:\Cases\WindowsFormsApplication1\WindowsFormsApplication1\Form1.cs @ 24]
001aec80 5e654507 System.Windows.Forms.Control.OnClick(System.EventArgs)
001aec94 5e656ca2 System.Windows.Forms.Button.OnClick(System.EventArgs)
001aecac 5ec3a480 System.Windows.Forms.Button.OnMouseUp(System.Windows.Forms.MouseEventArgs)
001aecc8 5ec03dd1 System.Windows.Forms.Control.WmMouseUp(System.Windows.Forms.Message ByRef, System.Windows.Forms.MouseButtons, Int32)
001aed5c 5efa6a2f System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message ByRef)
001aed60 5efae391 [InlinedCallFrame: 001aed60]?
001aedb4 5efae391 System.Windows.Forms.ButtonBase.WndProc(System.Windows.Forms.Message ByRef)
001aedf8 5e6c19f8 System.Windows.Forms.Button.WndProc(System.Windows.Forms.Message ByRef)
001aee04 5e6aa393 System.Windows.Forms.Control+ControlNativeWindow.OnMessage(System.Windows.Forms.Message ByRef)
001aee0c 5e6aa311 System.Windows.Forms.Control+ControlNativeWindow.WndProc(System.Windows.Forms.Message ByRef)
001aee20 5e6aa256 System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32, IntPtr, IntPtr)
001aefc4 00840ab8 [InlinedCallFrame: 001aefc4]?
001aefc0 5e6c6c1c DomainBoundILStubClass.IL_STUB_PInvoke(MSG ByRef)
001aefc4 5e6ba99f [InlinedCallFrame: 001aefc4] System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG ByRef)
001af008 5e6ba99f System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr, Int32, Int32)
001af00c 5e6ba5cc [InlinedCallFrame: 001af00c]?
001af0a4 5e6ba5cc System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)
001af0fc 5e6ba421 System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)
001af12c 5e642815 System.Windows.Forms.Application.Run(System.Windows.Forms.Form)
001af140 002900ae WindowsFormsApplication1.Program.Main() [D:\Cases\WindowsFormsApplication1\WindowsFormsApplication1\Program.cs @ 18]
001af370 710d21bb [GCFrame: 001af370]?

Conclusion

Hopefully you will be able to apply some of the techniques described in this post if you find yourself in the situation where you are trying to troubleshoot CreateWindowEx failures in managed and native applications.

轉載于:https://www.cnblogs.com/xingyi7/p/4925870.html

總結

以上是生活随笔為你收集整理的【转】CreateWindowEx异常原因汇总的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 四虎伊人 | 免费在线观看的黄色网址 | 韩国精品视频在线观看 | 国产伦精品一区二区三区视频女 | 精品国产av 无码一区二区三区 | 日韩成人精品视频 | 毛片123| 欧美一区二区在线观看视频 | 成人片黄网站久久久免费 | 国产久操视频 | 国产一二三区精品 | 亚洲一区二区精品在线 | 国产熟妇一区二区三区aⅴ网站 | 色一情一乱一乱一区91av | 亚洲911精品成人18网站 | 影音先锋波多野结衣 | 一级坐爱片| 亚洲妇熟xx妇色黄蜜桃 | 请用你的手指扰乱我吧 | 欧美性受xxxx黒人xyx性爽 | 中文字幕88页| 少妇人妻综合久久中文字幕 | 99在线播放 | 欧美日一区二区三区 | 国产成年人视频网站 | 一区二区久久久 | 日本黄色免费网站 | а√天堂资源官网在线资源 | 日韩av片在线播放 | 黑人3p波多野结衣在线观看 | 天天干导航 | 熊出没之冬日乐翻天免费高清观看 | 青娱乐在线视频免费观看 | 国产亚洲色婷婷久久99精品 | 特级西西www444人体聚色 | 134vcc影院免费观看 | 久久精品视屏 | 日本韩国欧美一区二区 | 亚洲欧美黄色片 | 亚洲国产视频一区二区三区 | 69av一区二区三区 | 欧美黄色一区 | 精品亚洲一区二区三区 | 国产片一区二区三区 | 日韩激情免费 | 国产二区视频 | 国产精品入口久久 | 欧美影视一区二区 | 韩国裸体网站 | 国产精欧美一区二区三区蓝颜男同 | 精品一区二区日韩 | 国产高清自拍视频 | 亚洲精品中文无码AV在线播放 | 欧美久久影院 | 少妇偷人精品无码人妻 | 亚洲五十路 | 一区二区伊人 | 日本亚洲视频 | 韩日视频在线观看 | 搞黄视频在线观看 | 午夜a视频 | 国产xxx| 东京av男人的天堂 | 18成人免费观看网站下载 | 特级一级黄色片 | 日韩一区二区三区网站 | 欧美午夜一区 | 成人性生交大片免费 | 日本在线一 | 亚洲精品一区二区三区四区五区 | 十八岁世界在线观看高清免费韩剧 | 日本三级精品 | 成人片在线免费看 | 在线观看黄网站 | 亚洲狼人色 | 国产1区在线观看 | 中文字幕15页 | 成年人免费网站视频 | 麻豆视频观看 | 91视频在线| 秋霞午夜鲁丝一区二区老狼 | 国产一级一片免费播放 | 熟妇毛片| 非洲黑寡妇性猛交视频 | 动漫一区二区 | 国产二级一片内射视频播放 | 久久国产视频网站 | 国产精品无码av在线播放 | 高清黄色一级片 | 被绑在床强摁做开腿呻吟 | 亚洲无人区码一码二码三码 | 欧美综合一区二区三区 | 久久久精品中文字幕麻豆发布 | 欧美zozo| av一级久久 | 久久久久久日产精品 | 视频精品一区 | 婷婷亚洲精品 | 久久久精品视频在线观看 |