Loading Go binary into memory and Running from C++ - c++

I am doing some independent cybersecurity research trying to read load a Windows executable into memory and run it from memory using C++. Using some videos and other Stack posts I was able to get it working with a very simple application I built using C++ that just shows a single pop-up and it works perfectly. However, I want to do the same process using a Golang binary, but whenever I build a simple Golang program and try to us it with the code below, I get an application error that says: "The application was unable to start correctly (0xc0000005). Click OK to close the application."
Most of my programming experience is in Golang and Python so this C++ code is fairly new to me for this most recent cybersecurity project, so I would appreciate any assistance!
This is my C++ code (the Go code is just a single fmt.Println built to an exe)
int RunPortableExecutable(void* Image)
{
IMAGE_DOS_HEADER* DOSHeader; // For Nt DOS Header symbols
IMAGE_NT_HEADERS* NtHeader; // For Nt PE Header objects and symbols
IMAGE_SECTION_HEADER* SectionHeader;
PROCESS_INFORMATION PI;
STARTUPINFOA SI;
CONTEXT* CTX;
DWORD* ImageBase; //Base address of the image
void* pImageBase; //Pointer to the image base
int count;
char CurrentFilePath[1024];
DOSHeader = PIMAGE_DOS_HEADER(Image); // Initialize variable
NtHeader = PIMAGE_NT_HEADERS(DWORD(Image) + DOSHeader->e_lfanew); // Initialize
GetModuleFileNameA(0, CurrentFilePath, 1024); // Path to current executable
if (NtHeader->Signature == IMAGE_NT_SIGNATURE) // Check if image is a PE file
{
ZeroMemory(&PI, sizeof(PI)); // Null the memory
ZeroMemory(&SI, sizeof(SI)); // Null the memory
if (CreateProcessA(CurrentFilePath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &SI, &PI)) //Create new instance of process in suspended state (for new image)
{
CTX = PCONTEXT(VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE)); // Allocate context memory
CTX->ContextFlags = CONTEXT_FULL; // Context is allocated
if (GetThreadContext(PI.hThread, LPCONTEXT(CTX))) // If context is in thread
{
// Read instructions
ReadProcessMemory(PI.hProcess, LPCVOID(CTX->Ebx + 8), LPVOID(&ImageBase), 4, 0);
pImageBase = VirtualAllocEx(PI.hProcess, LPVOID(NtHeader->OptionalHeader.ImageBase), NtHeader->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE);
// WRite the image to the process
WriteProcessMemory(PI.hProcess, pImageBase, Image, NtHeader->OptionalHeader.SizeOfHeaders, NULL);
for (count = 0; count < NtHeader->FileHeader.NumberOfSections; count++)
{
SectionHeader = PIMAGE_SECTION_HEADER(DWORD(Image) + DOSHeader->e_lfanew + 248 + (count * 40));
WriteProcessMemory(PI.hProcess, LPVOID(DWORD(pImageBase) + SectionHeader->VirtualAddress), LPVOID(DWORD(Image) + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData, 0);
}
WriteProcessMemory(PI.hProcess, LPVOID(CTX->Ebx + 8), LPVOID(&NtHeader->OptionalHeader.ImageBase), 4, 0);
// Move address of entry point to the new eax register
CTX->Eax = DWORD(pImageBase) + NtHeader->OptionalHeader.AddressOfEntryPoint;
SetThreadContext(PI.hThread, LPCONTEXT(CTX)); // set the context
ResumeThread(PI.hThread); //Start the process
return 0;
}
}
}
}
// Get the size of a file
long getFileSize(FILE* file)
{
long lCurPos, lEndPos;
lCurPos = ftell(file);
fseek(file, 0, 2);
lEndPos = ftell(file);
fseek(file, lCurPos, 0);
return lEndPos;
}
int main()
{
const char* filePath = "printtest.exe";
BYTE* fileBuf; // Pointer to our buffered data
FILE* file = NULL; // File pointer
if ((file = fopen(filePath, "rb")) == NULL)
std::cout << "Could not open specified file" << std::endl;
else
std::cout << "File opened successfully" << std::endl;
long fileSize = getFileSize(file);
fileBuf = new BYTE[fileSize];
fread(fileBuf, fileSize, 1, file);
fclose(file); // Almost forgot this
// This just logs some characters to verify it read in properly
for (int i = 0; i < 300; i++)
std::cout << fileBuf[i];
//printf("%X ", fileBuf[i]);
RunPortableExecutable(fileBuf);
std::cin.get();
delete[]fileBuf;
}

Related

Access violation reading when trying to run pe file from memory

I took famous example of running pe executable from memory. But when I trying to run it am getting memory access violation on function WriteProcessMemory().
I am using the latest Visual Studio 2019 and I have Windows 10 x64 OS. In preferences in Visual Studio I select Debug and x86 build. The app that I am trying to run(simpleMessageBox.exe) is the same x86 Debug. Here is my full program:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <Windows.h> // WinAPI header
#include <TlHelp32.h> // WinAPI Process API
std::vector<uint8_t> getFileContents(const char* filePath)
{
std::vector<uint8_t> rawData;
std::ifstream stream(filePath, std::ios::in);
rawData = std::vector<uint8_t>(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
return rawData;
}
int RunPortableExecutable(void* Image)
{
IMAGE_DOS_HEADER* DOSHeader; // For NT DOS Header symbols
IMAGE_NT_HEADERS* NtHeader; // For Nt Header objects & symbols
IMAGE_SECTION_HEADER* SectionHeader;
PROCESS_INFORMATION PI;
STARTUPINFOA SI;
CONTEXT* CTX;
DWORD* ImageBase; // Base address of the image
void* pImageBase; // Point to the image base
int count;
char CurrentFilePath[1024];
DOSHeader = PIMAGE_DOS_HEADER(Image); // Initialize variable
NtHeader = (PIMAGE_NT_HEADERS)((char*)DOSHeader + DOSHeader->e_lfanew);
GetModuleFileNameA(0, CurrentFilePath, 1024); // Path to current executable
if (DOSHeader->e_magic == IMAGE_DOS_SIGNATURE) // Check if image is a PE file
{
ZeroMemory(&PI, sizeof(PI)); // Null the memory
ZeroMemory(&SI, sizeof(SI)); // Null the memory
if (CreateProcessA(CurrentFilePath, NULL, NULL, NULL, FALSE,
CREATE_SUSPENDED, NULL, NULL, &SI, &PI)) // Create a new instance of current
//process in suspended state, for the new image.
{
// Allocate memory for the context.
CTX = LPCONTEXT(VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE));
CTX->ContextFlags = CONTEXT_FULL; // Context is allocated
if (GetThreadContext(PI.hThread, LPCONTEXT(CTX))) //if context is in thread
{
// Read instructions
ReadProcessMemory(PI.hProcess, LPCVOID(CTX->Ebx + 8), LPVOID(&ImageBase), 4, 0);
pImageBase = VirtualAllocEx(PI.hProcess, LPVOID(NtHeader->OptionalHeader.ImageBase),
NtHeader->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE);
// Write the image to the process
WriteProcessMemory(PI.hProcess, pImageBase, Image, NtHeader->OptionalHeader.SizeOfHeaders, NULL);
for (count = 0; count < NtHeader->FileHeader.NumberOfSections; count++)
{
SectionHeader = PIMAGE_SECTION_HEADER(DWORD(Image) + DOSHeader->e_lfanew + 248 + (count * 40));
WriteProcessMemory(PI.hProcess, LPVOID(DWORD(pImageBase) + SectionHeader->VirtualAddress),
LPVOID(DWORD(Image) + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData, 0);
}
WriteProcessMemory(PI.hProcess, LPVOID(CTX->Ebx + 8), LPVOID(&NtHeader->OptionalHeader.ImageBase), 4, 0);
// Move address of entry point to the eax register
CTX->Eax = DWORD(pImageBase) + NtHeader->OptionalHeader.AddressOfEntryPoint;
SetThreadContext(PI.hThread, LPCONTEXT(CTX)); // Set the context
ResumeThread(PI.hThread); //´Start the process/call main()
return 0; // Operation was successful.
}
}
}
}
int main()
{
auto rawPEData = getFileContents("C:\\Users\\..\\simpleMessageBox.exe");
auto runError = RunPortableExecutable(&rawPEData[0]);
return runError;
}
Appreciate any help. Thanks in advance.

Convert wmf file to emf file with SetWinMetaFileBits api in c++

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);

Reading statusbar from another application

I'm trying to read the text from another application's statusbar that contains multiple panels. How would I go about that. I have tried to allocate memory in the other application and read that buffer based on this:
http://www.codeproject.com/Articles/5570/Stealing-Program-s-Memory
My current code is:
GetWindowThreadProcessId(grxstatusbar, &statusbarpid);
statusbarprocess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, FALSE, statusbarpid);
char* _buffer = nullptr;
char buffer[20];
_buffer = (char*)VirtualAllocEx(statusbarprocess, NULL, 20, MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(statusbarprocess, _buffer, &buffer, 20, NULL);
SendMessage(grxstatusbar, SB_GETTEXT, (WPARAM)0, (LPARAM)_buffer);
ReadProcessMemory(statusbarprocess, _buffer, buffer, 20, NULL);
VirtualFreeEx(statusbarprocess, _buffer, 0, MEM_RELEASE);
However, buffer is always just gibberish. What would be the best way to approach this problem.
EDIT *****
That won't work if target window is UNICODE. You can use SB_GETTEXTLENGTH to find the text length. Using the UNICODE version:
int char_count;
char_count = SendMessageW(hwndTarget, SB_GETTEXTLENGTH, 1, 0);
if (char_count <= 0)
return 0;
char_count = LOWORD(char_count) + 1;
int datalen = LOWORD(char_count);
datalen *= sizeof(wchar_t);
void* data = VirtualAllocEx(hprocess, NULL, datalen,
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
SendMessageW(hwndTarget, SB_GETTEXT, 1, (LPARAM)data);
wchar_t *buf = new wchar_t[char_count];
if (ReadProcessMemory(hprocess, data, buf, datalen, 0))
std::wcout << "buf: " << buf << "\n";
delete[]buf;
VirtualFreeEx(hprocess, data, 0, MEM_RELEASE);
CloseHandle(hprocess);

Microsoft SDK AMCap GetCurrentImage error

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.

Unable to open file using CreateFile function

Ok so I've been following this tutorial: http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=4422&lngWId=3
And so far I've gotten everything to work, up until I need the program to load in a .raw audio file.
Here's the relevant code:
LPSTR loadAudioBlock(const char* filename, DWORD* blockSize)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD size = 0;
DWORD readBytes = 0;
void* block = NULL;
//open the file
if((hFile = CreateFile((LPCWSTR)filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
return NULL;
// get it's size, allocate memory, and then read it into memory
size = GetFileSize(hFile, NULL);
block = HeapAlloc(GetProcessHeap(), 0, size);
ReadFile(hFile, block, size, &readBytes, NULL);
CloseHandle(hFile);
*blockSize = size;
return (LPSTR)block;
}
And then my main function which calls it:
int _tmain(int argc, _TCHAR* argv[])
{
HWAVEOUT hWaveOut; //device handle
WAVEFORMATEX wfx; //struct for format info
MMRESULT result; // for waveOut return values
LPSTR block;
DWORD blockSize;
// first let's set up the wfx format struct
wfx.nSamplesPerSec = 44100; // rate of the sample
wfx.wBitsPerSample = 16; //sample size
wfx.nChannels = 2; // 2 channels = stereo
wfx.cbSize = 0; // no extra info
wfx.wFormatTag = WAVE_FORMAT_PCM; //PCM format
wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;
wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
// then let's open the device
if(waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR)
{
fprintf(stderr, "unable to open Wave Mapper device.\n");
Sleep(1000);
ExitProcess(1);
}
// if no errors then close it
printf("The Wave Mapper device was opened successfully!\n");
//load and play file
if((block = loadAudioBlock("ding.raw", &blockSize)) == NULL)
{
fprintf(stderr, "Unable to load file\n");
Sleep(1000);
ExitProcess(1);
}
writeAudioBlock(hWaveOut, block, blockSize);
Sleep(1000);
waveOutClose(hWaveOut);
return 0;
}
Everytime I run the program I get the: "Unable to load file" output. I've got the "ding.raw" file in the same directory as my exe. I've also tried doing the full path as "C://path" and "C:/path" but then the compiler just gives me more errors about being unable to load a pdb file.
Any ideas? I'm using the Visual Studio 2012 Professional IDE and compiler.
Instead of using the standard char you should be using e.g. _TCHAR and LPCTSTR everywhere. This will make all string and string pointers you pass around be correct.
Look at the argv argument to _tmain and you will see that it uses _TCHAR instead of char. This is because Windows support both normal characters and Unicode characters depending on a couple of macros. See e.g. here for some more information.
So to solve what is likely your problem (since you don't get the actual error code, see my comment about GetLastError) you should change the function like this:
void *loadAudioBlock(LPCTSTR filename, DWORD* blockSize)
{
// ...
if((hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
return NULL;
// ...
}
And call it like this:
// ...
void *block;
if((block = loadAudioBlock(_T("C:\\path\\ding.raw"), &blockSize)) == NULL)
{
fprintf(stderr, "unable to open Wave Mapper device, error code %ld.\n", GetLastError());
Sleep(1000);
ExitProcess(1);
}
// ...
As you can see I also changed the return type, as the file is binary and won't have any readable text.
LPSTR loadAudioBlock(const char* filename, DWORD* blockSize)
{
if((hFile = CreateFile(CA2T(filename), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
return NULL;
}
See ATL conversion macros: http://msdn.microsoft.com/en-us/library/87zae4a3%28v=vs.80%29.aspx Just casting const char* LPCWSTR doesn't work.