It seems to me that MAPI (Windows Mail API) has issues with UTF8 (or maybe I did something wrong).
Code sample:
HMODULE m_hLib = LoadLibraryA("MAPI32.DLL");
if (m_hLib == NULL)
return SEND_MAIL_CANCELED;
LPMAPISENDMAIL SendMail;
SendMail = (LPMAPISENDMAIL) GetProcAddress(m_hLib, "MAPISendMail");
if (!SendMail)
return;
MapiFileDesc fileDesc;
ZeroMemory(&fileDesc, sizeof(fileDesc));
fileDesc.nPosition = (ULONG) -1;
fileDesc.lpszPathName = (LPSTR) filePath.toUtf8();
fileDesc.lpszFileName = (LPSTR) fileName.toUtf8();
MapiRecipDesc recipientData;
ZeroMemory(&recipientData, sizeof(recipientData));
recipientData.lpszName = (LPSTR) recipient.toUtf8();
recipientData.ulRecipClass = MAPI_TO;
MapiMessage message;
ZeroMemory(&message, sizeof(message));
message.ulReserved = CP_UTF8;
message.lpszSubject = (LPSTR) title.toUtf8();
message.nFileCount = 1;
message.lpFiles = &fileDesc;
message.nRecipCount = 1;
message.lpRecips = &recipientData;
int nError = SendMail(0, NULL, &message, MAPI_LOGON_UI | MAPI_DIALOG, 0);
title, filePath, fileName and recipient are all std::strings. As far as I know, UTF8 is compatible with ASCII (also NULL terminated), so its string can hold such values without any problems.
I'm converting to UTF8 from wstring in this way:
int requiredSize = WideCharToMultiByte(CP_UTF8, 0, data.c_str(), -1, 0, 0, 0, 0);
if(requiredSize > 0)
{
std::vector<char> buffer(requiredSize);
WideCharToMultiByte(CP_UTF8, 0, data.c_str(), -1, &buffer[0], requiredSize, 0, 0);
this->container.append(buffer.begin(), buffer.end() - 1);
}
container is a std::string object.
MAPISendMail() does not support UTF-8, only Ansi. If you need to send Unicode data, you have to use MAPISendMailHelper() on Windows 7 and earlier, or MAPISendMailW() on Windows 8 and later. This is clearly stated in the MAPISendMail() documentation.
On a side note, WideCharToMultiByte() includes the null terminator when you set the cchWideChar parameter to -1. As such, you are encoding and including that null terminator in your container data. You should instead set cchWideChar to the actual length of the string to avoid the null terminator completely:
int requiredSize = WideCharToMultiByte(CP_UTF8, 0, data.c_str(), data.length(), 0, 0, 0, 0);
if (requiredSize > 0)
{
std::vector<char> buffer(requiredSize);
WideCharToMultiByte(CP_UTF8, 0, data.c_str(), data.length(), &buffer[0], requiredSize, 0, 0);
container.append(buffer.begin(), buffer.end());
}
On http://msdn.microsoft.com/en-us/library/windows/desktop/dd296721.aspx it states "On Windows 7 and earlier: Use MAPISendMailHelper to send a message" but at the bottom of http://msdn.microsoft.com/en-us/library/windows/desktop/hh802867.aspx it states "Minimum supported" is Windows 8. Seems like contradictory information and therefore it's unclear whether MAPISendMailHelper is really for Windows 7 and earlier.
Related
I wrote a font parser and renderer based on some functionality in the freetype library, but it currently only works for font files that I specify. I'd like to be able to retrieve fonts from the Windows Font Mapper and then parse and render them, but I can't figure out how to get the actual font data from a logical font.
I thought that the easy way to accomplish this would be to get the font file name from the logical font, but based on other stack overflow posts, there isn't any good solution to this because there isn't a 1 to 1 mapping of physical fonts to the logical font you specify.
This code shows how I'm currently retrieving a handle to a logical font:
HFONT windowsFont = CreateFontA(72, 0, 0, 0, 0,
0, 0, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH, "Arial");
HDC deviceContext = GetDC(windowHandle);
SelectObject(deviceContext, windowsFont);
DWORD fontSize = GetFontData(deviceContext, 0, 0, NULL, 0);
void *fontData = malloc(fontSize);
fontSize = GetFontData(deviceContext, 0, 0, fontData, 0);
char *fontFileData;
size_t fontFileSize;
// This is a function that I wrote that does what you'd expect. It opens
// a file, reads all the bytes to a buffer and closes the file
readFileToBuff(&fontFileData, &fontFileSize, "c:/windows/fonts/arial.ttf");
assert(fontFileSize == fontSize); // This passes
assert(((char)fontFileData) == ((char)fontData)); // This fails
Based on this stack overflow post which is for Java, I'm thinking that what I want to do may not be possible. It seems that the only solution may be to look at all the system font files and try to figure out what they are.
How to get ttf font data from system fonts in java
This surprises me though, because it seems that it would be relatively common for a program to want to render fonts themselves, without relying on the Windows renderer. Does anyone know of a way to get the font data, or how other people have solved this problem?
I don't understand why it's getting the exact same amount of bytes as
the file, but the data isn't the same.
From the official sample, I found the correct way to use GetFontData.
This is the modified code, and the returned data is the same as fontFileData.
HRESULT hr = S_OK;
LPVOID ptr = NULL;
HGLOBAL hGlobal = NULL;
...
HFONT windowsFont = CreateFontA(72, 0, 0, 0, 0,
0, 0, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH, "Arial");
HDC deviceContext = GetDC(hWnd);
SelectObject(deviceContext, windowsFont);
DWORD fontSize = GetFontData(deviceContext, 0, 0, NULL, 0);
hGlobal = GlobalAlloc(GMEM_MOVEABLE, fontSize);
ptr = GlobalLock(hGlobal);
if (!ptr)
{
hr = HRESULT_FROM_WIN32(GetLastError());
fwprintf(stderr, L"ERROR: Could not lock global memory object: %08X\n", hr);
}
else
{
if (GetFontData(deviceContext, 0, 0, ptr, fontSize) == GDI_ERROR)
{
fwprintf(stderr, L"ERROR: Could not get font data\n");
hr = E_UNEXPECTED;
}
GlobalUnlock(hGlobal);
}
char *fontFileData;
size_t fontFileSize;
// This is a function that I wrote that does what you'd expect. It opens
// a file, reads all the bytes to a buffer and closes the file
readFileToBuff(&fontFileData, &fontFileSize, "c:/windows/fonts/arial.ttf");
assert(fontFileSize == fontSize); // This passes
assert(((char)fontFileData) == ((char)fontData)); // This fails
I'm trying to create a list of partitions and their volumes of all the (fixed) disks in the system (Something like: PhyiscalDrive0, Partition 1, C:\; PhyiscalDrive0, Partition 2, D:\; ...) . I already got the list of installed disks via SetupApi and IOCTL_STORAGE_GET_DEVICE_NUMBER, as well as the number of partition.
The problem I'm having is how to find out the drive letters that are mounted to a partiticular partition (in meaning of partition 1 of Physical drive is C:\, for example)?
Thanks in before for any help,
Willi K.
The API you probably want to use is the Storage Management API. This provides a way to query just about anything you want. In particular, the drive letters are part of the MSFT_Volume class. The API isn't the friendliest for C++, which is why I'm not providing a sample query, but there's a sample here that shows how to write queries.
Once you have obtained the drives through the setup api you need to obtain information about partitions (through IOCTL_DISK_GET_DRIVE_LAYOUT_EX) and especially their starting offset and length.
Here is the code I use inside my library libwindevblk (libwindevblk):
BOOL FindVolume(int diskno, PSMI_DEVBLK_ENTRY pDevBlkEntry)
{
HANDLE vol;
BOOL success;
TCHAR szNextVolName[MAX_PATH+1];
TCHAR szNextVolNameNoBSlash[MAX_PATH+1];
vol = FindFirstVolume(szNextVolName, MAX_PATH);
success = (vol != INVALID_HANDLE_VALUE);
while (success)
{
//We are now enumerating volumes. In order for this function to work, we need to get partitions that compose this volume
HANDLE volH;
PVOLUME_DISK_EXTENTS vde;
DWORD bret;
//For this CreateFile, volume must be without trailing backslash
StringCchCopy(szNextVolNameNoBSlash, MAX_PATH, szNextVolName);
szNextVolNameNoBSlash[_tcslen(szNextVolNameNoBSlash) - 1] = _T('\0');
volH = CreateFile(szNextVolNameNoBSlash,
FILE_READ_ATTRIBUTES | SYNCHRONIZE | FILE_TRAVERSE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, 0);
if (volH != INVALID_HANDLE_VALUE)
{
bret = sizeof(VOLUME_DISK_EXTENTS) + 256 * sizeof(DISK_EXTENT);
vde = (PVOLUME_DISK_EXTENTS)malloc(bret);
if (DeviceIoControl(volH, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, (void *)vde, bret, &bret, NULL))
{
for (unsigned i = 0; i < vde->NumberOfDiskExtents; i++)
{
if (vde->Extents[i].DiskNumber == diskno &&
vde->Extents[i].StartingOffset.QuadPart == pDevBlkEntry->StartingOffset.QuadPart &&
vde->Extents[i].ExtentLength.QuadPart == pDevBlkEntry->PartitionLength.QuadPart)
{
CHAR szVolumeName[MAX_PATH + 1] = { 0 };
CHAR szFileSystemName[MAX_PATH + 1] = { 0 };
DWORD dwSerialNumber = 0;
DWORD dwMaxFileNameLength = 0;
DWORD dwFileSystemFlags = 0;
if (GetVolumeInformation(szNextVolName,
szVolumeName, _countof(szVolumeName),
&dwSerialNumber,
&dwMaxFileNameLength,
&dwFileSystemFlags,
szFileSystemName,
_countof(szFileSystemName)))
{
_tcsncpy(pDevBlkEntry->szRootPathName, szNextVolName, MAX_PATH);
_tcsncpy(pDevBlkEntry->szVolumeName, szVolumeName, MAX_PATH);
_tcsncpy(pDevBlkEntry->szFileSystemName, szFileSystemName, MAX_PATH);
pDevBlkEntry->dwSerialNumber = dwSerialNumber;
pDevBlkEntry->dwFileSystemFlags = dwFileSystemFlags;
}
else
{
DWORD dwErr = GetLastError();
printf("%lu", dwErr);
}
DWORD length = 0;
TCHAR pathnames[MAX_PATH + 1] = { 0 };
if (GetVolumePathNamesForVolumeName(szNextVolName, (LPTSTR)pathnames, MAX_PATH, &length))
{
_tcsncpy(pDevBlkEntry->szVolumePathName, pathnames, MAX_PATH);
}
free(vde);
CloseHandle(volH);
FindVolumeClose(vol);
return TRUE;
}
}//for
}
free(vde);
CloseHandle(volH);
}
success = FindNextVolume(vol, szNextVolName, MAX_PATH) != 0;
}
FindVolumeClose(vol);
return FALSE;
}
GetWindowThreadProcessId(hwndFoundWindow, &dwTrayProcessID);
HANDLE hTrayProc = OpenProcess(PROCESS_ALL_ACCESS, 0, dwTrayProcessID);
int iButtonsCount = SendMessage(hwndFoundWindow, TB_BUTTONCOUNT, 0, 0);
LPVOID lpData = VirtualAllocEx(hTrayProc, NULL, sizeof(TBBUTTON), MEM_COMMIT, PAGE_READWRITE);
int iButton;
DWORD dwBytesRead;
TBBUTTON buttonData;
dwBytesRead = -1;
int chk_data = (int)SendMessage(hwndFoundWindow, TB_GETBUTTON, iButton, (LPARAM)lpData);
ReadProcessMemory(hTrayProc, lpData, &buttonData, sizeof(TBBUTTON), &dwBytesRead);
int len_text = (int)SendMessage(hwndFoundWindow, TB_GETBUTTONTEXTW, buttonData.idCommand, (LPARAM)lpData);
till now, i know the length of button's text but i also need to get the text to display on console.
my problem is i do not really know how to get that text from the button. please kindly help.
what i am trying is ... trying to access to lpData to get the string inside, but could not do that.
My first comment is that you need to add error checking to your code. As far as I can see, you perform no checking of return values. Any of the API functions you call could fail. If you don't check return values for errors then you have no way of diagnosing where you went wrong.
For instance, starting with GetWindowThreadProcessId, you need to write it like this:
if (GetWindowThreadProcessId(hwndFoundWindow, &dwTrayProcessID) == 0)
{
// handle error
}
And so on for all the other functions. Consult MSDN carefully to understand how each function signals failure.
Now to the main part of the question. I believe that it is the TB_GETBUTTONTEXTW message that is giving you trouble. You need to write it like this:
LRESULT len = SendMessage(hwndFoundWindow, TB_GETBUTTONTEXTW,
buttonData.idCommand, NULL);
if (len == -1)
{
// handle error
}
size_t size = sizeof(wchar_t)*(len+1);
LPVOID lpData = VirtualAllocEx(hTrayProc, NULL, size, MEM_COMMIT, PAGE_READWRITE);
if (lpData == NULL)
{
// handle error
}
len = SendMessage(hwndFoundWindow, TB_GETBUTTONTEXTW,
buttonData.idCommand, (LPARAM)lpData);
if (len == -1)
{
// handle error
}
wchar_t* str = new wchar_t[len+1];
if (!ReadProcessMemory(hTrayProc, lpData, (LPVOID)str, size, NULL))
{
// handle error
}
// the text is now in str, as a null-terminated UTF-16 string
delete[] str;
You need this: (see documentation of TB_GETBUTTONTEXTW).
WCHAR *buffer ;
int len_text = (int)SendMessage(hwndFoundWindow, TB_GETBUTTONTEXTW,
buttonData.idCommand, (LPARAM)NULL);
buffer = (WCHAR*)malloc(sizeof(WCHAR) * (len_text + 1)) ;
SendMessage(hwndFoundWindow, TB_GETBUTTONTEXTW,
buttonData.idCommand, (LPARAM)buffer);
....
free(buffer) ;
I am trying to access the ListView control (located within an Dialog) in another application, and get the data from within the control. Here is the Win32 code (with appropiate comments) that I am writing :
HWND hListView32 = hRoot; //HANDLE to the ListView control within the Dialog, having class name - "SysListView32"
int cnt = (int) ::SendMessage(hListView32, LVM_GETITEMCOUNT, 0, 0L); //returns CORRECT item count of the ListView Control
int nItem=0,nRes;
for(int nItem=0;nItem<cnt;nItem++)
{
LVITEM LvItem; // ListView Item struct
char Text[255]={0};
char Temp[255]={0};
char Temp1[255]={0};
memset(&LvItem,0,sizeof(LvItem));
LvItem.mask=LVIF_TEXT;
LvItem.iSubItem=1; //Trying to get the 2nd Colomn text
LvItem.pszText=Text; //Does not returns any Text, after the below SendMessage is executed???
LvItem.cchTextMax=256;
LvItem.iItem=nItem;
nRes = (int)::SendMessage(hListView32,LVM_GETITEMTEXT, nItem, (LPARAM)&LvItem);
DWORD dd = ::GetLastError(); //returns 0
}
Though the code is executing, I am not getting any data from within the control. However, I am able to retrieve the correct Item count from within the control, but no data.
Another approach maybe would be to use an MSAA hook to get the data. But that would be a very long and cumbersome process. Running out of ideas here. Pls help.
Thanks,
There a few possibilities.
DLL Injection Using windows hooks. Pros: simple and straight forward. Cons: many processes get this dll loaded.
DLL Injection Making process to load library by opening it for debugging, allocating a chunc of virtual memory using VallocEx in the context of this process, writing it's memory with WriteProcessMemory and creating a remote thread with start address of LoadLibrary function. Pros: a single process is affected. Cons: A bit more complex than hooks solution.
Read of process memory. Same as option 2 but instead of writing this memory and executing the code remotely, send the message LVM_GETITEMTEXT to the window in question providing a valid known memory location and then read that location with ReadProcessMemory.
ListView messages that pass around buffers only work within the address space of the process that owns the ListView. You will have to use VirtualAllocEx() to allocate a memory block within that same process, then you can write to it with WriteProcessMemory() and have the ListView fill it as needed, then you can read it with ReadProcessMemory() and deallocate it with VirtualFreeEx().
Try this (error handling omitted for brevity):
HWND hListView32 = hRoot;
int cnt = (int) ::SendMessage(hListView32, LVM_GETITEMCOUNT, 0, 0);
if (cnt > 0)
{
DWORD dwProcessId;
GetWindowThreadProcessId(hListView32, &dwProcessId);
HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, dwProcessId);
LVITEM *pLvItem = (LVITEM*) VirtualAllocEx(hProcess, NULL, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE);
LPTSTR pText = (LPTSTR) VirtualAllocEx(hProcess, NULL, sizeof(TCHAR)*256, MEM_COMMIT, PAGE_READWRITE);
for(int nItem = 0; nItem < cnt; ++nItem)
{
TCHAR Text[256] = {0};
LVITEM LvItem = {0};
LvItem.mask = LVIF_TEXT;
LvItem.iSubItem = 1;
LvItem.pszText = pText;
LvItem.cchTextMax = 256;
LvItem.iItem = nItem;
WriteProcessMemory(hProcess, pLvItem, &LvItem, sizeof(LVITEM), NULL);
int nRes = (int) ::SendMessage(hListView32, LVM_GETITEMTEXT, nItem, (LPARAM)pLvItem);
if (nRes > 0)
ReadProcessMemory(hProcess, pText, &Text[0], sizeof(TCHAR)*nRes, NULL);
// use Text as needed...
}
VirtualFreeEx(hProcess, pText, 0, MEM_RELEASE);
VirtualFreeEx(hProcess, pLvItem, 0, MEM_RELEASE);
CloseHandle(hProcess);
}
I copypasted code by Remy Lebeau, but it is working very strange in my particular case. The number of elements is retreived correctly via SendMessage(listview, LVM_GETITEMCOUNT, 0, 0)
, but the cycle reads jast the same element every time! It is not the first or last element, not the selected, but seems to be random. Here is my code:
HWND win=FindWindowEx(NULL, NULL, _("TEventLogView"), NULL);
HWND listview=FindWindowEx(win, NULL, _("TListView"), NULL);
int cnt = (int) ::SendMessage(listview, LVM_GETITEMCOUNT, 0, 0);
if (cnt > 0)
{
DWORD dwProcessId;
GetWindowThreadProcessId(listview, &dwProcessId);
int n = grdEvents->GetNumberRows();
HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, dwProcessId);
LVITEM *pLvItem = (LVITEM*) VirtualAllocEx(hProcess, NULL, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE);
LPTSTR pText = (LPTSTR) VirtualAllocEx(hProcess, NULL, sizeof(TCHAR)*255, MEM_COMMIT, PAGE_READWRITE);
for(int nItem = 0; nItem < cnt; ++nItem)
{
// need to read 1 - 3 subitems
for (int j = 1; j < 4; j++)
{
TCHAR Text[255] = {0};
LVITEM LvItem = {0};
LvItem.mask = LVIF_STATE | LVIF_TEXT;
LvItem.pszText = pText;
LvItem.cchTextMax = sizeof(TCHAR)*255;
LvItem.iItem = nItem;
LvItem.iSubItem = j;
int nRes1 = WriteProcessMemory(hProcess, pLvItem, &LvItem, sizeof(LVITEM), NULL);
int nRes2 = (int) ::SendMessage(listview, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)pLvItem);
if (nRes2 > 0)
{
ReadProcessMemory(hProcess, pText, &Text[0], sizeof(TCHAR)*nRes2, NULL);
// insert into wxWidgets grid
grdEvents->SetCellValue(nItem, j - 1, Text);
}
}
VirtualFreeEx(hProcess, pText, 0, MEM_RELEASE);
VirtualFreeEx(hProcess, pLvItem, 0, MEM_RELEASE);
CloseHandle(hProcess);
}
}
I'm trying to read the .pdata section of a x64 exe.
I'm mapping the file to the memory, finding the .pdata section, and then I use it's PointerToRawData to get to the actual data of the section...
But then my "pdata" pointer points at a illegal address :(
This is what I do:
void* mappingHandle = CreateFileMapping(fileHandle,
NULL,
PAGE_READONLY,
0,
1,
NULL);
char* fileMemory = (char*)MapViewOfFile(mappingHandle, FILE_MAP_READ, 0, 0, 1);
IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)fileMemory;
IMAGE_SECTION_HEADER* pdataSectionHeader = NULL;
if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE) // "MZ" signature
{
IMAGE_NT_HEADERS* ntHeaders = (IMAGE_NT_HEADERS*)(fileMemory + dosHeader->e_lfanew);
if (ntHeaders->Signature == IMAGE_NT_SIGNATURE) // Supposed to be "PE"
{
unsigned int sectionCount = ntHeaders->FileHeader.NumberOfSections;
IMAGE_SECTION_HEADER* sectionHeaders = IMAGE_FIRST_SECTION(ntHeaders);
pdataSectionHeader = sectionHeaders + 3; // Going to .pdata section.
}
}
unsigned long pdataSize = pdataSectionHeader->SizeOfRawData;
char* pdata = fileMemory + pdataSectionHeader->PointerToRawData;
can anybody tell me what I doing wrong?
The problem was in the way I mapped the file to the memory.
I should have done it this way:
void* mappingHandle = CreateFileMapping(fileHandle,
NULL,
PAGE_READONLY,
0,
0, //Here: 0 instead of 1
NULL);