From: Manu <con...@wa...> - 2002-04-22 14:57:46
|
Hi, I have some trouble using SendMessage(...) based macros in my C++ classes. Here is the problem. I use a "CWindow" class that encapsulate common window procedures, like: CWindow::SendMessage(UINT msg, WPARAM wParam = 0, LPARAM lParam = 0) Though, this member is problematic if I try to use a SendMessage() based macro inside of a CWindow derived class. For example, my CTreeView class derives of a CWindow class. Then I can't use TreeView_ macros inside a CTreeView class because these macros are also based on SendMessage(...). For example: #define TreeView_GetCount(w) (UINT)SendMessage((w),TVM_GETCOUNT,0,0) I may change my CWindow::SendMessage(...) in, for example CWindow::SendMsg(...). Though, I know a possible workaround. I've found that headers of "well known products" use a different way to define these macros. First, a macro, for example, SENDMSG is defined as "SendMessage" in C and as "::SendMessage" in C++. I've tried the following. It seems to be correct and works fine. #ifndef SENDMSG #ifdef __cplusplus #define SENDMSG ::SendMessage #else #define SENDMSG SendMessage #endif #endif /* ifndef SENDMSG */ Then a macro would be: #define TreeView_GetCount(w) (UINT) SENDMSG((w),TVM_GETCOUNT,0,0) Is this method interesting ? Should I submit a patch using this ? Manu. ________________________________________________________________ Visual-Mingw project. Home: http://visual-mingw.sourceforge.net/ Sources: http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/visual-mingw/visual-mingw/src/ _________________________________________________________________ |
From: Oscar F. <of...@wa...> - 2002-04-22 16:22:57
|
Sorry if this shows too much lack of understanding about your problem... "Manu" <con...@wa...> writes: > Hi, > I have some trouble using SendMessage(...) based macros in my C++ classes. Ok. Macros are evil. > Here is the problem. > I use a "CWindow" class that encapsulate common window procedures, like: > CWindow::SendMessage(UINT msg, WPARAM wParam = 0, LPARAM lParam = 0) > > Though, this member is problematic if I try to use a SendMessage() > based macro inside of a CWindow derived class. Right. > For example, my CTreeView class derives of a CWindow class. Then I > can't use TreeView_ macros inside a CTreeView class because these > macros are also based on SendMessage(...). [What are those TreeView_ macros?] > For example: > #define TreeView_GetCount(w) (UINT)SendMessage((w),TVM_GETCOUNT,0,0) [After some searching on MinGW headers] Ah! Those macros are defined in commctrl.h. > I may change my CWindow::SendMessage(...) in, for example > CWindow::SendMsg(...). Though, I know a possible workaround. I've > found that headers of "well known products" use a different way to > define these macros. FWIW, Borland uses the same approach as MinGW for this issue. > First, a macro, for example, SENDMSG is defined as "SendMessage" in C and as > "::SendMessage" in C++. > > I've tried the following. It seems to be correct and works fine. > > #ifndef SENDMSG > #ifdef __cplusplus > #define SENDMSG ::SendMessage > #else > #define SENDMSG SendMessage > #endif > #endif /* ifndef SENDMSG */ > > Then a macro would be: > #define TreeView_GetCount(w) (UINT) SENDMSG((w),TVM_GETCOUNT,0,0) > > Is this method interesting ? But 'SendMessage' is still a macro, isn't it? That means that when you write: #include <commctrl.h> // ... myInstance.SendMessage(...); it would expand to myInstance.::SendMessageA(...); or myInstance.::SendMessageW(...); (depending on if you are using Unicode or not) Have you checked this? BTW, using SendMessage as a method name would give problems in either case, unless you #undef it. > Should I submit a patch using this ? Are you talking about a patch using your approach for _all_ cases (not only SendMessage) ? -- Oscar |
From: Manu <con...@wa...> - 2002-04-22 18:55:14
|
Oscar Fuentes <of...@wa...> wrote: > > Sorry if this shows too much lack of understanding about your > problem... > > "Manu" <con...@wa...> writes: > > > Hi, > > I have some trouble using SendMessage(...) based macros in my C++ classes. > > Ok. Macros are evil. Absolutely true, indeed I don't want to use these macros inside my CWindow derived code. :) It seems a schizophrenic problem, isn't it ? In fact, I'm also planning a sort of RAD feature using the CWindow based classes I've done. (a kind of "MFC-light") Then, I'm afraid that end users would probably like to use the macros. [snip] > [What are those TreeView_ macros?] [...] > [After some searching on MinGW headers] > > Ah! Those macros are defined in commctrl.h. Right, messages can be sent explicitly, using SendMessage(...) or using a macro, if there is one. > > I may change my CWindow::SendMessage(...) in, for example > > CWindow::SendMsg(...). Though, I know a possible workaround. I've > > found that headers of "well known products" use a different way to > > define these macros. > > FWIW, Borland uses the same approach as MinGW for this issue. BTW, not exactly. Borland's approach (in fact M$ approach) is different. To simplify a lot, their "SNDMSG" makes the macros more "C++ compliant", whereas MinGW headers are more strict. [snip] > But 'SendMessage' is still a macro, isn't it? That means that when you > write: > > #include <commctrl.h> > > // ... > > myInstance.SendMessage(...); > > it would expand to > > myInstance.::SendMessageA(...); > > or > myInstance.::SendMessageW(...); > > (depending on if you are using Unicode or not) > > Have you checked this? Yes, it seems like... you know... those dolls, each one put in another one :-) > BTW, using SendMessage as a method name would give problems in either > case, unless you #undef it. Here is the function: LRESULT CWindow::SendMessage(UINT Msg, WPARAM wParam, LPARAM lParam){ return ::SendMessage(_hWnd, Msg, wParam, lParam); } I won't have any trouble since I will call the standard SendMessage using the scope resolution operator (::), like: ::SendMessage(_hWnd, Msg, wParam, lParam); ^^^^ This is the problem, MinGW headers doesn't use (::), this is why "SNDMSG" seems to make the macros "C++ compliant". > > Should I submit a patch using this ? > > Are you talking about a patch using your approach for _all_ cases (not > only SendMessage) ? No, only for SendMessage based macros, of course. Manu. |
From: Oscar F. <of...@wa...> - 2002-04-22 20:53:40
|
"Manu" <con...@wa...> writes: > Oscar Fuentes <of...@wa...> wrote: > > > > Sorry if this shows too much lack of understanding about your > > problem... > > > > "Manu" <con...@wa...> writes: > > > > > Hi, > > > I have some trouble using SendMessage(...) based macros in my C++ classes. > > > > Ok. Macros are evil. > > Absolutely true, indeed I don't want to use these macros inside my CWindow derived code. :) > It seems a schizophrenic problem, isn't it ? > In fact, I'm also planning a sort of RAD feature using the CWindow based classes > I've done. (a kind of "MFC-light") MFC == RAD ? <grin> > Then, I'm afraid that end users would probably like to use the macros. It is a C++ library, isn't it? Well, every C++ programmer knows that macros should be avoided and we should use inline functions instead. See below. [snip] > > FWIW, Borland uses the same approach as MinGW for this issue. > > BTW, not exactly. Borland's approach (in fact M$ approach) is > different. To simplify a lot, their "SNDMSG" makes the macros more > "C++ compliant", whereas MinGW headers are more strict. Borland uses it on <commctrl.h>. Borland doesn't use it on other headers. > [snip] > > But 'SendMessage' is still a macro, isn't it? That means that when you > > write: > > > > #include <commctrl.h> > > > > // ... > > > > myInstance.SendMessage(...); > > > > it would expand to > > > > myInstance.::SendMessageA(...); > > > > or > > myInstance.::SendMessageW(...); > > > > (depending on if you are using Unicode or not) > > > > Have you checked this? > > Yes, it seems like... you know... those dolls, each one put in another one :-) > > > BTW, using SendMessage as a method name would give problems in either > > case, unless you #undef it. > > Here is the function: > > LRESULT CWindow::SendMessage(UINT Msg, WPARAM wParam, LPARAM lParam){ > return ::SendMessage(_hWnd, Msg, wParam, lParam); > } > > I won't have any trouble since I will call the standard SendMessage > using the scope resolution The issue is not the function declaration/definition, the issue is the _order_ of the macro/function definition/declaration. Example: // File header.h class MyClass { public: void SendMessage(); // Just an example }; // File imp.cpp #include <commctrl.h> // The above #defines SendMessage and it is applied to everything below #include "header.h" // We just included // class MyClass { // public: // void ::SendMessageA(); // <---------- // }; void MyClass::SendMessage() {} // The above is replaced with // void MyClass::::SendMessageA() {} // This unit will compile ok. // File mysource.cpp #include "header.h" void foo() { MyClass mc; mc.SendMessage(); // <<--- This is not transformed. Compile error. } Of course, you have not the problem if you #include <commctrl.h> on top of "header.h", but sometimes this is undesirable. There are other variations. Whatever you do, the macro approach will give trouble either compiling the library or compiling the user code, unless you #undefine the macro at some point. > operator (::), like: > ::SendMessage(_hWnd, Msg, wParam, lParam); > ^^^^ > This is the problem, MinGW headers doesn't use (::), this is why "SNDMSG" seems to > make the macros "C++ compliant". Well, making macros "C++ compliant" is throwing them away :-) This should work: #ifdef __cplusplus # ifdef UNICODE inline ... SendMessage(...) { return SendMessageW(...); } # else inline ... SendMessage(...) { return SendMessageA(...); } # endif #else # define SendMessage SendMessageA #endif This is not 100% annoyance-free, but it is more "correct". > > > Should I submit a patch using this ? > > > > Are you talking about a patch using your approach for _all_ cases (not > > only SendMessage) ? > > No, only for SendMessage based macros, of course. IMO this would introduce an "exception" on the header files that could produce some confussion on users. Isn't there other functions that have the same problem than SendMessage? IMHO, the above 'inline' approach should be user for every "function" that now is defined as a macro. -- Oscar |
From: Oscar F. <of...@wa...> - 2002-04-22 21:20:39
|
Oscar Fuentes <of...@wa...> writes: [snip] > void MyClass::SendMessage() {} > // The above is replaced with > // void MyClass::::SendMessageA() {} > // This unit will compile ok. Ooops!! This would _not_ compile ok. If SendMessage were defined as 'SendMessageA' and not '::SendMessageA', it would compile, though. [snip] -- Oscar |
From: Manu <con...@wa...> - 2002-04-23 07:55:09
|
Oscar Fuentes <of...@wa...> wrote: > Oscar Fuentes <of...@wa...> writes: > > [snip] > > > void MyClass::SendMessage() {} > > // The above is replaced with > > // void MyClass::::SendMessageA() {} > > // This unit will compile ok. > > Ooops!! This would _not_ compile ok. If SendMessage were defined as > 'SendMessageA' and not '::SendMessageA', it would compile, though. Well, i feel a little bit confused now. I can't understand all that you've explained :( I've tried to declare my procedure 'inline'. The compiler still complains. /* base class: note that _my_ procedure handles 3 parameters, instead of 4 */ class CWindow{ public: HWND _hWnd; LRESULT SendMessage(UINT Msg, WPARAM wParam = 0, LPARAM lParam = 0){ // 3 params return ::SendMessage(_hWnd, Msg, wParam, lParam); // SendMessageA handles 4 parameters } } /* derived class */ class CTreeView : public CWindow{ ... }; /* declaration of an instance */ CTreeView TreeView; /* no problem with this */ void TreeView::CountTvItems(void){ ::SendMessage((_hWnd), TVM_GETCOUNT,0 ,0); } /* using a macro inside the class */ void TreeView::CountTvItems(void){ TreeView_GetCount(_hWnd)); } Compilation error: no matching function for call to 'TreeView::SendMessageA (HWND, int, int, int)' candidates are: LRESULT CWindow::SendMessageA(unsigned int, unsigned int, unsigned int) /* this produces the same error, quite logical */ void TreeView::CountTvItems(void){ SendMessage((_hWnd), TVM_GETCOUNT,0 ,0); } TreeView_GetCount(int) equals to "SendMessageA(int, int, int, int)" in MinGW headers and "::SendMessageA(int, int, int, int)" in Borland ones. (because of their "SNDMSG", so my code would probably build with BCC32) Anyway, unless adopting Borland's way, the _simplest_ way would be: /* base class */ class CWindow{ public: HWND _hWnd; LRESULT SendMsg(UINT Msg, WPARAM wParam = 0, LPARAM lParam = 0){ // 3 params // ^^^^^^^^ no more confusion return ::SendMessage(_hWnd, Msg, wParam, lParam); // 4 params } } Thanks Oscar, Manu. |
From: Oscar F. <of...@wa...> - 2002-04-23 17:41:04
|
"Manu" <con...@wa...> writes: > Oscar Fuentes <of...@wa...> wrote: > > Oscar Fuentes <of...@wa...> writes: > > > > [snip] > > > > > void MyClass::SendMessage() {} > > > // The above is replaced with > > > // void MyClass::::SendMessageA() {} > > > // This unit will compile ok. > > > > Ooops!! This would _not_ compile ok. If SendMessage were defined as > > 'SendMessageA' and not '::SendMessageA', it would compile, though. > > Well, i feel a little bit confused now. I can't understand all that > you've explained :( I've tried to declare my procedure 'inline'. The > compiler still complains. Not _your_ procedure. Read again my previous msg. It talks about replacing <winuser.h> SendMessage macro definition with inline functions. [snip] > Anyway, unless adopting Borland's way, the _simplest_ way would be: > > /* base class */ > class CWindow{ > public: > HWND _hWnd; > LRESULT SendMsg(UINT Msg, WPARAM wParam = 0, LPARAM lParam = 0){ // 3 params > // ^^^^^^^^ no more confusion > return ::SendMessage(_hWnd, Msg, wParam, lParam); // 4 params > } > } My speculative patch for _<winuser.h>_ is oriented to save the user the need of having to worry about "functions" that really are macros, like SendMessage. It wipes out that macros and replaces them with inline function definitions. Nothing to do with client code. -- Oscar |
From: Manu <con...@wa...> - 2002-04-24 15:42:26
|
Oscar Fuentes <of...@wa...> wrote: [snip] > > Well, i feel a little bit confused now. I can't understand all that > > you've explained :( I've tried to declare my procedure 'inline'. The > > compiler still complains. > > Not _your_ procedure. Read again my previous msg. It talks about > replacing <winuser.h> SendMessage macro definition with inline > functions. Ok Oscar, I've finally understood. Thanks for your patience :) [...] > My speculative patch for _<winuser.h>_ is oriented to save the user > the need of having to worry about "functions" that really are macros, > like SendMessage. It wipes out that macros and replaces them with > inline function definitions. Nothing to do with client code. I'm writing a test case to study this issue. Manu. |
From: Marco M. <mma...@me...> - 2002-04-24 06:58:13
|
In the newgrid demo, move the cursor to the column or row label area and resize the column/row from there. If while dragging you accidentally (or deliberately in this case) move off the label area, the resizing is cancelled but a vertical/horizontal line is left inside the grid. This problem does not occur if the resizing is started from within the grid. I reported this bug wxMSW220 but is still there in the 229. Regards Marco. --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.351 / Virus Database: 197 - Release Date: 20-Apr-02 |