Board index » cppbuilder » Getting Message with WinMain

Getting Message with WinMain


2007-02-13 04:21:02 AM
cppbuilder81
I've got a small AutoRun style application that currently only has a WinMain
function (i.e. old C program style).
How can I add the ability to search for Windows Messages like WM_COMMAND?
TCustomForm includes a WndProc function that has what I want, but my small
WinMain application does not have (or need) a TForm. Is there some way to
implement this without having to create a form that I don't use? Or, how
would I create a custom WndProc for my application?
Thanks in advance!
PJ
 
 

Re:Getting Message with WinMain

"poojo hackma" <poojo.com/mail>wrote in message
Quote
I've got a small AutoRun style application that currently only
has a WinMain function (i.e. old C program style).

How can I add the ability to search for Windows Messages like
WM_COMMAND?
First, you need an actual window to receive the message with. Console
applications do not have a window by default. You will have to call
CreateWindow/Ex() for that.
Second, you need an active message queue to receive and process
messages with. You will have to call Get/PeekMessage(),
TranslateMessage(), and DispatchMessage() for the lifetime of the
program for that.
Quote
TCustomForm includes a WndProc function that has what I want, but
my small WinMain application does not have (or need) a TForm. Is
there
some way to implement this without having to create a form that I
don't use?
If you have enabled the VCL for your project, then you can use the
AllocateHWnd() function instead of calling CreateWindow/Ex(). The
callback method for AllocateHWnd() has to be a member of a class, and
you still need to implement your own message queue to receive the
messages.
Gambit
 

Re:Getting Message with WinMain

Thanks Gambit,
I've been chugging through the Help with the info you gave me, but now I am
stuck.
Here is why:
CreateWindow requires lpClassName, which can be an ATOM.
RegisterClass() creates an ATOM, but requires a WNDCLASS parameter.
The WNDCLASS structure requires lpClassName.
Now I am stuck in a loop.
I am trying to pop up a notification icon in the taskbar.
What did I missunderstand?
Code: (not all of the variables have been shown)
//---------------------------------------------------------------------------
void Say(const wchar_t* message, wchar_t* title) {
#ifdef _DEBUG
wchar_t *clob = title;
wcscat(clob, L"\n");
wcscat(clob, message);
MessageBox(NULL, message, L"Debug", MB_OK);
#endif
}
//---------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR
lpCmdLine, int nCmdShow) {
if (SHGetAutoRunPath(Path) == FALSE) {
Say(L"No AutoRun path. Exiting.", L"WinMain");
return 0; // no CF card detected. Exit
} else if (IsProcessRunning(L"wceload.exe") == TRUE) { // exit!
Say(L"Process Is Running. Exiting.", L"WinMain");
return 0;
} else {
wcscpy(buff, Path);
wchar_t *c;
c = buff;
buffTail = c;
while (*c != 0) {
if (*c == '\\')
buffTail = c + 1;
c++;
}
}
wchar_t *cmdLine;
wchar_t *exeFile = L"App1.exe"; // Main executable file
wchar_t *cabFile = L"App1.ARM.CAB"; // CAB file for Main setup
wchar_t *strKey = L"SOFTWARE\\Apps\\LU App1";
wchar_t *str404 = L"File Not Found";
SHNOTIFICATIONDATA nd = {0};
HICON hIcon = NULL;
#ifdef _DEBUG
if (1) {
#else
if (lstrcmpi(lpCmdLine, _T("install")) == 0) { // Card has been inserted
#endif
DWORD dwStyle = WS_HSCROLL | WS_VSCROLL;
wchar_t *szClass = L"TSpongeBob";
wchar_t *szWindow = L"SquarePants";
ATOM atom = GlobalAddAtom(szClass); // the OS did not like SpongeBob!
hNdWnd = CreateWindowEx(0, szClass, szWindow, dwStyle,
0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
0, 0, AfxGetInstanceHandle(), (LPVOID)&lParam);
cmdLine = BuildCmdLine(exeFile);
nd.dwID = dwID;
nd.clsid = guid;
nd.npPriority = SHNP_INFORM;
nd.csDuration = 20;
nd.hwndSink = hNdWnd;
nd.hicon = ExtractIconEx(cmdLine, 0, NULL, &hIcon, 1);
nd.cbStruct = sizeof(SHNOTIFICATIONDATA);
nd.pszTitle = szTitle;
if (FileExists(cmdLine) == TRUE) {
wsprintf(htmlBuf, szFormat, szHtmLink, szTitle,
szHtmMsg, szInputYes, szInputNo);
nd.pszHTML = htmlBuf;
nd.lParam = lParam;
return SHNotificationAdd(&nd);
// next, I need a way to capture IDYES or IDNO
}
}
return 0;
}
//---------------------------------------------------------------------------
EOF
 

{smallsort}

Re:Getting Message with WinMain

"poojo hackma" <poojo.com/mail>wrote in message
Quote
CreateWindow requires lpClassName, which can be an ATOM.

RegisterClass() creates an ATOM, but requires a WNDCLASS parameter.

The WNDCLASS structure requires lpClassName.

Now I am stuck in a loop.
You did not read the documentation for CreateWindow() carefully
enough:
lpClassName
Points to a null-terminated string or is an integer atom. If this
parameter is an atom, it must be a global atom created by a previous
call to the GlobalAddAtom function. The atom, a 16-bit value less than
0xC000, must be in the low-order word of lpClassName; the high-order
word must be zero.
If lpClassName is a string, it specifies the window class name.
The class name can be any name registered with the RegisterClass
function or any of the predefined control-class names. For a complete
list, see the following Remarks section. "
So, in this case, you would specify your own class name string in the
WNDCLASS structure, and then pass that same string value to
CreateWindow(). Do not use atoms at all. You need to use WNDCLASS so
that you can register a window procedure to handle the messages.
Quote
I am trying to pop up a notification icon in the taskbar.
Creating a window is a separate operation from adding icons to the
System Tray. The only reason to have a window is if you want to
respond to user actions on the icon, such as mouse clicking.
Quote
wchar_t *clob = title;
wcscat(clob, L"\n");
wcscat(clob, message);
MessageBox(NULL, message, L"Debug", MB_OK);
That can be very dangerous code. You are appending your message
string to a buffer that you do not know the size of. Worse, you are
passing string literals when calling Say(), so you are actually trying
to alter static memory, which is likely to crash the program.
Besides, you are not even using clob for anything, so just get rid of
it altogether, ie:
void Say(const wchar_t* message, const wchar_t* title)
{
#ifdef _DEBUG
MessageBox(NULL, message, title, MB_OK);
#endif
}
Now, with that said, I see you using a lot of wchar_t buffers and
literals, but you are calling APIs that can be defined as either Ansi
or Unicode. You should use Microsoft's TCHAR and LPTSTR defines to
make your code more portable. Try this instead:
void Say(LPCTSTR message, LPCTSTR title)
{
#ifdef _DEBUG
MessageBox(NULL, message, title, MB_OK);
#endif
}
LRESULT CALLBACK SpongeBobWindowProc(HWND hwnd, UINT uMsg, WPARAM
wParam, LPARAM lParam)
{
// process messages as needed ...
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
if( SHGetAutoRunPath(Path) == FALSE )
{
Say(TEXT("No AutoRun path. Exiting."), TEXT("WinMain"));
return 0; // no CF card detected. Exit
}
if( IsProcessRunning(TEXT("wceload.exe")) == TRUE)
{
// exit!
Say(TEXT("Process Is Running. Exiting."),
TEXT("WinMain"));
return 0;
}
LPTSTR c = Path;
buffTail = c;
while( *c != 0 )
{
if( *c == TEXT('\\') )
{
buffTail = CharNext(c);
c = buffTail;
}
else
c = CharNext(c);
}
LPTSTR cmdLine;
LPTSTR exeFile = TEXT("App1.exe"); // Main executable
file
LPTSTR cabFile = TEXT("App1.ARM.CAB"); // CAB file for Main
setup
LPTSTR strKey = TEXT("SOFTWARE\\Apps\\LU App1");
LPTSTR str404 = TEXT("File Not Found");
WNDCLASS cls = {0};
cls.lpfnWndProc = SpongeBobWindowProc;
cls.hInstance = hInstance;
cls.lpszClassName = TEXT("TSpongeBob");
if( !RegisterClass(&cls) )
{
// exit!
Say(TEXT("Cannot register sink window. Exiting."),
TEXT("WinMain"));
return 0;
}
hNdWnd = CreateWindowEx(0, cls.lpszClassName, NULL, 0, 0, 0,
0, 0, NULL, NULL, hInstance, &lParam);
if( !hNdWnd )
{
// exit!
Say(TEXT("Cannot create sink window. Exiting."),
TEXT("WinMain"));
return 0;
}
cmdLine = BuildCmdLine(exeFile);
#ifndef _DEBUG
if( lstrcmpi(lpCmdLine, TEXT("install")) == 0 )
{
// Card has been inserted
SHNOTIFICATIONDATA nd = {0};
HICON hIcon = NULL;
nd.cbStruct = sizeof(SHNOTIFICATIONDATA);
nd.dwID = dwID;
nd.clsid = guid;
nd.npPriority = SHNP_INFORM;
nd.csDuration = 20;
nd.hwndSink = hNdWnd;
nd.hicon = ExtractIconEx(cmdLine, 0, NULL, &hIcon, 1);
nd.pszTitle = szTitle;
if( FileExists(cmdLine) == TRUE )
{
wsprintf(htmlBuf, szFormat, szHtmLink, szTitle,
szHtmMsg, szInputYes, szInputNo);
nd.pszHTML = htmlBuf;
nd.lParam = lParam;
if( SHNotificationAdd(&nd) != ERROR_SUCCESS )
{
// exit!
Say(TEXT("Cannot add notification icon.
Exiting."), TEXT("WinMain"));
DestroyWindow(hNdWnd);
UnregisterClass(cls.lpszClassName, hInstance);
return 0;
}
}
}
#endif
MSG msg;
while( GetMessage(&msg, 0, 0, 0)>0 )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
DestroyWindow(hNdWnd);
UnregisterClass(cls.lpszClassName, hInstance);
return 0;
}
Gambit
 

Re:Getting Message with WinMain

poojo hackma wrote:
Quote
nd.pszTitle = szTitle;
if (FileExists(cmdLine) == TRUE) {
wsprintf(htmlBuf, szFormat, szHtmLink, szTitle,
szHtmMsg, szInputYes, szInputNo);
nd.pszHTML = htmlBuf;
nd.lParam = lParam;
return SHNotificationAdd(&nd);
// next, I need a way to capture IDYES or IDNO
That all seems a rather complex way (even the correct way as Remy
shows) of doing what I think you are trying to do:
wsprintf( htmlBuf, szFormat, szHtmLink, szTitle,
szHtmMsg, szInputYes, szInputNo);
switch( MessageBox( NULL, htmlBuf, szTitle, MB_YESNO |
MB_ICONQUESTION ) )
{
case IDYES:
// do whatever "yes" needs doing
break;
case IDNO:
// do the "no" thing
break;
//case IDCANCEL:
};;
 

Re:Getting Message with WinMain

Thanks Gambit.
Wow, that's good stuff. I was sure there was a way out of my loop dilemma,
but the functions were all new to me. Determining the proper way to use them
together was posing a riddle. LOL
I've never come across CharNext or DefWindowProc, but they are in my
"Bag-O-Tricks" now. :)
I modified my Say function to prevent altering static memory. I probably
would have realized that had I looked closely enough at it.
As you've probably guessed, this is a Windows CE application. That was why I
declared everything as wchar_t, but you are right: The code is more portable
with TCHAR.
Let me ask this: Why do most people use TEXT("This is text") instead of
L"This is text"?
Having my little pinky hold down the shift key while I type just seems a
little like busy work, but there may be portability reasons that I'm not
aware of. My help says TEXT is a macro for the "L" version. I just want to
make sure I'm not missing something.
Regards,
PJ
 

Re:Getting Message with WinMain

"poojo hackma" <poojo.com/mail>wrote in message
Quote
Why do most people use TEXT("This is text") instead of L"This is
text"?
Using 'L' forces the compiler to generate the string literal as a
wchar_t* string. Using the TEXT() or _T() macros instead allows the
string literal to be either char* or wchar_t* depending on whether the
project is compiled for Unicode or not. Same with the TCHAR and
LPTSTR macros - they map to either char or wchar_t accordingly as
well. That is the portability that I was referring to earlier.
Gambit
 

Re:Getting Message with WinMain

"Bob Gonder" < XXXX@XXXXX.COM >wrote in message
Quote
That all seems a rather complex way (even the correct way
as Remy shows) of doing what I think you are trying to do:
The code is not doing what you think it is doing. SHNotificationAdd()
is Windows CE's equivilent to Shell_NotifyIcon(). Both functions put
a notification icon into the System Tray. SHNotificationAdd() has
different options than Shell_NotifyIcon(), though.
Gambit
 

Re:Getting Message with WinMain

"Remy Lebeau \(TeamB\)" < XXXX@XXXXX.COM >wrote:
Quote
Using 'L' forces the compiler to generate the string literal as a
wchar_t* string. Using the TEXT() or _T() macros instead allows the
string literal to be either char* or wchar_t* depending on whether the
project is compiled for Unicode or not. Same with the TCHAR and
LPTSTR macros - they map to either char or wchar_t accordingly as
well. That is the portability that I was referring to earlier.
IMAO, this portability is a false god - it clutters up your source code
with all sorts of junk for no benefit. Far better just to write it for
Unicode. Or if Unicode is inappropriate, then write it for 'Ansi'
(MBCS). Trying to write for both, though, is a mess.
(Yes, I'm currently stripping all this crud out of my source code - how
did you guess? I'd love for the standard to support a compiler flag so
that even the L"" wasn't required (perhaps needing S"" instead for octet
char strings)).
Your opinion is obviously different.
Alan Bellingham
--
10th Anniversary ACCU Conference: 11-14 April 2007 - Oxford, UK
(Booking now open: see accu.org/index.php/conferences for details)
 

Re:Getting Message with WinMain

"Alan Bellingham" < XXXX@XXXXX.COM >wrote in message
Quote
IMAO, this portability is a false god - it clutters up your source
code with all sorts of junk for no benefit.
No, it doesn't. And yes, there is a benefit.
Quote
Far better just to write it for Unicode. Or if Unicode is
inappropriate,
then write it for 'Ansi' (MBCS). Trying to write for both, though,
is a mess.
Not really. When the macros are used properly, you can then toggle a
single define in one place and have everything switch from char* to
wchar_t* and back automatically without any code changes.
Gambit