Is there a way to get the user's email address from within Windows via Win32 or .NET? Is there a registry key or API that contains this information?
EDIT: I have an application that emails my company if our application fails and I wanted to get a return email address so that we could respond that individual that experienced the crash. I'm currently getting the username, but that may not match the email name. Obviously I can get the user to enter his email address, but the interface would be a little friendlier if I could at least attempt to acquire the email address and have the user verify that the return email address is correct.
The only way I can think that this would make sense is in a Windows Active Directory environment. In this case you can query AD and see if there's an email address associated with the user's account. This will definitely work with MS Exchange and may also work with other enterprise email systems. For .Net you can use the classes in the System.DirectoryServices namespace. For Win32 you can use the ADSI API. You will have to read up on AD and create a suitable query to match your requirements.
Have you saved your e-mail address somewhere in the system? There is no standard place to look for. I always depends on the applications the user uses (Outlook, Outlook Express, TuhunderBird).
The best way to get the users e-mail address is to ask him.
Let me answer you by asking you this: Did you ever enter your email address when installing windows?
You could try using the NameUserPrincipal constant from the EXTENDED_NAME_FORMAT enumeration with the GetUserNameEx function.
NameUserPrincipal
The user principal name (for example, someone#example.com).
But I would only recommend using this as a pre-filled address in a prompt to the user.
There is more than a good chance it will fail with GetLastError of ERROR_NONE_MAPPED though if the info is not available.
I think the simple answer is no ... but of course the email address will be stored in their email program such as Outlook.
What is it you are trying to achieve?
Windows stores used email accounts in the "UserExtendedProperties" key in
HKEY_CURRENT_USER\Software\Microsoft\IdentityCRL
So you can get the email accounts using the following code:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#define MAX_KEY_LENGTH 255
#define MAX_VALUE_NAME 16383
void GetDefaultEmailAddress()
{
HKEY key;
TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name
DWORD cbName; // size of name string
TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name
DWORD cchClassName = MAX_PATH; // size of class string
DWORD cSubKeys = 0; // number of subkeys
DWORD cbMaxSubKey; // longest subkey size
DWORD cchMaxClass; // longest class string
DWORD cValues; // number of values for key
DWORD cchMaxValue; // longest value name
DWORD cbMaxValueData; // longest value data
DWORD cbSecurityDescriptor; // size of security descriptor
FILETIME ftLastWriteTime; // last write time
DWORD i, retCode;
TCHAR achValue[MAX_VALUE_NAME];
DWORD cchValue = MAX_VALUE_NAME;
if (RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Microsoft\\IdentityCRL\\UserExtendedProperties", NULL, KEY_READ, &key) == ERROR_SUCCESS)
{
// Get the class name and the value count.
retCode = RegQueryInfoKey(
key, // key handle
achClass, // buffer for class name
&cchClassName, // size of class string
NULL, // reserved
&cSubKeys, // number of subkeys
&cbMaxSubKey, // longest subkey size
&cchMaxClass, // longest class string
&cValues, // number of values for this key
&cchMaxValue, // longest value name
&cbMaxValueData, // longest value data
&cbSecurityDescriptor, // security descriptor
&ftLastWriteTime); // last write time
// Enumerate the email accounts subkeys, until RegEnumKeyEx fails.
if (cSubKeys)
{
wprintf(TEXT("\nNumber of email accounts used: %d\n"), cSubKeys);
for (i = 0; i < cSubKeys; i++)
{
cbName = MAX_KEY_LENGTH;
retCode = RegEnumKeyEx(key, i,
achKey,
&cbName,
NULL,
NULL,
NULL,
&ftLastWriteTime);
if (retCode == ERROR_SUCCESS)
{
wprintf(TEXT("(%d) %s\n"), i + 1, achKey);
}
}
}
}
}
When it comes to desktop applications used for email (i.e. MAPI clients) the place to look in order to enumerate these clients, is the Software\Clients\Mail Key in HKEY_LOCAL_MACHINE.
You will find there all installed [MAPI clients][1]..
You can also determine the default one by looking at:
HKEY_LOCAL_MACHINE\SOFTWARE\Clients\Mail\Default.
See also: article and tool / source code to download
Email addresses could be for web-based clients like gmail or they could be domain email addresses. Either way the implementation would have to be based on the specifics of the user's email setup. So the short answer is "no", at least there's no "one-size-fits-all" method.
There may be SOME email address stored within Windows, but for you to get a user's actual email address, you have to have them type it in, and to assure it, you have to handshake by sending them an activate email before you use it.
I know this is an old question but if like me you arrive here, as per this answer on Superuser
https://superuser.com/questions/836220/get-email-address-of-current-logged-in-user
On CMD run whoami /upn
It gives the user principal which is often the default email
https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/whoami
Related
Microsoft docs contain MSG structure page, which tells:
wParam
Type: WPARAM
Additional information about the message. The exact meaning depends on
the value of the message member.
lParam
Type: LPARAM
Additional information about the message. The exact meaning depends on
the value of the message member.
What is this "additional meaning"? They don't even link this page with others, which explain all of the possible additional meanings.
I had some very ugly code, which determined what registered hotkey was pressed, which looks like this:
RegisterHotKey(NULL, 1, MOD_NOREPEAT, VK_F2);
...
MSG msg;
while (GetMessage(&msg, NULL, WM_HOTKEY, WM_HOTKEY) != 0)
{
switch (htonl(msg.lParam) >> 8)
{
case VK_ESCAPE:
// handle escape
case VK_F1:
// handle F1
// possibly handle some more buttons
default:
// handle stuff
}
}
As you can see, it is not the most elegant way to do this. Not elegant at all.
So, is there a better way (the best way) to determine which key was pressed from the MSG structure returned from GetMessage/PeekMessage?
EDIT: I understand that "meaning depends on the value of the message", give me the link to the page which maps "value of the message"->"meaning", please, instead of writing comments on how stupid am I. Much thanks.
AFAIK, there is no unified message->meaning map page, but the document page of each individual window message. You need to know the message you want to use first, and then find the corresponding meaning in the document.
For example, the WM_HOTKEY you are using, according to the document:
wParam
The identifier of the hot key that generated the message. If the
message was generated by a system-defined hot key, this parameter will
be one of the following values.
lParam
The low-order word specifies the keys that were to be pressed in
combination with the key specified by the high-order word to generate
the WM_HOTKEY message. This word can be one or more of the following
values. The high-order word specifies the virtual key code of the hot
key.
is there a better way (the best way) to determine which key was pressed from the MSG structure returned from GetMessage/PeekMessage?
Determine the pressed hot key through the wParam parameter (The identifier of the hot key). The second parameter of RegisterHotKey specifies the identifier of the hot key
RegisterHotKey(NULL, 1, MOD_NOREPEAT, VK_F2);
...
switch (msg.wParam)
{
case 1:
// handle VK_F2
default:
// handle stuff
}
In my C++ application I have an IMAPITable with contacts.
In method 1, I search a contact and get contact properties, such as PR_DISPLAY_NAME_W ir PR_ENTRYID.
In method 2, I must receive an ID and I have to open this entry to get another property. For instance, for a contact I will need PR_ADDRTYPE_W and for a distribution list i will need all its members addresses.
Is PR_ENTRYID the best way to indentify a contact/distList (return id in 1) and find easily when required (2)? I supponse it is, since it is an unique value
and I see that pAddressBook->OpenEntry() can help me, passing the entryID as parameter.
First, is it correct? Can I find a contact (with the entryId) directly from the addressBook? In my AB I have 10 lists, the contact is in one of them
My problem is that I am not sure how to manage this ID, what to return in method 1 where I have:
pRows->aRow->lpProps[abPR_ENTRYID]
and how to use it in method 2 with the OpenEntry, where I need
ULONG cbEntryID
LPENTRYID lpEntryID
hr = pAddressBook->OpenEntry(
ULONG cbEntryID,
LPENTRYID lpEntryID,
LPCIID lpInterface, // nullptr
ULONG ulFlags, // 0L
ULONG FAR * lpulObjType,
LPUNKNOWN FAR * lppUnk // In my case
);
About returned value (lppUnk), for a contact it is a IMailUser* and for a Distribution List a IDistList*?
I'm afraid i am a bit lost at this moment...
Any help?
Thanks,
Diego
lpulObjType (out) parameter above in your code will tell you what the returned object type is - MAPI_MAILUSER vs MAPI_DISTLIST.
I want to know the time when a disk is made offline by user. Is there a way to know this through WMI classes or other ways?
If you cannot find a way to do it through the Win32 API/WMI or other, I do know of an alternate way which you could look into as a last-resort.
What about using NtQueryVolumeInformationFile with the FileFsVolumeInformation class? You can do this to retrieve the data about the volume and then access the data through the FILE_FS_VOLUME_INFORMATION structure. This includes the creation time.
At the end of the post, I've left some resource links for you to read more on understanding this so you can finish it off the way you'd like to implement it; I do need to quickly address something important though, which is that the documentation will lead you to
an enum definition for the _FSINFOCLASS, but just by copy-pasting it from MSDN, it probably won't work. You need to set the first entry of the enum definition to 1 manually, otherwise it will mess up and NtQueryVolumeInformationFile will return an error status of STATUS_INVALID_INFO_CLASS (because the first entry will be identified as 0 and not 1 and then all the entries following it will be -1 to what they should be unless you manually set the = 1).
Here is the edited version which should work.
typedef enum _FSINFOCLASS {
FileFsVolumeInformation = 1,
FileFsLabelInformation,
FileFsSizeInformation,
FileFsDeviceInformation,
FileFsAttributeInformation,
FileFsControlInformation,
FileFsFullSizeInformation,
FileFsObjectIdInformation,
FileFsDriverPathInformation,
FileFsVolumeFlagsInformation,
FileFsSectorSizeInformation,
FileFsDataCopyInformation,
FileFsMetadataSizeInformation,
FileFsMaximumInformation
} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
Once you've opened a handle to the disk, you can call NtQueryVolumeInformationFile like this:
NTSTATUS NtStatus = 0;
HANDLE FileHandle = NULL;
IO_STATUS_BLOCK IoStatusBlock = { 0 };
FILE_FS_VOLUME_INFORMATION FsVolumeInformation = { 0 };
...
Open the handle to the disk here, and then check that you have a valid handle.
...
NtStatus = NtQueryVolumeInformationFile(FileHandle,
&IoStatusBlock,
&FsVolumeInformation,
sizeof(FILE_FS_VOLUME_INFORMATION),
FileFsVolumeInformation);
...
If NtStatus represents an NTSTATUS error code for success (e.g. STATUS_SUCCESS) then you can access the VolumeCreationTime (LARGE_INTEGER) field of the FILE_FS_VOLUME_INFORMATION structure with the FsVolumeInformation variable.
Your final task at this point will be using the LARGE_INTEGER field named VolumeCreationTime to gather proper time/date information. There are two links included at the end of the post which are focused on that topic, they should help you sort it out.
See the following for more information.
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntifs/nf-ntifs-ntqueryvolumeinformationfile
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/ne-wdm-_fsinfoclass
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntddk/ns-ntddk-_file_fs_volume_information
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724280.aspx
https://blogs.msdn.microsoft.com/joshpoley/2007/12/19/datetime-formats-and-conversions/
I have a bunch of code currently to check if the PE is signed by my company but it only checks the signature (not written by me)
// hMsg was obtained earlier by using CryptQueryObject
DWORD dwSignerInfo;
bool ret = CryptMsgGetParam(hMsg,
CMSG_SIGNER_INFO_PARAM,
0,
NULL,
&dwSignerInfo);
PCMSG_SIGNER_INFO pSignerInfo = NULL;
pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
ret = CryptMsgGetParam(hMsg,
CMSG_SIGNER_INFO_PARAM,
0,
(PVOID)pSignerInfo,
&dwSignerInfo);
std::vector<BYTE> fileSerial;
fileSerial.assign(pSignerInfo->SerialNumber.pbData, pSignerInfo->SerialNumber.pbData + pSignerInfo->SerialNumber.cbData);
const std::array<BYTE, 16> k_serial = {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}
const std::vector<BYTE> k_SerialKey(k_serial.cbegin(), k_serial.cend());
if (fileSerial == k_SerialKey)
{
// Do stuff since signature is made by us
}
The above code looks like it works well enough but it doesn't seem tp really check the integrity of the file itself. I want to be able to verify that the executable did not get corrupted by a virus or something but kept the signature intact.
I was thinking that I can keep using CryptMsgGetParam and use the params
CMSG_COMPUTED_HASH_PARAM
CMSG_HASH_DATA_PARAM
These params return 2 different hashes, if I compare them and they match does it mean that my file matches the hash in the signature?
N.B. I looked at WinVerifyTrust but I feel like its wayyy overkill for what I want, all I want is verify the file still matches the file the signature was made for.
As with most "legacy" MSDN pages, the page for ReportEvent has too little information for me to make much sense of it. I've tried searching, but can't find a good, clean, simple example of the function's usage. Could anyone suggest one?
I ended up using this:
HANDLE eventLog;
WORD type;
const char* msg;
// ... snip ...
ReportEvent(eventLog, type, 0, 1, NULL, 1, 0, &LPCTSTR(msg), NULL);
Seems to work well enough.
Well this seems to be a very old thread, landed here looking for a good example of Report Event... but figured out you have not received any replies...and would have probably already found the solution.
The reason you see "Event Id not found" is because the EventViewer is not able to load/lookup the text resource to be displayed for the event Id. Sorry if last line sounded geeky.. but this is what i understand of EventLog:
-EventLogging has two aspects
Registering with EventLog (or in other terms creating EventSource)
Logging or Writing into Event Log
Viewing or Reading from log
When you register in event log, you simply specify a eventSource (any name that identifies that log) + EventMessageFile, Category File and SupportedEventTypes. Here EventMessageFile points to a DLL/EXE that contains your message descriptions/resources.
When you log an event, you simply log it with some data like EventID, Category ID and EventData. But when you view it using any EventViewer (or Windows eventVwr.exe) the viewer reads your events, looks for a DLL/EXE associated with your eventSource(pointed by EventMessageFile), and renders the decription from the resource section of that DLL/EXE.
This DLL is nothing but a simple resource file that was compiled using MessageCompiler, and contains a "MessageTable". This is done to provide culture specific event logging
This is the reason, When you export the log into XML/TXT etc from your EventViewer, It asks you if you want to Save it "with Display informaion" or "without display information", so that you can view it on computers that do not have EventMessageFile.
JFYI the reg entry is located at:
HKLM\CurrentControlSet\System\Services\EventLog\Application
one catch: If you're wondering how .Net does it..., it simply does it by providing a default EventMessageFile called EventLogMessage.dll (found under %SYSTEMROOT%\Microsoft.Net\Framework\vXXXX\)
As I recall it is a pain to set up correctly - you need to add messages to you application using the Message Compiler - if you skip this you won't see useful messages only error codes. Take a look at Creating a Windows NT Service by Using ATL for an example
The sample Windows Service C++, is a windows service reporting to event log, you can get the code from https://code.msdn.microsoft.com/windowsapps/CppWindowsService-cacf4948
in particular, the following function (quoted from ServiceBase.cpp) does it
//
// FUNCTION: CServiceBase::WriteEventLogEntry(PWSTR, WORD)
//
// PURPOSE: Log a message to the Application event log.
//
// PARAMETERS:
// * pszMessage - string message to be logged.
// * wType - the type of event to be logged. The parameter can be one of
// the following values.
//
// EVENTLOG_SUCCESS
// EVENTLOG_AUDIT_FAILURE
// EVENTLOG_AUDIT_SUCCESS
// EVENTLOG_ERROR_TYPE
// EVENTLOG_INFORMATION_TYPE
// EVENTLOG_WARNING_TYPE
//
void CServiceBase::WriteEventLogEntry(PWSTR pszMessage, WORD wType)
{
HANDLE hEventSource = NULL;
LPCWSTR lpszStrings[2] = { NULL, NULL };
hEventSource = RegisterEventSource(NULL, m_name);
if (hEventSource)
{
lpszStrings[0] = m_name;
lpszStrings[1] = pszMessage;
ReportEvent(hEventSource, // Event log handle
wType, // Event type
0, // Event category
0, // Event identifier
NULL, // No security identifier
2, // Size of lpszStrings array
0, // No binary data
lpszStrings, // Array of strings
NULL // No binary data
);
DeregisterEventSource(hEventSource);
}
}