|
|
Comments and Discussions
|
|
 |

|
Thanks you very much it help me to resolve me my issue very fast... Thanks once again
|
|
|
|

|
Great article and application. This code made it very easy to add event logging to my Windows Service application.
|
|
|
|

|
You code writes a registry value in HKLM which has elevated security in Windows Vista/7 requiring the program to be run as administrator. Do you see any way around this restriction?
|
|
|
|

|
Any idea how to implement the above to log in the security section (given you've got local system permissions) ?
|
|
|
|

|
I haven't found a way to do this yet.
|
|
|
|

|
Hi Hans,
I'm trying to fully understand the sample code. What is the purpose of the class in the message DLL? From reading the article and poking around on my own Windows systems, it seems like the class is completely unnecessary. Shouldn't the DLL just contain a mc-compiled message table?
Thanks.
|
|
|
|

|
Adam J Richardson wrote: Shouldn't the DLL just contain a mc-compiled message table? The point of this article is to show an alternative to using the message compiler. The mc is the Microsoft-recommended technique. It is also IMHO tedious and requires you to maintain duplicate message strings (in some cases).
My suggestion is to try to set up a project using the mc, and then use my DLL. There is a good article on mc here: Using MC.exe, message resources and the NT event log in your own projects[^]
|
|
|
|

|
Hi Hans,
My purpose is to truly understand what's going on in this Windows subsystem because it interests me. I am not trying to find a quick fix. With that in mind I have some questions.
I think I get the MSG00001.bin file. It is the output of mc-compiling Message.mc, yes? Seems we need mc just this once for our minimal message table and then we never need touch it again.
I still don't understand why there is a class declaration, definition and instantiation in the message DLL. The class (CXEventMessageApp) appears to do nothing. What is it for?
Thanks for reading.
|
|
|
|

|
I extracted your example and ran the exe but ssaw nothing added to the Application log. Am I missing something? I'm using XP. I'm loggeds in as an admin.
Thanks, Doug Neumann
|
|
|
|

|
I have tried to compile the DLL in 64 bit and it says:
------ Build started: Project: XEventMessage, Configuration: Release x64 ------
Linking...
.\XEventMessage.def(4) : warning LNK4017: DESCRIPTION statement not supported for the target platform; ignored
Creating library c:\projects\solutions\x64\release\XEventMessage.lib and object c:\projects\solutions\x64\release\XEventMessage.exp
CVTRES : fatal error CVT1100: duplicate resource. type:MESSAGETABLE, name:1, language:0x0409
LINK : fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt
Any ideas?
|
|
|
|

|
Were you able to compile it?
|
|
|
|

|
Thanks for the ingeniously forged code concerning event logging.
Nevertheless I would like to get to know some special information:
The eventlog-viewer supports six event-types ( error, warning, information, success, success-audit, failure-audit), which come along with six icons.
For my project I attempted to insert an extra event-type into eventlog-viewer connected to an extra built icon, which, both, should work like system-supported event-types, described in your code, but I failed.
I was not able to insert a new eventtype to the just existing ones of the enum-list of the event-viewer. And I did not know where and how to insert an appropriate icon and how to connect both.
Have you an idea how to proceed in this operation?
Thanks chr
|
|
|
|

|
reading the comments, some pepole seemed to have problem writing to System log etc. I had the same problems, trying to write to a custom log (I mean, why would you stuff your logs together with the already nicely filled System or Application ones?).
here's the deal: if you register a source "ID1" under Application, registering it again under System won't work: if you watch the registry, the multi-string Application.Sources has ID1 in it. This key is maintained by event log system, afaik it's the key that the logger uses to find out where to log ID1, and afaik ReportEvent will still log to Application->ID1.
to get your app to log to System->ID1, or MyLog->ID1, delete Application->ID1, and remove ID1 from Application->Sources. Then add the key System->ID1 key, then reboot, then log.
another problem I found out about: suppose you want to log to MyLog->ID1, and that doesn't exist yet, the first run of your program might still log to Application, simply because at the time you write ReportEvent, the registry/even log system isn't updated yet. Second run works though.
btw it took me some time to figure this out, mainly because when you fiddle too hard with the event logger, it gets stuck in a bad state: after some trying out, no matter what I did, all logs went to System->ID1, although I modified the Sources key, deleted registry entries etc. After a reboot all was fixed.
suggestions to the author:
- add an option to remove the created registry keys (there are just too many coders using the registry that never clean up. No wonder people complain their machine runs slowly after they installed/removed x programs)
- allow user to choose logging to Application or custom log
- add option to delete all created stuff (all reg keys, *.evt file created under %SYSTEMROOT%\System32 in case of custom log)
- maybe check if key is created or exists already, add a sleep() if it's created, else check values instead of overwriting them each time the progrm starts
- (this is personal preference): use tabs or spaces, preferrably spaces, but not both, your source will be much more readable; also spaces at the end of a line have no use at all
modified on Friday, November 21, 2008 5:43 AM
|
|
|
|

|
The description for Event ID 1 from source xxxxxxxxxx:xxxxxx.xxxx cannot be found. Either the component that raises this event is not installed on your local computer or the installation is corrupted. You can install or repair the component on the local computer.
|
|
|
|

|
I copied the exe and dll in the demo download to Vista and tried it (running the exe "as administrator"). It worked exactly the same way it does on XP. Exactly the same entries in the event log.
Do you have the dll in the same directory as your exe?
|
|
|
|

|
On W2K3 server its not working properly because "::RegSetValueEx(.. _T("EventMessageFile").. REG_SZ ....) in method CXEventLog::RegisterSource. In Microsoft article (http://msdn2.microsoft.com/en-us/library/aa363634.aspx) its setting to "REG_EXPAND_SZ".
(sorry for my bad english).
|
|
|
|

|
Windows can be so complicated at times. I just want to write strings to the event log. No messing with message compliers and what ever. This is just what the doctor ordered!
Thanks
|
|
|
|

|
Hi,
First of all, thanks for the article, and code. It's great! However, I have one question. Does this code only work when the user is logged in as an administrator? I have this application that uses this code and it logs events fine when i am logged in as an admin. However, when I am logged in as a user, my application does not seem to log events. How can i get this working for non-admins. thanks. Any ideas are much appreciated.
Martin
|
|
|
|

|
Hi,
many thanks for submitting this code which we can all use and learn from.
I do not code in VB or in C++ but use a compiler called Visual Objects for our Win32 development. It has full access to structures, pointers, dlls and the API.
I was hoping to use the XEventMessage.dll in our app so we could append to the log without having to create umteen message DLL files.
The code I use to add to the event log is :-
hEventLog := RegisterEventSourceA( String2PSZ( '' ), String2PSZ( 'CashfacVBT' ) )
IF hEventLog != Null_Ptr
cbStringSize := SLen( cString ) + 1
hMsgs := GlobalAlloc( 0x40, cbStringSize )
IF hMsgs != Null_Ptr
cString := cString + _Chr( 0 )
MemCopy( hMsgs, @cString, cbStringSize )
iNumStrings := 1
IF !ReportEventA( hEventLog, iLogType, 0, iEventID, Null_Ptr, iNumStrings, cbStringSize, hMsgs, hMsgs )
Information( NTrim( GetLastError() ) )
ENDIF
GlobalFree( hMsgs )
ENDIF
DeregisterEventSource( hEventLog )
ENDIF
I have registered the DLL in...
HKLM\System\CurrentControlSet\Services\EventLog\Application\TESTVBT
EventMessageFile REG_SZ C:\WinNT\System32\XEventMessage.dll
TypesSupported REG_DWORD 7
The XEventMessage dll does reside in the System32 folder.
WHen I view the log my messages are there, however they are still prefixed with the standard garbage.
Any ideas as to what it is I might be doing wrong ?
Many thanks
Keith Hurst
|
|
|
|

|
Guys,
I managed to get it up and running by reading a little more of what was going on here. All I had to do is make sure I had the GENERIC_MESSAGE define set up within my IDE and then used this to pass into ReportEvent.
Again, many thanks for this.
Regards
Keith Hurst
|
|
|
|

|
Thank's a lot to you and others like Daniel Lohmann who spend time and
help us going over bstacles and to progress with our ability to wtite
inelegent and robust software.
|
|
|
|

|
yes, this is such a great help!
I was looking for ages for a way to simplify the process of non-managed windows events. This is perfect.
Good explanation too
Thanks heaps.
|
|
|
|

|
A project that compiles without any errors and COMMENTS. Wow, I love these kinds of samples.
|
|
|
|

|
I have not yet tried this but can you have multiple instances of the same XEventMessage objects running at the same time. I need to use logging in various places so instead of passing the same XEventMessage object around (possibly propagating the pointer to my XEventMessage object to other objects several layers deep), I just want to create an instance of the object where I need it. Would this cause any problems with registering the same application name multiple times?
|
|
|
|

|
Hye,
This is a very good article... I appreciate this kind of article as it is ready to reuse in other projects...
Thanks!!!
Jigar Mehta
(jigarmehta@gatescorp.com)
Software Developer
Gates Information Systems
|
|
|
|

|
Your project is very good thx was exactly the think I need for my project.
But one Question is it possible that my Application can delete the EventLog it made or to modyfy a older one?
MFG
Bardioc
|
|
|
|

|
hii,
i'm developing a mfc dll program and i must make an event in my dll. how can i create an event for my dll using mfc shared dll and the event can be used in program that use this dll.
please help me if u have any idea, thx a lot.
regards,
-xins
|
|
|
|

|
It is a good idea to use only one DLL for multiply clients to log messages.
I have used parts of your code and improved it as follows:
1. I made a COM object with a simple interface that has only 3 functions like this:
LogError(BSTR sMsg);
LogWarning(BSTR sMsg);
LogInfo(BSTR sMsg);
2. I link the resource with the "dummy message" together with this COM object.
3. I register the component as usually.
4. Any client can use this component for logging without any registration
just calling one of the above interface methods.
(During the first call one of the interface methods the COM object
is registrating the calling client for logging!)
The advantage is:
- no class has to be used with the client code (thin code)
- the COM object itself is registering the client for logging
- the client must not know where the DLL is on your system
It works fine!
Reinhard Dietrich
|
|
|
|

|
Fantastic. It is very nice to have.
VB programmers just get the job done by having App.LogEvent(), while it is not so simplest for us.
Is there any way one can get the source and/or the binaries of the nice COM wrapper dll? And any useful readme.txt on the same?
It would be great.
Thanks.
Raju
|
|
|
|

|
I'll do a small project on this subject and submit it to CodeProject soon...
|
|
|
|

|
Hi! Hans,
I got another question, do you know how to send msg to NT Event Viewer Log, but go to 'System' or 'Security' or a custom Log??? I was using 'RegisterEventSource' function and then 'ReportEvent' function, but the msg will always display on Application Log. I also tried 'OpenEventLog' function to open other Logs (ie. System) and pass that handle to 'ReportEvent', and the msg did show up on System Log. However, because the source name is not there, I cannot open that particular msg.
Do you know how to send msg to other Logs and also able to resolved using DLL. I did put the DLL in the System Log Registry, that part is correct.
Thanks a lot!
- Eva
|
|
|
|

|
Eva,
I have the exact same question and I have not yet found a solution. Please let me know if you found something.
Steve
|
|
|
|

|
hi steve,
i'm having the same problem as Eva. did you ever figure it out? i really need to write to the 'System' log as well. any help?
Eva wrote:
Hi! Hans,
I got another question, do you know how to send msg to NT Event Viewer Log, but go to 'System' or 'Security' or a custom Log??? I was using 'RegisterEventSource' function and then 'ReportEvent' function, but the msg will always display on Application Log. I also tried 'OpenEventLog' function to open other Logs (ie. System) and pass that handle to 'ReportEvent', and the msg did show up on System Log. However, because the source name is not there, I cannot open that particular msg.
Do you know how to send msg to other Logs and also able to resolved using DLL. I did put the DLL in the System Log Registry, that part is correct.
Thanks a lot!
- Eva
|
|
|
|

|
I have made it!
Modifying CXEventLog::RegisterSource to add a registry key to "SYSTEM\\CurrentControlSet\\Services\\Eventlog\\System\\" instead of "SYSTEM\\CurrentControlSet\\Services\\Eventlog\\Application\\" is enough. However, in CXEventLogTestDlg::CXEventLogTestDlg, the string resource AFX_IDS_APP_TITLE cannot be "XEventLogTest". I have tested several strings including "XEventLogTess", "XEventLogTesu", and other strings. All are OK--events can be inserted to the System log. But if AFX_IDS_APP_TITLE is "XEventLogTest", events are inserted into the Application log.
Pretty weird!!!
|
|
|
|
|

|
In response to this statement:
"All are OK--events can be inserted to the System log. But if AFX_IDS_APP_TITLE is "XEventLogTest", events are inserted into the Application log.
Pretty weird!!!"
Did you delete the registry key 'XEventLogTest' found under application before running your test?
|
|
|
|

|
Hi!
I am writing a program to send NT Event msg to the NT Event Viewer Log and encountering the following problem... I want to use a existing userid on the box to send the msg to NT Event Viewer Log. I used 'LookUpAccountName' function to get th Sid from the userid and I was able to put the msg up to the Event Viewer Log(via 'ReportEvent'). However, the userid will display as the native NT id (S-1-39061...).
So, do you know how to have the actual userid display on the NT Event Viewer Log??? I mean the userid is valid (because if not, then it won't go thru 'LookUpAccountName' and cannot pass into 'ReportEvent' to send to the Viewer Log)
Thanks in advance!
- Eva
|
|
|
|

|
In the CXEventLog::Write() method you will see the following code:
PSID pSid = GetUserSid();
LPCTSTR* lpStrings = &lpszMessage;
bRet = ::ReportEvent(m_hEventLog, wType, 0, 0x20000001L, pSid, 1, 0, lpStrings, NULL);
if (pSid)
HeapFree(GetProcessHeap(), 0, pSid);
This displays the user id in the event log record. Note that GetUserSid() is a private method in XEventLog.cpp.
|
|
|
|

|
Hi! Hans,
Thanks for replying. Yes, I did read the 'GetUserSid' function that you wrote. What I'm looking for is if I want to say using a particular 'userid' which exist on the box(ie. tester1). Not using the userid which start the current process.
For example, the current process is start by 'Administrator'. But I want to use userid=tester1 to send this msg to Event Viewer Log. I was able to send the msg, but the USERID part on the NT Event Viewer Log listed as (S-1-3906...) instead of 'tester1'. Do you know how to make it to list as 'tester1' on the NT Event Viewer Log???
-- I did tried use 'GetCurrentProcess' and 'GetTokenInformation' and it will display the current process's userid correctly.
Thanks, Eva
|
|
|
|

|
OK, I understand. I replaced call to GetUserSid() with this:
PSID pSid = NULL;
DWORD cbSid = 0;
char * pszDomain = NULL;
DWORD cbDomain = 0;
SID_NAME_USE snuType;
BOOL bSuccess = FALSE;
bSuccess = LookupAccountName((LPSTR) NULL, "user1",
pSid, &cbSid, pszDomain, &cbDomain, &snuType);
_ASSERTE(!bSuccess);
pSid = (PSID) HeapAlloc(GetProcessHeap(), 0, cbSid);
pszDomain = (char *) HeapAlloc(GetProcessHeap(), 0, cbDomain);
bSuccess = LookupAccountName((LPSTR) NULL, "user1",
pSid, &cbSid, pszDomain, &cbDomain, &snuType);
_ASSERTE(bSuccess);
LPCTSTR* lpStrings = &lpszMessage;
bRet = ::ReportEvent(m_hEventLog, wType, 0, 0x20000001L, pSid, 1, 0, lpStrings, NULL);
if (pSid)
HeapFree(GetProcessHeap(), 0, pSid);
if (pszDomain)
HeapFree(GetProcessHeap(), 0, pszDomain);
You will want to replace "user1" with your user id.
|
|
|
|

|
Hi! Hans,
It works!!!! Thank you sooooooo much for your help! I rated 5 on this! =)
Thanks & Regards, Eva
P.S. I probably have other questions on Event Logging, but I will start a different email thread.
|
|
|
|

|
Hi,
First, thanks for your work. Now the problem is that we can not remove this file while uninstallation. What's the solution?
Thanks
kevin
|
|
|
|

|
Have you tried deleting the registry entries first?
|
|
|
|

|
yes. While I saw the registry was removed, then i delete the file manully, but still failed.
|
|
|
|

|
Unless Event Viewer is running, there should not be a problem to delete the dll. I will let you know if I find anything more.
|
|
|
|

|
I have the same issue too...
How to remove it when uninstall or re-install.
Thanks.
-Steel
|
|
|
|

|
Hi Hans,
Great Example! Would you mind making the source code for XEventMessage.dll available? I don't really understand the message compiling part that well so I would like to compile it myself.
thanks,M
|
|
|
|

|
Complete source is included in the download. The dll project is in the XEventMessage directory.
Best wishes,
Hans
|
|
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
|
XEventLog shows how to integrate minimalist NT event logging into your application
| Type | Article |
| Licence | CPOL |
| First Posted | 22 Apr 2003 |
| Views | 154,732 |
| Bookmarked | 93 times |
|
|