text: There are two kinds of messages which you, as a programmer, can defined. The first kind is the compile-time-constant variety. I have found, after years of experience, These Are Not Your Friend. I'll nonetheless describe them as many people still prefer them, but as a matter of opinion I avoid them as much as I can. The second kind are messages which are guaranteed to be unique within a system. I much prefer these, and use them exclusively.
  Older books on Windows programming tell about how to define user-defined messages using the symbol WM_USER. This technique is obsolete. There were too many problems with WM_USER-based symbols conflicting with messages that Microsoft was using. The new method is to use WM_APP as the base. If you have something that uses WM_USER, the usage is identical to the usage of messages based on WM_APP. Therefore, I will not reproduce the discussion here.
  WM_USER
  WM_APP
  If you are comfortable with the idea of compile-time constant messages--and after you read the next section, you may not be--then you can use definitions based on the symbol WM_APP, which Microsoft now specifies as the desirable symbol to use. The correct form of the definition of such a symbol is
  #define UWM_MYMESSAGE (WM_APP + n)
  where n is some integer, typically a small integer like 1, 2, 3, etc. This defines a value which identifies the message. While strictly speaking the parentheses are not mandatory, good programming practice demands their presence.
  I prefer a naming convention that does not conflict with the Microsoft naming convention. For one thing, it makes your code difficult for someone else to read and understand; for another, it makes it hard for you to read and understand. My preference is to use a UWM_ prefix (User Window Message); other people have used WMU_ (Window Message, User), and you can pick any convention you want, but do not use prefixes that conflict with those already in use by Microsoft.
  UWM_
  WMU_
  Note that there is absolutely no requirement that every user-defined message be unique. Messages are always interpreted in the context of a particular window. Thus, you can have messages like
  #define UWM_PAINT_VIEW_PURPLE (WM_APP + 7)
  #define UWM_RESET_VIEW (WM_APP + 7)
  These are perfectly valid providing that the view that accepts the purple request is never sent a reset request, and vice-versa.
  To create an entry in the table to dispatch on these messages, you make an entry
  ON_MESSAGE(UWM_RESET_VIEW, OnReset)
  This requires that you define the handler OnReset. In the message handler part of your .h file, you add the declaration
  OnReset
  .h
  afx_msg LRESULT OnReset(WPARAM, LPARAM);
  When your window class receives the UWM_RESET_VIEW message, it will call the OnReset handler.
  UWM_RESET_VIEW
  There are several problems with constant messages.
  (WM_APP+7)
  SendMessageToDescedants
  The way this is solved is by using a Registered Window Message. This is a message which is guaranteed to be unique. Only those windows or processes or DLLs that create it, and those which specifically use it, will actually have the same message number.
  How is this done?
  There is a range of messages, 0xC000 through 0xEFFF, which is reserved for use by registered window messages. When you call the API function ::RegisterWindowMessage you pass it a string. It looks up the string in an internal table. If it finds the string, it returns the integer which has been assigned. If it does not find the string, it creates a new entry in the table, assigns it a new integer value from the range 0xC000 through 0xEFFF, and returns that integer value. The table in which these strings are kept is global to all processes on the machine, so if two completely different programs register the same string, they both get the same integer. They may now communicate with each other via these messages.
  ::RegisterWindowMessage
  No, you can't "unregister" a message. You don't need to.
  So a simple form of the user-defined message would be to declare a variable, which I usually just make static in each module that uses it:
  static const UINT UWM_RESET_VIEW =
  ::RegisterWindowMessage(_T("UWM_RESET_VIEW"));
  I'll tell you later why this still isn't quite adequate, but take it as a working example for the moment.
  The way you handle a registered message is just like you handle a constant user-defined message. The macro is slightly different, but the rest of the handling is the same. Add the line to your MESSAGE_MAP:
  MESSAGE_MAP
  ON_REGISTERED_MESSAGE(UWM_RESET_VIEW, OnReset)
  As with the constant messages, you will need to define the OnReset handler by adding a declaration to the handler section of your class in the .h file:
  The handlers for a registered window message and for a constant user-defined message are absolutely identical. In fact, in the handler, you can't really tell if the programmer has rewritten the code to use one or the other.
  You.
  GUIDGEN.
  DECLARE_USER_MESSAGE.
  User-defined messages are an interface. As an interface, they need to be defined. I have some macros in my text editor that make this easy. They generate a standard header for me which I fill in. The header looks something like the examples below.
  Example 1: A message which has simple parameters, and which is sent but whose response doesn't matter:
  /***************************************************************
  * UWM_COLOR_IT
  * Inputs:
  * WPARAM: ignored, 0
  * LPARAM: RGB value to use for coloring
  * Result: LRESULT
  * Logically void, 0, always
  * Effect:
  * Causes the view to repaint itself in the specified color
  ***************************************************************/
  #define UWM_COLOR_IT_MSG _T("UWM_COLOR_IT-{4E7F6EC1-6ADC-11d3-BC36-006067709674}")
  Example 2: A message which has no parameters, and which is sent for the purpose of getting a result:
  /***************************************************************
  * UWM_QUERY_CUT
  * Inputs:
  * WPARAM: ignored, 0
  * LPARAM: ignored, 0
  * Result: LRESULT
  * (LRESULT)(BOOL) TRUE if a cut operation is possible
  * FALSE if there is no selection
  ***************************************************************/
  #define UWM_QUERY_CUT_MSG _T("UWM_QUERY_CUT-{4E7F6EC3-6ADC-11d3-BC36-006067709674}")
  Example 3: A message which has complex parameters, and which returns an interesting value:
  /***************************************************************
  * UWM_SET_COORD
  * Inputs:
  * WPARAM: (WPARAM)(BOOL) FALSE for absolute
  * TRUE for relative
  * LPARAM: (LPARAM)MAKELONG(x, y)
  * Result: LRESULT
  * (LRESULT)MAKELONG(x, y) previous coordinate value
  * Effect:
  * Sets the coordinate in the view, and returns the previous
  * coordinate.
  * Notes:
  * The x,y values are added to the current position if
  * WPARAM is TRUE, otherwise they replace the current
  * position.
  ***************************************************************/
  #define UWM_SET_COORD_MSG _T("UWM_SET_COORD-{4E7F6EC2-6ADC-11d3-BC36-006067709674}")
  Note that I carefully document the casting that is required to get the desired WPARAM and LPARAM values. Then I know when I'm writing my method how I should cast it. Here's an example of a handler for another message, which takes a pointer to an object.
  WPARAM
  LPARAM
  /***************************************************************
  * CMyView::OnAssignMyInfo
  * Inputs:
  * WPARAM: ignored, 0
  * LPARAM: (LPARAM)(LPMYINFO)
  * Result: LRESULT
  * Logically void, 0, always
  * Effect:
  * Modifies the current view by the values in LPMYINFO
  * Notes:
  * If LPMYINFO.IsValidCount is FALSE, the count field is
  * not modified
  ***************************************************************/
  LRESULT CMyView::OnAssignMyInfo(WPARAM, LPARAM lParam)
  {
  LPMYINFO info = (LPMYINFO)lParam;
  visible = info.visible;
  if(info.IsValidCount)
  count = info.count;
  return 0; // value is ignored
  }
  When!
  SendMessage
  PostMessage.
  CString
  }
  It is often a Bad Idea to send messages across threads. The problems of potential deadlock are substantial. If you SendMessage to a thread that is blocked, and that thread is waiting for the sending thread to complete, you're dead in the water. Your process is blocked, and it will stay blocked, and you will have to set of sticks of dynamite under it to make it go away.
  Note that you can get into this inadvertently. You should never, ever manipulate a GUI object from a worker thread, or a GUI object owned by a thread other than the user-interface thread that is sending the message. If you are getting deadlock, these are key problems to look for.
  You are safest, when transferring information across threads, to use PostMessage to handle it. A cross-thread PostMessage will not block the sender. If you need a positive acknowledgement, it is often best to restructure your algorithm to be a two-phase algorithm, where one method posts a message to the alternate thread, and expects the alternate thread to post a message back indicating completion. While harder to program, it avoids the deadlock issue.
  If you must send across threads, and you need a positive response, and you have the potential for deadlock, you should use SendMessageTimeout. This will send the message to the thread, but if the thread does not respond within the timeout period, the message is completed, and you get control back, with an error indication. A typical call I use looks like the example below.
  SendMessageTimeout
  // The following replaces the unconditional send
  // result = wnd->SendMessage(UWM_QUERY_SOMETHING);
  //
  DWORD result;
  if(!SendMessageTimeout(wnd->m_hWnd, // target window
  UWM_QUERY_SOMETHING, // message
  0, // WPARAM
  0, // LPARAM
  SMTO_ABORTIFHUNG |
  SMTO_NORMAL,
  TIMEOUT_INTERVAL,
  &result))
  { /* error or timed out */
  // take some appropriate action on timeout or failure
  // if we care, we can distinguish timeout from other
  // errors
  if(::GetLastError() == 0)
  { /* time out */
  // take timeout action
  } /* time out */
  else
  { /* other error */
  // take error action
  } /* other error */
  } /* error or timed out */
  else
  { /* successful */
  // decode the result
  switch(result)
  { /* result */
  case ...:
  break;
  case ...:
  break;
  } /* result */
  } /* successful */
  Sending a user-defined message across processes is somewhat more complex. First, you really have to use a Registered Window Message. Using a WM_APP-based message is somewhere between seriously dangerous and totally insane.
  When you send a message across processes, you are implicitly sending it across threads. All of the caveats about cross-thread messages apply. But even more, there are other serious restrictions on cross-process messages.
  The most significant one is that you cannot send a pointer across process boundaries. This is because process address spaces are separate, and a pointer has no meaning when it is received in the other process. For example,
  LRESULT CMainFrame::OnLogMessage(WPARAM, LPARAM lParam)
  {
  CString * s = (CString *)lParam;
  if(s[0] == _T('$')) // app crashes hard here
  { /* special message */
  // ...
  } /* special message */
  }
  When the operation s[0] is performed, the chances are almost dead certainty that the application receiving the message will take an access fault. The chances of the pointer being valid (and if it is, it will point to meaningless gibberish) are close to zero, and the gibberish pointed to will certainly not resemble a CString.
  s[0]
  You can't even pass a pointer to shared memory, even DLL-shared-segment shared memory. This is because the shared memory is not guaranteed to be in the same locations in all processes that share the memory (this is described in detail in Win32 Programming). Essentially, figure that you can't pass information across the process boundary using ordinary messages.
  In addition to all of the previous issues, posting messages across processes have additional hazards. For example, you cannot under any circumstances pass an address across process boundaries.
  This is true even if the address is in a shared memory area, such as shared DLL data segment or a memory-mapped files. Just because an address is valid in one process does not guarantee it is valid in a different process. And if you have evidence that says this is not so, that you've seen that you can pass a shared memory pointer from one process to another and it is valid, be aware that the phenomenon you are seeing is transient and accidental. While Win32 makes a sincere attempt to map shared memory into the same location in each process, it is important to emphasis that it does not guarantee this. Depending on this opens you to serious problems with the delivered product, which might not show up for months. But that's an essay for some other time.
  In addition, you can hit nasty deadlock situations, where a SendMessage does not complete, and hangs forever, or appears to.
  Here's a typical example, and we've actually seen this in practice:
  My application wants to be the one-and-only-copy running. One of the many detection mechanisms for this is to search for a window of the same class (which is a Bad Idea, since the class names are invented by MFC), the same caption (which is a Bad Idea since the captions may vary depending on which MDI child is active), etc. One of the better ways is to send a Registered Window Message to each window and look for a specific response. It used to be easy; it is now somewhat harder. The naive approach is to do something like shown below. What I show here is the handler for the EnumWindows call:
  EnumWindows
  BOOL CMyApp::myEnumProc(HWND hWnd, LPARAM lParam)
  {
  CMyApp * me = (CMyApp *)lParam;
  if(::SendMessage(hWnd, UWM_ARE_YOU_ME))
  { /* found duplicate */
  // ... do something here, e.g.,
  me->foundPrevious = TRUE;
  return FALSE; // stop enumerating
  } /* found duplicate */
  return TRUE; // keep enumerating
  }
  If I have a handler in my main window
  LRESULT CMainFrame::OnAreYouMe(WPARAM, LPARAM)
  {
  return TRUE;
  }
  then in principle any message sent to any window that doesn't recognize the Registered Window Message will pass it on to DefWindowProc, which, because it does not recognize the message, will return 0, which means that only my window will respond. This is also a technique for locating a client or server window of an affiliated application.
  DefWindowProc
  0
  So if I initially set foundPrevious to FALSE and call EnumWindows(myEnumProc, (LPARAM)this) then when I return I'll know if I found a previous instance.
  foundPrevious
  FALSE
  EnumWindows(myEnumProc, (LPARAM)this)
  There are three major flaws in this code, none of which are evident.
  First, while this is a fine technique for recognizing an affiliated window such as a client window or server window (and in that case, the message would probably pass a window handle as WPARAM to tell the affiliated window who sent the message), it won't work for finding a duplicate instance of the application. That's the topic of a different essay.
  Second, it can deadlock on a failed or non-responsive application, leaving you hanging.
  Third, Microsoft has gone out of their way to make life totally miserable by installing, on Windows 98, as part of the FrontPage product, a window which ALWAYS responds with TRUE to any message!!!! While it is hard to believe that anyone would have been stupid enough to do this, they have done it, and we all suffer.
  TRUE
  Let's look at these problems in detail:
  The first flaw is very evident when you have a desktop configured to launch an application on a single click. A user who is accustomed to double-clicking to launch an application will double-click, and this will launch TWO copies of the application. The first one does the EnumWindows loop and sees that it is the only instance running. It then proceeds to create its main window and continue on. The second instance comes up, and does the EnumWindows loop as well. Because we are in a preemptive multithreaded environment, it actually manages to complete its EnumWindows loop while the first application is still creating its main window! So the first application's main window isn't up yet, and the second application doesn't find it, and thinks that IT is the one-and-only application. So we have two copies running, which is not what we wanted.
  We can't avoid this. Come up with any scenario (such as not calling the EnumWindows until after the main window is created) and you still get the same race condition.
  So we rule this out for finding duplicate copies of the application. But let's look at the issue of polling all the windows to find a client or server. In this case, I might do
  HWND target = ::SendMessage(hWnd, UWM_HERE_I_AM, (WPARAM)m_hWnd);
  which is handled by the response:
  LRESULT CTheOtherApp::OnHereIAm(WPARAM wParam, LPARAM)
  {
  other = new CWnd;
  other.Attach((HWND)wParam);
  return (LRESULT)m_hWnd;
  }
  which looks like a pretty good exchange of window handles. If you don't know what Attach does, read my essay on Attach/Detach.
  Attach
  Attach/Detach
  Now, somewhere on the system I've got a wedged application. Perhaps it is a copy of IE waiting for an infinitely-long Web page timeout, and is blocked somewhere in the network handler. Perhaps it is some poorly-designed program that is doing a convolution algorithm on a terabit bitmap, and is doing it in the one-and-only main thread, and isn't allowing any messages to come in (it will be finished in a week or two). Perhaps it is one of your own programs you're debugging that is lost in a loop. Whatever. The key is that there is very long, possibly infinite delay, in an application you may not have even heard of. And guess what? Your innocent application hangs.
  The solution to this is to use ::SendMessageTimeout, so if one of these applications would block you, you will not hang. You should select a small timeout interval, such as 100ms, otherwise, you'll have a simply very long startup.
  ::SendMessageTimeout
  Now to the nasty part, in which Microsoft really does us in. There is some application which has a window whose class is "Front Page Message Sink", and which exhibits the pathological and unsociable behavior that it returns a nonzero value for EVERY message it receives. This is colossally stupid. It is undocumented, it violates all known Windows standards, and it will be fatal to you. This only shows up if you have Personal Web Server running. But it is absolutely inexcusable to have done this.
  All I know is that I see it return the value 1, consistently, for any kind of Registered Window Message it receives. Perhaps this is the only value it returns. I don't know, and nobody at Microsoft responded to my bug report with anything explaining what is going on.
  Thus testing the result of the ::SendMessage or the DWORD result of ::SendMessageTimeout against 0 is not informative. Thus far, if you see 0 or 1, you can't depend on the value having any meaning. With any luck, Microsoft will fix this (hah!), and ideally they will not introduce other gratuitous examples of such insanity in the future.
  DWORD
  I worked around this by modifying the receiving handler to return a non-zero, non-one value. For example, I actually use ::RegisterWindowMessage to get a value, although I suppose I could have used ::GlobalAddAtom. At least I know that ::RegisterWindowMessage will return a non-zero, non-one value.
  ::GlobalAddAtom
  // ... in a header file shared by both applications
  #define MY_TOKEN T("Self token-{E32F4800-8180-11d3-BC36-006067709674}")
  // ... rewrite the handler as
  LRESULT CMainFrame::OnAreYouMe(WPARAM, LPARAM)
  {
  return ::RegisterWindowMessage(MY_TOKEN);
  }
  // In the calling module, do something like
  UINT token = ::RegisterWindowmessage(MY_TOKEN);
  // ... and recode the caller, the EnumWndProc, as
  DWORD result;
  BOOL ok = ::SendMessageTimeout(hWnd,
  (WPARAM)m_hWnd, // WPARAM
  0, // LPARAM
  SMTO_ABORTIFHUNG |
  SMTO_NORMAL,
  TIMEOUT_INTERVAL,
  &result));
  if(!ok)
  return TRUE; // failed, keep iterating
  if(result == token)
  { /* found it */
  // ... do whatever you want here
  return FALSE; // done iterating
  } /* found it */
  If you are trying to pass a handle back, instead of just a designated value, you would have to make the test
  if(result != 0 && result != 1) // avoid Microsoft problem
  { /* found it */
  target = new CWnd;
  target->Attach(hWnd);
  // ... do whatever you want here
  return FALSE; // done iterating
  } /* found it */
  Note that if you choose to use ::FindWindow, it does an ::EnumWindows internally, and consequently can be subject to the same permanent hang. Using ::FindWindow is extremely hazardous, since it assumes that in fact every ::SendMessage will complete. Note that ::FindWindow does a ::SendMessage(hWnd, WM_GETTEXT,...) to get the window text to search for.
  ::FindWindow
  ::EnumWindows
  ::SendMessage
  ::SendMessage(hWnd, WM_GETTEXT,...)
  There is a possibly useful message, WM_COPYDATA, that will transfer information across the boundary. It does this by passing the data thru the kernel. Space is allocated in the receiving process to hold the information that is copied, by the kernel, from the source process to the target process. Or something that resembles that. The implementation details are actually concealed from you.
  WM_COPYDATA
  The sender passes a pointer to a COPYDATASTRUCT, which is defined as a structure of the following:
  COPYDATASTRUCT
  typedef struct tagCOPYDATASTRUCT {
  DWORD dwData;
  DWORD cbData;
  PVOID lpData;
  } COPYDATASTRUCT, *PCOPYDATASTRUCT;
  The dwData member holds an arbitrary 32-bit value that is being passed to the target. You can set this to any value the two processes agree on. The cbData member tells how many bytes are in the value referenced by lpData. When the target process receives the information, it handles it via a method
  dwData
  cbData
  lpData
  BOOL CMainFrame::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
  The CWnd * is a reference to the sending window, and the COPYDATASTRUCT * references the COPYDATASTRUCT that was passed in. Note that you don't know the actual address in the sender. The data which is passed in must not contain pointers.
  CWnd *
  There are some potential problems with WM_COPYDATA, in that you need to identify who has sent it in order to understand if it is valid, or you must have some other way to identify it. One way to handle it is to use our old friend the GUID. If you put a GUID in the beginning of the data packet, you can compare it to the expected GUID and if they are equal you know for certain that the packet you received is the packet you want.
  You must not store the pCopyDataStruct.lpData pointer, because after you return from the OnCopyData handler the pointer should be assumed to be no longer valid. You must also not attempt to write into the data referenced by the lpData pointer; it must be treated as read-only.
  pCopyDataStruct.lpData
  OnCopyData
  MFC has a wonderful message routing mechanism. A command message first comes to the active view, then the view frame, then the document, and so on. This works for WM_COMMAND and WM_UPDATE_COMMAND_UI messages, but does not work for any other kind of message, including user-defined messages. This is a real pain, and somewhat silly because it would be easy for Microsoft to implement. So a problem arises when you need to send a message to some sub-window, but you can't send a WM_COMMAND message because you are not directly responding to a GUI component.
  WM_COMMAND
  WM_UPDATE_COMMAND_UI
  Of course, you could invent a fictitious control and generate your own imitation WM_COMMAND messages. But this is very risky, and contributes to significant future unmaintainability.
  What can you do?
  I've done several things. Sometimes, I just put a message handler in the child frame whose sole purpose is to route the message to the child window contained in the frame. This can be a pain, but gives you serious control over how the messages are processed. Thus, the main frame, to which I post a message (often from a thread), has a handler of the form
  // ... in the message map
  ON_REGISTERED_MESSAGE(UWM_THREAD_DID_SOMETHING, OnThreadDidSomething)
  // ... the handler
  LRESULT CMainFrame::OnThreadDidSomething(WPARAM wParam, LPARAM lParam)
  {
  CView * active = GetActiveView();
  if(active != NULL)
  active->SendMessage(UWM_THREAD_DID_SOMETHING, wParam, lParam);
  return 0;
  }
  Sometimes you have to send the message not to the view, but to its parent frame window. This is done by the following code:
  RESULT CMainFrame::OnThreadDidSomething(WPARAM wParam, LPARAM lParam)
  {
  CFrameWnd * active = GetActiveFrame();
  if(active != this)
  active->SendMessage(UWM_THREAD_DID_SOMETHING, wParam, lParam);
  return 0;
  }
  Note the special test above. If, for some reason, you had managed to kill off all the MDI children while the thread was still running, GetActiveFrame returns this, which would mean you would get into a semi-infinite SendMessage loop which would terminate when you ran out of stack space. Note that because the function is defined as returning this we don't have to worry about the possibility that a temporary window handle has been returned, a caution I discuss in my essay on the use of Attach/Detach. This requires that you use the CMDIChildFrame subclass, and introduce a similar handler there:
  GetActiveFrame
  this
  CMDIChildFrame
  BEGIN_MESSAGE_MAP(CMyMDIChildFrame, CMDIChildWnd)
  ON_REGISTERED_MESSAGE(UWM_THREAD_DID_SOMETHING, OnThreadDidSomething)
  // and the handler is
  LRESULT CMyMDIChildFrame::OnThreadDidSomething(WPARAM wParam, LPARAM lParam)
  {
  // ... do things to the frame window (resize, reposition?)
  // and if appropriate, pass the message down...
  SendMessageToDescendants(UWM_THREAD_DID_SOMETHING,
  wParam,
  lParam,
  FALSE, // only go one level deep
  TRUE); // only to permanent windows
  return 0;</FONT>
  Now, you may wonder why I didn't send it directly to the child window. Partly because I'm lazy, and SendMessageToDescendants does what I need. Partly because I don't need the result, because it came in from PostMessage. In a case where I had to route a message to the descendant where I needed the result, I'd instead write
  SendMessageToDescendants
  CView * view = (CView *)GetWindow(GW_CHILD);
  ASSERT(view != NULL && view->IsKindOf(RUNTIME_CLASS(CView)));
  view->SendMessage(...);
  User-defined messages are a powerful and flexible mechanism for handling the passing of information and control between levels of your application, threads of your application, and processes. However, using them effectively requires certain degrees of care. I favor using ::RegisterWindowMessage and GUIDs to define all messages. Interthread and interprocess sends are risky, and should be avoided; if you must, use SendMessageTimeout to ensure that you will not end up in deadlock.
  WM_USER + x
  TTM_ACTIVATE
  TB_ENABLEBUTTON
  WM_USER + 1
  MESSAGE_RANGE_HANDLER(0xC000, 0xffff, OnAnyRegisteredMessage)
  LRESULT OnAnyRegisteredMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  {
  TRACE(_T("msg = %d, wParam = %d, lParam = %d\n"), uMsg, wParam, lParam);
  bHandled = ~bHandled; // Do this so the message is still handled
  return 0;
  }
  #define REGISTERED_MESSAGE_HANDLER(msg, func) \
  if(uMsg == *((UINT*)(&msg))) \
  { \
  bHandled = TRUE; \
  lResult = func(uMsg, wParam, lParam, bHandled); \
  if(bHandled) \
  return TRUE; \
  }
  REGISTERED_MESSAGE_HANDLER(s_iRegMsgID, OnBlah)
  uMsg == *((UINT*)(&msg))
  // ID: MyMsg
  // WParam: Not Used
  // LParam: Not used
  static unsigned int s_iMyMsg = ::RegisterWindowMessage(_T("MyMsg"));
  REGISTERED_MESSAGE_HANDLER(s_iMyMsg, OnMyMsg)
  // LRESULT OnMyMsg(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
  //pp<bool> pCancel = new bool;
  //*pCancel = false;
  //;
  //ACCESS( m_GUITasks, m_GUITasks->push_back( new CGUITask(CGUITask::LOCK_TREE) ) );
  m_Tree.LockUpdate();
  //ACCESS( m_GUITasks, m_GUITasks->push_back( new CGUITask(CGUITask::CALL_SHOWWINDOW, &ProgressDlg, SW_SHOW) ) );
  ProgressDlg.ShowWindow(SW_SHOW);
  DoTasks(true);
  ZeroMemory(pProgress.GetPointer(), sizeof(*pProgress) * si.dwNumberOfProcessors);
  //NewThread(&CKantanAnimeDlg::UpdateGUIThread, this, pProgress, dwSize, pCancel)->m_bAutoDelete = true;
  CThread* pThread = NewThread(&CKantanAnimeDlg::AddFilesThread2<T>, this, pFilesArg, /*pCancel, */pProgress, dwSize); // Do some processing
  UINT nTotalProgress;
  UINT nLength = si.dwNumberOfProcessors;
  int nCount = 1;
  while(pThread->Running())
  {
  nTotalProgress = 0;
  for (UINT i = 0; i < nLength; i++) nTotalProgress += pProgress[i];
  ProgressDlg.m_ProgressText->Format("Loading encoding list. Please wait...\nAdding file %u of %u...", nTotalProgress, dwSize);
  ProgressDlg.m_Progress.SetPos( (int)( (float)nTotalProgress / dwSize * 100 ) );
  //ACCESS( m_GUITasks, m_GUITasks->push_back( new CGUITask(CGUITask::CALL_SETPOS, &ProgressDlg.m_Progress, (int)( (float)nTotalProgress / dwSize * 100 )) ) );
  if (nCount++ == 20) // Update every 200 ms
  {
  //ACCESS( m_GUITasks, m_GUITasks->push_back( new CGUITask(CGUITask::CALL_UPDATEDATA, &ProgressDlg, FALSE) ) );
  ProgressDlg.UpdateData(FALSE);
  nCount = 1;
  }
  //DoTasks(false);
  DoMessageLoop();
  //if (*pCancel) break;
  Sleep(10);
  }
  /) ) );
  m_Tree.UnlockUpdate();
  ProgressDlg.ShowWindow(SW_HIDE); // DEADLOCK!!!!
  DoMessageLoop();
  //DoTasks(false);
  //*pCancel = true;
  ProgressDlg.bCancel = true;
  }
  CKantanAnimeDlg dlg;
  m_pMainWnd = &dlg;
  dlg.Create(IDD_KANTANANIME_DIALOG);
  dlg.ShowWindow(SW_SHOW);
  pp<EnumValuesArray> pArray = dlg.pRegForPlaylist->EnumValues("");
  if (pArray)
  {
  //pp<EnumSubKeysArray> pMMArray = pArray;
  //size_t nCount = 0;
  //NewThread(&CKantanAnimeDlg::AddFilesThread<EnumValuesArray>, &dlg, pArray)->m_bAutoDelete = true;
  dlg.AddFilesThread(pArray.GetPointer());
  };
  m_Tree.LockUpdate();
  ProgressDlg.ShowWindow(SW_SHOW);
  ZeroMemory(pProgress.GetPointer(), sizeof(*pProgress) * si.dwNumberOfProcessors);
  m_AddFilesCmd.EnableWindow(FALSE);
  m_StartEncodingCmd.EnableWindow(FALSE);
  m_StopEncodingCmd.EnableWindow(FALSE);
  m_RemoveFileCmd.EnableWindow(FALSE);
  NewThread(&CKantanAnimeDlg::AddFilesThread2<T>, this, pFilesArg, /*pCancel, */pProgress, dwSize);
  }
  template<typename T> void AddFilesThread2(T* pFilesArg, /*pp<bool> pCancel, */pp<UINT> pProgress, DWORD dwSize)
  {
  vector<CString>* pFiles = (vector<CString>*)pFilesArg;
  EnumValuesArray* pFilesReg = (EnumValuesArray*)pFilesArg;
  UINT nTotalProgress;
  UINT nLength = si.dwNumberOfProcessors;
  int nCount = 1;
  #pragma omp parallel private(pFiles, pFilesReg) shared(pProgress, dwSize)
  {
  CString strTemp;
  pFiles = (vector<CString>*)pFilesArg;
  pFilesReg = (EnumValuesArray*)pFilesArg;
  size_t nToExecute;
  if ( (omp_get_thread_num() + 1) == omp_get_num_threads() )
  {
  // Make sure that the last thread gets the remaining job until the end if an aneven number was divided
  nToExecute = (size_t)dwSize - ( dwSize / omp_get_num_threads() );
  }
  else
  nToExecute = (size_t)dwSize / omp_get_num_threads();
  for (size_t i = nToExecute * omp_get_thread_num(); nToExecute; i++, nToExecute--)
  {
  // Add file
  if ( typeid(pFilesArg) == typeid(vector<CString>*) )
  {
  if (! AddNewFile(pFiles->at(i), GetFile( pFiles->at(i) ), true, true) )
  MsgBox(this, "Failed to add new file...\n\n" + pFiles->at(i) + "\n\n...to the list!", ERR);
  }
  else if ( typeid(pFilesArg) == typeid(EnumValuesArray*) )
  {
  if (! AddNewFile((char*)pFilesReg->at(i)->GetData(), GetFile( (char*)pFilesReg->at(i)->GetData() ), true, true) )
  MsgBox(this, "Failed to add new file...\n\n" + (CString)(char*)pFilesReg->at(i)->GetData() + "\n\n...to the list!", ERR);
  }
  // Update progress
  pProgress[ omp_get_thread_num() ]++;
  nTotalProgress = 0;
  for (UINT i = 0; i < nLength; i++) nTotalProgress += pProgress[i];
  ProgressDlg.m_ProgressText->Format("Loading encoding list. Please wait...\nAdding file %u of %u...", nTotalProgress, dwSize);
  ACCESS( m_GUITasks, m_GUITasks->push_back( new CGUITask(CGUITask::CALL_SETPOS, &ProgressDlg.m_Progress, (int)( (float)nTotalProgress / dwSize * 100 )) ) );
  if (nCount++ == 20) // Update for every 20 loops
  {
  ACCESS( m_GUITasks, m_GUITasks->push_back( new CGUITask(CGUITask::CALL_UPDATEDATA, &ProgressDlg, FALSE) ) );
  nCount = 1;
  }
  DoTasks(false);
  if (ProgressDlg.bCancel) break;
  }
  }) ) ); // DEADLOCK!
  ACCESS( m_GUITasks, m_GUITasks->push_back( new CGUITask(CGUITask::CALL_ENABLEWINDOW, &m_AddFilesCmd, FALSE) ) );
  ACCESS( m_GUITasks, m_GUITasks->push_back( new CGUITask(CGUITask::CALL_ENABLEWINDOW, &m_StartEncodingCmd, FALSE) ) );
  ACCESS( m_GUITasks, m_GUITasks->push_back( new CGUITask(CGUITask::CALL_ENABLEWINDOW, &m_StopEncodingCmd, FALSE) ) );
  ACCESS( m_GUITasks, m_GUITasks->push_back( new CGUITask(CGUITask::CALL_ENABLEWINDOW, &m_RemoveFileCmd, FALSE) ) );
  DoTasks(false);
  }
  Joseph M. Newcomer wrote:You cannot send user-defined messages to CDocuments, CWinApps, etc.
  Joseph M. Newcomer wrote:See my essay on the use of I/O Completion Ports for queueing
  In a private communication with a Senior Support Engineer at Microsoft, it has been noted that there is no guarantee that a process has any windows at all. It is also possible that a process has more than one window. Even if you get the correct window, it must know about and be able to handle the message being sent. A window always has a process, but a process can have zero to any number of windows, so there is no way to make a correlation between a process and a particular window.
  static UINT TH_PROGRESS_INITWINDOW = RegisterWindowMessage("TH_PROGRESS_INITWINDOW");
  static UINT TH_PROGRESS_ENDPROCESS = RegisterWindowMessage("TH_PROGRESS_ENDPROCESS");
  ON_REGISTERED_THREAD_MESSAGE(TH_PROGRESS_INITWINDOW,OnInitWindow)
  ON_REGISTERED_THREAD_MESSAGE(TH_PROGRESS_ENDPROCESS,OnEndThread)
  General News Suggestion Question Bug Answer Joke Rant Admin
  Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.