We help IT Professionals succeed at work.

how to pass argument with CreateWindow

TheMadManiac asked
Medium Priority
Last Modified: 2016-11-10

I,m trying to pass a pointer along with the CreateWindow function, to initialize some data.

this whould be possible, and i thought the lParam was for that... but when i put a pointer in there, the CREATEDATA->lpCreateParams in the LPARAM of the WM_CREATE message point to garble...

well, my app. hangs because of this.

Can someone give me an example how to do this? I read that in NT4 this is done a bit differently?

os: NT4
compiler: VC++ 5.0
weird stuff: no MFC/OWL etc


Watch Question

Pass a pointer to the data in the last parameter.  (Not a pointer to a pointer to the data, however.)

In the WM_CREATE message the long parameter points to a CREATESTRUCT.  The lpCreateParams specifies the pointer (or other value you passed).

Example coming.

struct WndInitialData
// stuff.

 WndInitialData *IniDat = {//stuff };

CreateWindow(... IniDat);

*  *  *  *  *  *

   WndInitalData *IniDat = (WndInitalData *) CrtStrPtr->lpCreateParams;


Post sample code/questions if more help is needed.


thanks nietod...

so i'm not insane.. phew.

that's almost exactly what i did:

char string[100];

// assign something to string here with strcpy or something


char *str=(char *)cs->lpCreateParams;

// do something with str...
// uuh, error.. str = not string :(

the only thing different is that i don't use a struct, and i tell the compiler to give the address of a char array, instead of a pointer to a char array (which is the same)

i really don't know what i'm doing wrong here... difference between win95 & NT ?
Tommy HuiEngineer

If your char string[100] is declared inside of a function, then you will need to put static in front of it to move it from the stack (which gets cleaned every time this function is entered and exited), to the global data area. So change that statement to

  static char string[100];

Actually, I don't think thui is right.  (although it makes me nervous to dissagree with him.)  The WM_CREATE message is sent (not posted) from within the createwindow() procedure, so it should be processed before the CreateWindow(0 procedure returns, this the string can be stored on the stack.  Furthermore, "static" might not be the best way to fix the problem.  It would not work well if the procedure is called recursively as window creation procedures often are.

Actually, I think the problem might be what I hinted at originilly.  I think you are passing a pointer to a pointer, not just a pointer.  
Your sample code is a little messy, but I'll extract and "fix" the appropriate lines.  (Hopefully, not creating a problem that was not there)  You have:

char string[100];

"string " is already a pointer, sort of.  arrays and pointers are pretty much the same (in C).  That is "string" is a pointer to the first element of an array.  So when you take the address with "&" you are passing a pointer to a pointer.  Try


nietod's solution is right on this one. The Win32 SDK docs for CreateWindow specifically state:

"Before returning, CreateWindow sends a WM_CREATE message to the window procedure."

SendMessage processes the message before it returns, thus the stack variable string will be valid when the WM_CREATE handler is called.

and if you have
char string[100];
&string returns a char **, not a char *

Thanks, anichini.  
Tommy HuiEngineer

The documentation is wrong. There are at least 2 other messages that occur before WM_CREATE gets sent to the window proc: WM_NCCALCSIZE and WM_NCCREATE. The way to figure this out is to create a WNDPROC and print everything to a file and you'll see there are about 3 messages (I forgot the other one) that occur before WM_CREATE. So the WndProc doesn't get called only once during the creation process.

Tommy HuiEngineer

The sequence that gets sent to a wndproc:

Msg = 0x00000024 (WM_GETMINMAXINFO)
Msg = 0x00000081 (WM_NCCREATE)
Msg = 0x00000083 (WM_NCCALCSIZE)
Msg = 0x00000001 (WM_CREATE)


sorry if the sample code was messy :)

but, i tried everything,

 1 : making static            //nothing
 2 :(LPARAM)&string[0]        //nothing
 3 :(LPARAM)string            //nothing
 4 :(LPARAM)&string           //nothing
 5 : any combination of these // nothing
 6 : all of these under windows '95

these all yield the same result... string does not get passed correctly.

why is it always me with strange results.. it's driving me nutters :$

There is a difference between Windows NT and Windows 95 as the CREATESTRUCT is concerned. In Windows NT, lpCreateParams does not point directly to your data, but to an area to a SHORT (16-bit) value specifying the size in bytes of your data, immediately followed by your data. I'm including below the reference for CREATESTRUCT so that you can see what I'm talking about:

The CREATESTRUCT structure defines the initialization parameters passed to the window procedure of an application.
typedef struct tagCREATESTRUCT { // cs
    LPVOID    lpCreateParams;
    HINSTANCE hInstance;
    HMENU     hMenu;
    HWND      hwndParent;
    int       cy;
    int       cx;
    int       y;
    int       x;
    LONG      style;
    LPCTSTR   lpszName;
    LPCTSTR   lpszClass;
    DWORD     dwExStyle;
Points to data to be used for creating the window.
Windows NT: This member is the address of a SHORT (16_bit) value that specifies the size, in bytes, of the window creation data. The value is immediately followed by the creation data. For more information, see the following Remarks section.
Identifies the module that owns the new window.
Identifies the menu to be used by the new window.
Identifies the parent window, if the window is a child window. If the window is owned, this member identifies the owner window. If the window is not a child or owned window, this member is NULL.
Specifies the height of the new window, in pixels.
Specifies the width of the new window, in pixels.
Specifies the y-coordinate of the upper left corner of the new window. If the new window is a child window, coordinates are relative to the parent window. Otherwise, the coordinates are relative to the screen origin.
Specifies the x-coordinate of the upper left corner of the new window. If the new window is a child window, coordinates are relative to the parent window. Otherwise, the coordinates are relative to the screen origin.
Specifies the style for the new window.
Points to a null-terminated string that specifies the name of the new window.
Points to a null-terminated string that specifies the class name of the new window.
Specifies the extended style for the new window.
Windows NT: Referring to the lpCreateParams member of the CREATESTRUCT structure, because the pointer may not be DWORD aligned, an application should access the data using a pointer that has been declared using the UNALIGNED type, as shown in the following example:
typedef struct tagMyData {
    . . .;      // define creation data here
typedef struct tagMyDlgData {
    SHORT    cbExtra;
    MYDATA  myData;
    (PMYDLGDATA) (((LPCREATESTRUCT) lParam)->lpcreateParams);
See Also
CreateWindow, CreateWindowEx


Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts

to thui:

Yes, other messages are being sent by Createwindow() (and the exact messages change depending on the window being created.)  However the point I was making is that the WM_CREATE is always called from within the CreateWindow() call, so it can always access the local variables of the procedure that called CreateWindow().  My software works this way without a problem (in that area in any case).

To TheMadManiac (or can I just call you mad):

There is hope, I do this and I suspect that 90% of the windows programs out there do it.  You are just doing something a little wrong.  Try to fix the code the way I suggested and then, if it doesn't work, post it again.  

Another thing you could do is test a simpler case.  Rather than passing a pointer, pass a constant you would recognize and then look at the WM_CREATE message and see if the constant is in the lpCreateParams.

Just a note, since the data passed by the pointer is local data, you cannot "keep" the pointer.  The WM_CREATE handler can look at the data and use it, but not retain it forever.  If it needs to keep the data, it must copy it.

One other point.  Are you sure the problem is in the WM_CREATE message handler.  i.e. you are not getting a crash and assuming the problem is there or something right?  For example, there are messages that occur before the WM_CREATE.  If your code tries to use the data that will set by WM_CREATE, but hasn't been set yet...  I have a good way out of this (I've been there) if this is the problem.

The order is kinda weird here because FabMan and I were commenting/answering at the same time.

FabMan, seems to be right.  For some reason the SDK documentation has two entries for CREATESTRUCT.  They are almost word for word identical, but one mentions this and the other does not.  I think this must be a 16/32 bit issue.  My 16 bit program that uses this works fine on NT and win95 and there is no code to treat the two differently.  My 32 bit program has not been tested on NT--yet.

Does the API provide a way to access the parameter you want?  i.e. is there an API procedure that does the work of determining what operating system and then getting to the data.  That would be a good idea.  If not (To Mr. Maniac) you might want to write one to try to localize the logic.  I intend to.

I should mention.  That the points I made are still correct.  You don't want to pass a pointer to a pointer and the data (if local) cannot be "kept".   Just add to this FabMan's points on how to get the data.

nietod is right on his last comment. When you declare an array in C (such as char string[100]), you are creating an r-value pointer that already points to an area of 100 items. So you don't want to pass a pointer to that pointer (&string).


What a great response to my humble question.

I tried heaps of things, including the NT specific:

typedef struct
  SHORT cbExtra;  // size ??? should be 4 me thinks
  char *str;      // a char * to a name or something

Well, the result was ( i literally copied/pasted the online help, so no typo's or pointer errors etc) that the 'str' contained the NAME of the window.. which was NOT what i passed with the lParam.

Then, i tried to (sneaky me) use the title-part to pass along the string i needed in my creation. Well, when it was NOT static, the result was that lpzsName in the CREATESTRUCT pointed to garbish, while when i made it static it worked ok.. This would mean that the WM_CREATE is executed after the calling function is finished?

So now i use the title to pass along my string, and manually change it in the WM_CREATE message (which would be done anyways).

Not a very beautifull solution, but it works! AND this also should work on win '95, so no strange incompatible stuff when i try it under windows '95

btw, you can just call me Floris (which is my name) or mad (which is shorter :P) or maddy or whatever

And the application did not hang when i just threw away all that argument passing code.

And of course nietod is right about the pointer stuff.. but after doing a lot of things to make something work, you'll try about anything ..hehe

so in the end:

thui was right about the static part
nietod was probably right about everything nietod spoke, but somehow didn't work with me
Fabman was also quite right with his NT explanation, but again, this didn't work with me

well, problem not really solved, but at least i don't have to use a global variable anymore to initialize some data in the WM_CREATE message :) only thing now is i can't really change the title in the CreateWindow function, but i don't really mind.

A whole lot of thanks to all who helped me, and i'll just answer the question orso.. i dunno..

As remarked in the quoted section I previously sent to you, you might be using DWORD alignment for your application. This means that when trying to access a field next to the SHORT size, there might be problems. That is probably the reason why things didn't work for you. You have to make sure your structure is WORD aligned to properly access your data.
And it's your data that'll be next to the SHORT size field. A way to access it could be:

typedef struct
SHORT cbExtra;
char c[100]; // the first character of data

Later on, after retrieving the above structure, you would recover your string somewhat like this:

name UNALIGNED* lpName = (name UNALIGNED *)(((LPCREATESTRUCT) lParam)->lpcreateParams);

char *str = &(lpName->c);

Or something like that...

Oops! In the above comment, change:

char *str = &(lpName->c);


char *str = lpName->c;
That not the good way to use createwindow, because you lose all income messages before wn_create
To get all message and forward them to you currently created class you must use the thread local storage (tls) with C
and with C++ you can declare a static TLS variable as _declspect(thread) MyClass* myCurrentCreatedClass;

With TLS you have a thread storage that ensure you never get conflict if you plan having a multithreaded application, else in
single thread app you can use a normal static without TLS

In your create window proc, instance you have to write :

MyClass::Create() {
       myCurrentCreatedClass = this;
       this->myHWnd = CreateWindow(blablabla);

In your static proc (you can have a static class proc also, but here it is global fonction) :

LRESULT myStaticProc(...) {
   MyClass*  myClass;

   if(myCurrentCreatedClass != NULL) { //you test if the current calling thread has set the class instance pointer
        myClass = myCurrentCreatedClass;
        myCurrentCreatedClass = NULL;
        SetWindowLongPtr(hWnd, GWL_WNDEXTRA + offset, (LONG)myClass);
   } else {
        myClass = (MyClass*)GetWindowLongPtr(hWnd, GWL_WNDEXTRA + offset);

Where here, "offset" is the offset returned from GetClassInfoEx() and set by you when you call RegisterClassEx and you set
the CLASSINFOEX::cbWndExtra to the needed extra bytes for you window.

Instead of calling Get/SetWindowLongPtr(), you can also store all your window in a std::map in this case but you should implement locking mutex
to synchronize all threaded access to the std::map

That all...

Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.


Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.