I am trying to convert a wmf file to emf file. From what I've learned on Internet, the best solution looks like this.
BYTE* buffer;
HDC hdc = CreateMetaFileA(filename);
HMETAFILE hmf = CloseMetaFile(hdc);
UINT metasize = GetMetaFileBitsEx(hmf, 0, NULL);
buffer = (BYTE*)malloc(metasize);
HENHMETAFILE hEMF = SetWinMetaFileBits(metasize, buffer, NULL, NULL);
The idea here is to use CreateMetaFileA and CloseMetaFile to get HMETAFILE hmf.
Then I tried my code and the weird thing came. The handle hmf always points ??? in memory and the metasize is always 24 with different pictures. And hEMF is always None.
This is really sad because I spend my whole night on figuring out how to make the code work.
I do read a lot of materials including
http://math2.org/luasearch-2/luadist-extract/cdlua-5.2.dist/src/win32/wmf_emf.c
https://www-user.tu-chemnitz.de/~heha/viewzip.cgi/hs/wmfsave.zip/src/wmfsave.cpp?auto=CPP
Can anyone help me here? Thanks.
You need to initialize the METAFILEPICT structure.
Minimal example:
if (hmf) {
DWORD nSize = GetMetaFileBitsEx( hmf, 0, NULL );
if (nSize) {
BYTE *lpvData = new BYTE[nSize];
if (lpvData) {
DWORD dw = GetMetaFileBitsEx( hmf, nSize, lpvData );
if (dw) {
// Fill out a METAFILEPICT structure
mp.mm = MM_ANISOTROPIC;
mp.xExt = 1000;
mp.yExt = 1000;
mp.hMF = NULL;
// Get a reference DC
hDC = GetDC( NULL );
// Make an enhanced metafile from the windows metafile
hemf = SetWinMetaFileBits( nSize, lpvData, hDC, &mp );
// Clean up
ReleaseDC( NULL, hDC );
}
delete[] lpvData;
}
DeleteMetaFile( hmf );
}
My test code:
hdcMeta = CreateMetaFile(NULL);
hBrush = CreateSolidBrush(RGB(0, 0, 255));
Rectangle(hdcMeta, 0, 0, 100, 100);
MoveToEx(hdcMeta, 0, 0, NULL);
LineTo(hdcMeta, 100, 100);
MoveToEx(hdcMeta, 0, 100, NULL);
LineTo(hdcMeta, 100, 0);
SelectObject(hdcMeta, hBrush);
Ellipse(hdcMeta, 20, 20, 80, 80);
hmf = CloseMetaFile(hdcMeta);
UINT nSize = GetMetaFileBitsEx(hmf, 0, NULL);
Debug:
You can see nSize = 114
I suspect that you use CreateMetaFileA and CloseMetaFile to directly load the file name and return a handle to a Windows-format metafile is a wrong way.
Updated:
You can get the handle of WMF file in another way.
#include <windows.h>
#include <iostream>
#include <vector>
#pragma pack(1)
typedef struct tagWIN16RECT
{
WORD left;
WORD top;
WORD right;
WORD bottom;
} WIN16RECT;
typedef struct tagPLACEABLEMETAHEADER
{
DWORD key;
WORD hmf;
WIN16RECT bbox;
WORD inch;
DWORD reserved;
WORD checksum;
} PLACEABLEMETAHEADER;
#pragma pack()
HENHMETAFILE WINAPI ConvertWMFToEWMF(IN LPCWSTR lpszMetaFile)
{
HANDLE hFile = ::CreateFileW(
lpszMetaFile,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == NULL || hFile == INVALID_HANDLE_VALUE)
return NULL;
DWORD dwSize = ::GetFileSize(hFile, NULL);
std::vector<BYTE> data(dwSize);
DWORD dwRead;
BOOL bSuccess = ::ReadFile(hFile, &data[0], dwSize, &dwRead, NULL);
::CloseHandle(hFile);
HENHMETAFILE hEnhMetaFile = NULL;
if (bSuccess)
{
PLACEABLEMETAHEADER * hdr = (PLACEABLEMETAHEADER*)&data[0];
int iPlaceableHeaderSize = sizeof(PLACEABLEMETAHEADER);
int iOffset = 0;
if (hdr->key != 0x9AC6CDD7) //not placeable header
{
iOffset = 0; //offset remains zero
}
else
{
iOffset = iPlaceableHeaderSize; //file is offset with placeable windows metafile header
}
hEnhMetaFile = ::SetWinMetaFileBits(data.size(), &data[iOffset], NULL, NULL);
if (NULL == hEnhMetaFile)
{
DWORD dwError = GetLastError();
std::cout << "Failed with error code: " << dwError;
}
else
{
std::cout << "Success! Metafile opened and returned as enhanced metafile";
}
}
return hEnhMetaFile;
}
int main()
{
HENHMETAFILE hEMF = ConvertWMFToEWMF(L"C:\\Users\\strives\\Desktop\\AN00010.WMF");
HENHMETAFILE newHEMF = CopyEnhMetaFile(hEMF, L"new EMF.emf");
return 0;
}
This worked for me
CStatic * m_pictCtrl = (CStatic *)this->GetDlgItem(PICT_STATIC);
LPCSTR file = filePath;
ALDUSMFHEADER aldusmfHeader;
DWORD wBytesRead;
double xOri, xExt, yOri, yExt;
HANDLE fh = CreateFileA(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
ReadFile(fh, (void *)&aldusmfHeader, ALDUSMFHEADERSIZE, &wBytesRead, NULL);
xOri = aldusmfHeader.bbox.left;
xExt = aldusmfHeader.bbox.right - xOri;
if (aldusmfHeader.bbox.bottom < aldusmfHeader.bbox.top) {
yOri = aldusmfHeader.bbox.bottom;
yExt = aldusmfHeader.bbox.top - aldusmfHeader.bbox.bottom;
}
else {
yOri = aldusmfHeader.bbox.top;
yExt = aldusmfHeader.bbox.top - aldusmfHeader.bbox.bottom;
}
if (wBytesRead == -1 || wBytesRead < ALDUSMFHEADERSIZE)
{
AfxMessageBox(L" is not a placeable Windows metafile : it cannot be converted into EMF format.");
CloseHandle(fh);
return 0;
}
// Envelope in /100 cm
double Density = static_cast<double>(aldusmfHeader.inch);
double Top = static_cast<double>(aldusmfHeader.bbox.top) / Density;
double RawBottom = static_cast<double>(aldusmfHeader.bbox.bottom) / Density;
double Left = static_cast<double>(aldusmfHeader.bbox.left) / Density;
double RawRight = static_cast<double>(aldusmfHeader.bbox.right) / Density;
// In order to correctly import the EMF metafile into WORD, add one delta
double Bottom, Right, Delta, Rate = 0.1;
if (RawBottom > RawRight)
{
Delta = Rate * RawRight;
Right = RawRight + Delta;
Bottom = Right * RawBottom / RawRight;
}
else
{
Delta = Rate * RawBottom;
Bottom = RawBottom + Delta;
Right = Bottom * RawRight / RawBottom;
}
// Metafile header
SetFilePointer(fh, ALDUSMFHEADERSIZE, NULL, FILE_BEGIN);
METAHEADER mfHeader;
ReadFile(fh, (void *)&mfHeader, sizeof(METAHEADER), &wBytesRead, NULL);
// Allocate memory in order to save into memory bits after the Aldus header in the WMF metafile
// * 2 : 16 bits API
DWORD dwSize = mfHeader.mtSize * 2 * sizeof(BYTE);
BYTE *lpMFBits = (BYTE *)malloc(dwSize);
if (lpMFBits == nullptr)
{
AfxMessageBox(L"nullptr lpmfbits");
//cout << "Not enough memory to convert " << WMFFileName << " into EMF format." << endl;
CloseHandle(fh);
return 0;
}
// Bits after the Aldus header
SetFilePointer(fh, ALDUSMFHEADERSIZE, NULL, FILE_BEGIN);
ReadFile(fh, (void *)lpMFBits, dwSize, &wBytesRead, NULL);
if (wBytesRead == -1)
{
//cout << "Error while reading " << WMFFileName << " : impossible to convert it into EMF format." << endl;
free(lpMFBits);
CloseHandle(fh);
return 0;
}
// Save these bits into a memory enhanced metafile
// The memory enhanced metafile only contains 32 bits API functions : TextOut has been converted into ExtTextOutW,
// CreateFontIndirect has been converted into ExtCreateFontIndirectW, ...
METAFILEPICT MetaFilePict;
MetaFilePict.hMF = NULL;
MetaFilePict.mm = MM_ANISOTROPIC;
double Fact = 10.0 * Density;
MetaFilePict.xExt = static_cast<LONG>(Fact * (Right - Left));
MetaFilePict.yExt = static_cast<LONG>(Fact * (Bottom - Top));
HENHMETAFILE hMemoryEnhMetafile = SetWinMetaFileBits(dwSize, lpMFBits, NULL, &MetaFilePict);
free(lpMFBits);
CloseHandle(fh);
if (m_pictCtrl->GetEnhMetaFile() == NULL)
m_pictCtrl->SetEnhMetaFile(hMemoryEnhMetafile);
Related
I am trying to modify the existing AmCap application, available through Microsoft's SDK Direct Show samples, in order to get an image of the captured stream when I press the space button. Below is the point in which I am handling the space keydown.
case WM_KEYDOWN:
if((GetAsyncKeyState(VK_ESCAPE) & 0x01) && gcap.fCapturing)
{
StopCapture();
if(gcap.fWantPreview)
{
BuildPreviewGraph();
StartPreview();
}
}
else if ((GetAsyncKeyState(VK_SPACE) & 0x01))
{
IMediaControl *pMC = NULL;
HRESULT hr = gcap.pFg->QueryInterface(IID_IMediaControl, (void **)&pMC);
if (SUCCEEDED(hr)){
hr=pMC->Pause();
if (SUCCEEDED(hr)){
CaptureImage(TEXT("C:\\output.bmp"));
pMC->Run();
pMC->Release();
}else
ErrMsg(TEXT("Failed to pause stream! hr=0x%x"), hr);
}
else
ErrMsg(TEXT("Cannot grab image"));
}
break;
Below is the contents of the CaptureImage function.
HRESULT hr;
SmartPtr<IBasicVideo> pWC;
// If we got here, gcap.pVW is not NULL
ASSERT(gcap.pVW != NULL);
hr = gcap.pVW->QueryInterface(IID_IBasicVideo, (void**)&pWC);
if (pWC)
{
long bufSize;
long *lpCurrImage = NULL;
pWC->GetCurrentImage(&bufSize, NULL);
lpCurrImage = (long *)malloc(bufSize);
//
// Read the current video frame into a byte buffer. The information
// will be returned in a packed Windows DIB and will be allocated
// by the VMR.
hr = pWC->GetCurrentImage(&bufSize, lpCurrImage);
if (SUCCEEDED(hr))
{
HANDLE fh;
BITMAPFILEHEADER bmphdr;
BITMAPINFOHEADER bmpinfo;
DWORD nWritten;
memset(&bmphdr, 0, sizeof(bmphdr));
memset(&bmpinfo, 0, sizeof(bmpinfo));
bmphdr.bfType = ('M' << 8) | 'B';
bmphdr.bfSize = sizeof(bmphdr) + sizeof(bmpinfo) + bufSize;
bmphdr.bfOffBits = sizeof(bmphdr) + sizeof(bmpinfo);
bmpinfo.biSize = sizeof(bmpinfo);
bmpinfo.biWidth = 640;
bmpinfo.biHeight = 480;
bmpinfo.biPlanes = 1;
bmpinfo.biBitCount = 32;
fh = CreateFile(TEXT("C:\\Users\\mike\\Desktop\\output.bmp"),
GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
WriteFile(fh, &bmphdr, sizeof(bmphdr), &nWritten, NULL);
WriteFile(fh, &bmpinfo, sizeof(bmpinfo), &nWritten, NULL);
WriteFile(fh, lpCurrImage, bufSize, &nWritten, NULL);
CloseHandle(fh);
ErrMsg(TEXT("Captured current image to %s"), szFile);
return TRUE;
}
else
{
ErrMsg(TEXT("Failed to capture image! hr=0x%x"), hr);
return FALSE;
}
}
return FALSE;
The problem is that when I am trying to run the app, I receive an HRESULT (0x8000ffff) error when the GetCurrentImage function is being called.
On the other hand in case I execute the app through the VS debugger the code works just fine.
I tried to add a Sleep just after the stream pMC->Pause(), assuming that the problem was timing issue but that did not work.
Any ideas would be extremely helpful!
Thank you in advance.
I need to read binary file and display bytes at certain offset so i can change that bytes and then save an updated file. I don't really understand how can i achieve that. I'm using MFC/VS 2008
So, i'am opening file using WinApi and getting its content to BYTE buffer. But i'm not sure how to print data at certain offset to (for example) an editbox and the main quesiton - how to edit this data (like in HEX editor) and save updated file.
CFileDialog FileDlg(TRUE, "*", "*", OFN_FILEMUSTEXIST);
if(FileDlg.DoModal() == IDOK)
{
CString pathName = FileDlg.GetPathName();
//MessageBox(pathName, NULL, MB_OK);
// Implement opening and reading file in here.
//Change the window's title to the opened file's title.
//CString fileName = FileDlg.GetFileTitle();
//SetWindowText(fileName);
HANDLE hFile = CreateFile(pathName.GetString(), GENERIC_READ | GENERIC_WRITE, NULL,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if(!hFile)
return;
DWORD dwSize = GetFileSize(hFile, NULL);
BYTE *Content = (BYTE *)malloc(dwSize);
DWORD dwRead;
if(!ReadFile(hFile, Content, dwSize, &dwRead, NULL))
return;
}
Here is a solution with owner draw ListBox (size=fixed-sized, sort=false)
class CListHex : public CListBox
{
public:
std::vector<BYTE> Buffer;
CRect SaveItemRect;
CEdit Edit;
int Index;
void setup()
{
if (Edit.m_hWnd && IsWindow(Edit.m_hWnd))
return;
Edit.Create(WS_CHILD | WS_BORDER | ES_CENTER, CRect(0, 0, 0, 0), this, 1);
Edit.SetFont(GetFont());
Edit.SetLimitText(2);
SetItemHeight(0, 21);
}
void read()
{
HANDLE hfile = CreateFile(L"in.txt", GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hfile != INVALID_HANDLE_VALUE) //****CHANGED****
{
DWORD size = GetFileSize(hfile, NULL);
Buffer.resize(size);
ReadFile(hfile, &Buffer[0], size, 0, NULL);
CloseHandle(hfile);
for (int i = 0; i <= (int)Buffer.size() / 16; i++)
AddString(0);
}
else
{
MessageBox(L"error");
}
}
void write()
{
HANDLE hFile = CreateFile(L"out.txt", GENERIC_WRITE, NULL, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hfile != INVALID_HANDLE_VALUE) //****CHANGED****
{
WriteFile(hFile, &Buffer[0], Buffer.size(), 0, 0);
CloseHandle(hFile);
}
else
{
MessageBox(L"error");
}
}
void DrawItem(LPDRAWITEMSTRUCT di)
{
SaveItemRect = di->rcItem;
CRect r = di->rcItem;
r.right = r.left + r.Width() / 16;
HBRUSH brush = (HBRUSH)SelectObject(di->hDC, GetStockObject(WHITE_BRUSH));
FillRect(di->hDC, &di->rcItem, brush);
for (int i = 0; i < 16; i++)
{
unsigned int cursor = di->itemID * 16 + i;
if (cursor >= Buffer.size())
break;
CString s;
s.Format(L"%02X", Buffer[cursor]);
DrawText(di->hDC, s, s.GetLength(), r, DT_EDITCONTROL|DT_CENTER|DT_VCENTER|DT_SINGLELINE);
}
}
void OnLButtonDown(UINT f, CPoint p)
{
CListBox::OnLButtonDown(f, p);
setup();
int w = SaveItemRect.Width() / 16;
CRect r = SaveItemRect;
r.right = r.left + w;
for (int i = 0; i < 16; i++)
{
if (r.PtInRect(p))
{
unsigned int index = GetCurSel() * 16 + i;
if (index >= Buffer.size())
return;
Index = index;
GetParent()->SetRedraw(0);
CString s;
s.Format(L"%02X", Buffer[Index]);
Edit.SetWindowText(s);
Edit.SetWindowPos(0, r.left, r.top, r.Width(), r.Height(), SWP_NOZORDER | SWP_NOREDRAW | SWP_SHOWWINDOW);
Edit.SetFocus();
GetParent()->SetRedraw(1);
break;
}
r.OffsetRect(w, 0);
}
}
//******CHANGED******
void MeasureItem(LPMEASUREITEMSTRUCT m) { m->itemHeight=21; }
int CompareItem(LPCOMPAREITEMSTRUCT) { return 0; }
//******CHANGED******
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CListHex, CListBox)
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
In addition,
You can add subclass for CEdit
Override CMyEdit::OnKillFocus() to close the edit box
Override CMyEdit::OnChar to accept hexadecimal characters only
Read Edit string then convert to unsigned char and assign it to Buffer[Index].
Override CListHex::OnVScroll to close the edit box
//CHANGED:
To create the function try to do it manually, to make sure it get the right flags:
list.Create(WS_VSCROLL | WS_BORDER | WS_CHILD | WS_VISIBLE | LBS_USETABSTOPS | LBS_OWNERDRAWFIXED , CRect(10, 10, 450, 350), this, 1001);
list.read();
I am trying to use the enhanced video renderer to take a snapshot, image of the current rendered stream. I am able to display a video feed either from a file or capture card. When I run
if (pDisplay)
{
BITMAPINFOHEADER lpHeader = { 0 };
BYTE* lpCurrImage = NULL;
DWORD bitmapSize = 0;
LONGLONG timestamp = 0;
lpHeader.biSize = sizeof(BITMAPINFOHEADER);
if (SUCCEEDED(hr = pDisplay->GetCurrentImage(&lpHeader, &lpCurrImage, &bitmapSize, ×tamp)))
{
the output image data is 0, see image below:
For some reason, when I use VMR7 or 9, the image works fine and has data (rendering the same video) however EVR does not get an image. The bitmap that outputs is 14kb (which is the header information).
For more info, here is the code that I use to render the EVR:
HRESULT InitializeWindowlessEVR(IGraphBuilder* pGraph, IBaseFilter** ppEVR)
{
IBaseFilter* pEvr = NULL;
CComPtr<IMFGetService> pServices;
CComPtr<IMFQualityAdvise2> pAdvise;
if (!ppEVR)
return E_POINTER;
*ppEVR = NULL;
// Create the VMR and add it to the filter graph.
HRESULT hr = CoCreateInstance(CLSID_EnhancedVideoRenderer, NULL,
CLSCTX_INPROC, IID_IBaseFilter, (void**)&pEvr);
if (SUCCEEDED(hr))
{
hr = pGraph->AddFilter(pEvr, L"Enhanced Video Renderer");
if (SUCCEEDED(hr))
{
// Update the window settings
CHECK_HR(pEvr->QueryInterface(IID_IMFGetService, (void**)&pServices));
CHECK_HR(pServices->GetService(MR_VIDEO_RENDER_SERVICE, IID_IMFVideoDisplayControl, (void**)&pVideoDisplay));
CHECK_HR(pVideoDisplay->SetVideoWindow(ghApp));
CHECK_HR(pVideoDisplay->SetAspectRatioMode(MFVideoARMode_PreservePicture));
}
pEvr->AddRef();
*ppEVR = pEvr;
pEvr->Release();
pEvr = NULL;
}
done:
return hr;
}
Please help me figure out why I am unable to get an image for EVR, I do not want to go back and use VMR9. I can post more code if it helps. Thanks in advance!
Answer:
BOOL CaptureImage(LPCTSTR szFile)
{
if (pVideoDisplay)
{
BYTE* lpCurrImage = NULL;
BITMAPINFOHEADER lpHeader = { 0 };
DWORD bitmapSize = 0;
LONGLONG timestamp = 0;
lpHeader.biSize = sizeof(BITMAPINFOHEADER);
if (SUCCEEDED(pVideoDisplay->GetCurrentImage(&lpHeader, &lpCurrImage, &bitmapSize, ×tamp)))
{
// Create a new file to store the bitmap data
HANDLE hFile = CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_READ, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
DWORD dwWritten;
BITMAPFILEHEADER fileHeader;
fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
fileHeader.bfReserved1 = 0;
fileHeader.bfReserved2 = 0;
fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + lpHeader.biSizeImage;
fileHeader.bfType = 0x4d42;
// Write the bitmap header and bitmap bits to the file
WriteFile(hFile, (LPCVOID)&fileHeader, sizeof(BITMAPFILEHEADER), &dwWritten, 0);
WriteFile(hFile, (LPCVOID)&lpHeader, sizeof(BITMAPINFOHEADER), &dwWritten, 0);
WriteFile(hFile, (LPCVOID)lpCurrImage, bitmapSize, &dwWritten, 0);
CloseHandle(hFile);
CoTaskMemFree(lpCurrImage);
return TRUE;
}
else
{
return FALSE;
}
}
return FALSE;
}
I'm creating file deletion tool, so working with raw disk access. Have made some functions to read data.
A bit sorry because posting so much code, but not sure where is the real problem.
struct Extent
{
LONGLONG ClustersCount;
LARGE_INTEGER Lcn; //lcn - logical cluster number - the offset of a cluster from some arbitary point within volume
Extent() : ClustersCount(), Lcn()
{}
Extent(LONGLONG clustersCount, LARGE_INTEGER lcn) : ClustersCount(clustersCount), Lcn(lcn)
{}
};
typedef std::vector<Extent> ExtentsVector;
bool GetFileExtentPoints(const std::wstring& filePath, ExtentsVector& output)
{
output.clear();
DWORD err = ERROR_SUCCESS;
HANDLE file = CreateFile(filePath.c_str(), FILE_READ_ATTRIBUTES, (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), NULL, OPEN_EXISTING, 0, 0);
if (file != INVALID_HANDLE_VALUE)
{
STARTING_VCN_INPUT_BUFFER vcnStartBuffer = {};
RETRIEVAL_POINTERS_BUFFER pointsBuffer = {};
DWORD deviceIoControlDataritten = 0;
do
{
if (DeviceIoControl(file, FSCTL_GET_RETRIEVAL_POINTERS, &vcnStartBuffer, sizeof(vcnStartBuffer), &pointsBuffer, sizeof(pointsBuffer), &deviceIoControlDataritten, NULL))
{
Extent extent(pointsBuffer.Extents->NextVcn.QuadPart - pointsBuffer.StartingVcn.QuadPart, pointsBuffer.Extents[0].Lcn);
output.push_back(extent);
CloseHandle(file);
return true;
}
if (pointsBuffer.ExtentCount == 0) //small files could be stroed in master file table, so this part shouldn't always return false
{
CloseHandle(file);
return false;
}
Extent extent(pointsBuffer.Extents->NextVcn.QuadPart - pointsBuffer.StartingVcn.QuadPart, pointsBuffer.Extents[0].Lcn);
output.push_back(extent);
vcnStartBuffer.StartingVcn = pointsBuffer.Extents->NextVcn;
}
while (ERROR_MORE_DATA == GetLastError());
CloseHandle(file);
}
return false;
}
bool PermanentDeleteFile/*for now just read...*/(const std::wstring& filePath)
{
ExtentsVector extents;
if (!GetFileExtentPoints(filePath, extents))
return false;
DWORD sectorsPerCluster = 0;
DWORD bytesPerSector = 0;
LARGE_INTEGER fileSize = {};
HANDLE file = CreateFile(filePath.c_str(), FILE_READ_ATTRIBUTES, (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), NULL, OPEN_EXISTING, 0, 0);
if (file != INVALID_HANDLE_VALUE)
{
TCHAR drive[] = L"?:\\";
drive[0] = filePath[0];
if (!GetDiskFreeSpace(drive, §orsPerCluster, &bytesPerSector, NULL, NULL))
{
CloseHandle(file);
return false;
}
if (!GetFileSizeEx(file, &fileSize))
{
CloseHandle(file);
return false;
}
CloseHandle(file);
}
LONGLONG clusterSize = sectorsPerCluster * bytesPerSector;
LONGLONG clustersCount = fileSize.QuadPart / clusterSize + ((fileSize.QuadPart % clusterSize == 0) ? 0 : 1);
TCHAR rawDrive[] = L"\\\\.\\?:";
rawDrive[4] = filePath[0];
HANDLE driveHandle = CreateFile(rawDrive, /*GENERIC_WRITE*/GENERIC_READ/**/, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
if (driveHandle != INVALID_HANDLE_VALUE)
{
for (ExtentsVector::iterator it = extents.begin(); it != extents.end(); ++it)
{
LARGE_INTEGER distance = {};
distance.QuadPart = it->Lcn.QuadPart * clusterSize;
BOOL b = SetFilePointerEx(driveHandle, distance, NULL, FILE_BEGIN);
if (b)
{
std::string buffer;
buffer.resize(clusterSize * it->ClustersCount);
DWORD read = 0;
BOOL B = ReadFile(driveHandle, &buffer[0], clusterSize * it->ClustersCount, &read, NULL);
B = FALSE;//here I have breakpoint and for FAT type drives buffer contains invalid data
}
else
{
CloseHandle(driveHandle);
return false;
}
}
}
return false;
}
GetFileExtentPoints should collect clusters entries and cluster chain size for latter actions according to given file.
The place where the problem is seen is in PermanentDeleteFile I have marked that place with comment.
I have tried to read all my FAT32 drive and found that data I'm looking for is in drive but in other place so, as I understand FAT uses some kind of data offset. After that read this. As I think the offset is described by first 3 bytes in drive, but don't understand how to use it. In my case it is 0xEB 0x58 0x90. Want to ask, how to decode file system header into data offset.
BTW. I'm coding with C++ and using WinAPI.
EDIT: I have change my line into distance.QuadPart = it->Lcn.QuadPart * clusterSize + 0x01000000;, this works for FAT, however I don't want to have hardcoded constants, so can someone tell, if it is always this value, or it is calculated some way.
I am trying to get the names of all the battery devices on my computer using this code mostly acquired from a Microsoft tutorial but it isn't working.
#define INITGUID
#include <windows.h>
#include<batclass.h>
#include<setupapi.h>
#define GBS_HASBATTERY 0x1
#define GBS_ONBATTERY 0x2
#include<iostream>
using namespace std;
int main()
{
DWORD dwResult = GBS_ONBATTERY;
HDEVINFO hdev = SetupDiGetClassDevs(&GUID_DEVICE_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
for (int idev = 0; idev < 100; idev++)
{
SP_DEVICE_INTERFACE_DATA did = {0};
did.cbSize = sizeof(did);
if (SetupDiEnumDeviceInterfaces(hdev, 0, &GUID_DEVICE_BATTERY, idev, &did))
{
DWORD cbRequired = 0;
SetupDiGetDeviceInterfaceDetail(hdev, &did, 0, 0, &cbRequired, 0);
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR,cbRequired);
if (pdidd)
{
pdidd->cbSize = sizeof(*pdidd);
if (SetupDiGetDeviceInterfaceDetail(hdev,&did,pdidd,cbRequired,&cbRequired,0))
{
HANDLE hBattery = CreateFile(pdidd->DevicePath,GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (INVALID_HANDLE_VALUE != hBattery)
{
BATTERY_QUERY_INFORMATION bqi = {0};
DWORD dwWait = 0;
DWORD dwOut;
if (DeviceIoControl(hBattery,
IOCTL_BATTERY_QUERY_TAG,
&dwWait,
sizeof(dwWait),
&bqi.BatteryTag,
sizeof(bqi.BatteryTag),
&dwOut,
NULL)
&& bqi.BatteryTag)
{////////////////////////////////////////problem around here///////
string bi;
bqi.InformationLevel = BatteryDeviceName;
if (DeviceIoControl(hBattery,
IOCTL_BATTERY_QUERY_INFORMATION,
&bqi,
sizeof(bqi),
&bi,
sizeof(bi),
&dwOut,
NULL))
{
cout<<bi;
BATTERY_WAIT_STATUS bws = {0};
bws.BatteryTag = bqi.BatteryTag;
BATTERY_STATUS bs;
if (DeviceIoControl(hBattery,
IOCTL_BATTERY_QUERY_STATUS,
&bws,
sizeof(bws),
&bs,
sizeof(bs),
&dwOut,
NULL))
{
if (bs.PowerState & BATTERY_POWER_ON_LINE)
{
dwResult &= ~GBS_ONBATTERY;
}
}
}
}
CloseHandle(hBattery);
}
}
LocalFree(pdidd);
}
}
}
else if (ERROR_NO_MORE_ITEMS == GetLastError())
{
break;
}
}
SetupDiDestroyDeviceInfoList(hdev);
}
i am trying to print the names of all the batteries, but when i run the program it doesnt print anything at all, it does however work when i request a battery_information structure instead of the string BatteryDeviceName please help
The problem is that in your call to DeviceIoControl is wrong. You are passing in garbage, and when you put garbage in you get garbage out.
string bi;
if(DeviceIoControl(hBattery,
IOCTL_BATTERY_QUERY_INFORMATION,
bqi,
sizeof(bqi),
&bi, // Really?!?!?!
sizeof(bi), // WHAT?!?
&dwOut,
NULL))
You are passing the address a std::string object to DeviceIoControl, which knows nothing about std::string and expects the adress of a raw buffer that it can write to. You at least specify the right size for that buffer, but even that is wrong in a sense. Basically, when that function returns, that std::string is junk and accessing it could do just about anything - from crashing the program to playing Vivaldi on your speakers.
Try something like this:
WCHAR szBuf[_MAX_PATH] = { 0 }; // In a real program you'd dynamically
// allocate an appropriately sized buffer
// instead.
if(DeviceIoControl(hBattery,
IOCTL_BATTERY_QUERY_INFORMATION,
bqi,
sizeof(bqi),
szBuf,
sizeof(szBuf),
&dwOut,
NULL))