{"id":104518,"date":"2020-12-07T07:00:00","date_gmt":"2020-12-07T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104518"},"modified":"2020-12-07T08:52:38","modified_gmt":"2020-12-07T16:52:38","slug":"20201207-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20201207-00\/?p=104518","title":{"rendered":"Why does CreateWindowEx take the extended style parameter as its first parameter instead of its last?"},"content":{"rendered":"<p>Windows 3.0 expanded the <code>Create\u00adWindow<\/code> function by adding a new extended style parameter, resulting in the <code>Create\u00adWindow\u00adEx<\/code> function. You would expect that the new parameter would go at the end of the parameter list, but that&#8217;s not where it ended up. Instead, it became a bonus <i>first<\/i> parameter.<\/p>\n<table class=\"cp3\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>\n<pre>CreateWindow(\r\n\r\n   lpszClass,\r\n   lpszName,\r\n   dwStyle,\r\n   x,\r\n   y,\r\n   cx,\r\n   cy,\r\n   hwndParent,\r\n   hMenu,\r\n   hInstance,\r\n   lpCreateParams\r\n);\r\n<\/pre>\n<\/td>\n<td>\n<pre>CreateWindowEx(\r\n   dwExStyle,\r\n   lpszClass,\r\n   lpszName,\r\n   dwStyle,\r\n   x,\r\n   y,\r\n   cx,\r\n   cy,\r\n   hwndParent,\r\n   hMenu,\r\n   hInstance,\r\n   lpCreateParams\r\n);\r\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Why did the extra parameter go at the start rather than at the end?<\/p>\n<p>If you&#8217;re familiar with the <code>__stdcall<\/code> calling convention, you would know that the parameters are pushed onto the stack from right to left. Adding a new parameter to the front would therefore permit the old function to forward to the new function by inserting an extra parameter on the stack:<\/p>\n<pre>CreateWindow:\r\n    pop     eax             ; pop return address\r\n    push    0               ; dwExStyle\r\n    push    eax             ; restore return address\r\n    jmp     CreateWindowEx  ; continue as if CreateWindowEx\r\n<\/pre>\n<p>However, this theory doesn&#8217;t hold up because Windows 3.0 used the 16-bit Pascal calling convention, which pushes parameters from left to right.<\/p>\n<p>But you&#8217;re close. The calling convention does play a role.<\/p>\n<p>The other half of the puzzle is the in the <code>lParam<\/code> of the <code>WM_<code><\/code>NCCREATE<\/code> and <code>WM_<code><\/code>CREATE<\/code> messages. That parameter is a pointer to a <code>CREATESTRUCT<\/code> structure, which originally looked like this:<\/p>\n<pre>struct tagCREATESTRUCT {\r\n  LPVOID    lpCreateParams;\r\n  HINSTANCE hInstance;\r\n  HMENU     hMenu;\r\n  HWND      hwndParent;\r\n  int       cy;\r\n  int       cx;\r\n  int       y;\r\n  int       x;\r\n  LONG      style;\r\n  LPCSTR    lpszName;\r\n  LPCSTR    lpszClass;\r\n} CREATESTRUCT;\r\n<\/pre>\n<p>Look familiar?<\/p>\n<p>It&#8217;s the parameter list of the <code>Create\u00adWindow<\/code> function, but <i>backward<\/i>.<\/p>\n<p>Why is it backward?<\/p>\n<p>Since the Pascal calling convention pushes parameters from left to right, it means that the first parameter has the highest address, and the last parameter has the lowest address. If you take all the parameters and treat them as a structure, they end up in reverse order.<\/p>\n<p>And that&#8217;s the missing link.<\/p>\n<p>Back in the days of 16-bit Windows, the <code>CREATESTRUCT<\/code> that was passed to the <code>WM_<code><\/code>NCCREATE<\/code> and <code>WM_<code><\/code>CREATE<\/code> messages was just a pointer to the &#8220;structure&#8221; on the stack formed by all of the parameters.<\/p>\n<p>For backward compatibility, the new <code>dwExStyle<\/code> structure member needs to go to the end, so that old code which understood the old structure would have all the old data at the old offsets.<\/p>\n<pre>struct tagCREATESTRUCT {\r\n  LPVOID    lpCreateParams;\r\n  HINSTANCE hInstance;\r\n  HMENU     hMenu;\r\n  HWND      hwndParent;\r\n  int       cy;\r\n  int       cx;\r\n  int       y;\r\n  int       x;\r\n  LONG      style;\r\n  LPCSTR    lpszName;\r\n  LPCSTR    lpszClass;\r\n  DWORD     dwExStyle; \/\/ Now with extended style support!\r\n} CREATESTRUCT;\r\n<\/pre>\n<p>Backward compatibility dictates that the new structure member goes at the end, which means that the corresponding new parameter must go at the beginning.<\/p>\n<p>It&#8217;s another example of the lengths that 16-bit Windows went in order to run in a very memory-constrained system.<\/p>\n<p><b>Bonus chatter<\/b>: This means that converting a classic <code>Create\u00adWindow<\/code> to the new <code>Create\u00adWindow\u00adEx<\/code> is not a simply matter of inserting a new parameter under the return address. The return address plus all of the existing parameters need to be popped off, the new parameter inserted, and then all the parameters and return address pushed back on. Alternatively, the code could simply have pushed another frame onto the stack:<\/p>\n<pre>HWND CreateWindow(\r\n   LPCSTR lpszClass,\r\n   LPCSTR lpszName,\r\n   DWORD dwStyle,\r\n   int x,\r\n   int y,\r\n   int cx,\r\n   int cy,\r\n   HWND hwndParent,\r\n   HMENU hMenu,\r\n   HINSTANCE hInstance,\r\n   LPVOID lpCreateParams)\r\n{\r\n  return CreateWindowEx(\r\n   0,\r\n   lpszClass,\r\n   lpszName,\r\n   dwStyle,\r\n   x,\r\n   y,\r\n   cx,\r\n   cy,\r\n   hwndParent,\r\n   hMenu,\r\n   hInstance,\r\n   lpCreateParams);\r\n}\r\n<\/pre>\n<p>The code chose to do the &#8220;pop, insert, push&#8221; because the C wrapper function to push a new frame was 59 bytes long, whereas the pop\/insert\/push mechanism, written in hand-tuned assembly, was faster and consumed <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20190827-00\/?p=102809\"> only 32 bytes<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It sure looks like a strange place to add a new parameter.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[2],"class_list":["post-104518","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>It sure looks like a strange place to add a new parameter.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104518","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=104518"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104518\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=104518"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104518"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104518"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}