i would like to find a way detecting the type of the media in my optical drive (e.g. DVD+R, DVD-R, DVD-RW, CD+R, etc.) using a simple function in C++ on windows.
The function should not require Admin privilege.
EDIT
I implemented the following code:
#include <windows.h>
#include <winioctl.h>
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <imapi2.h>
#include <imapi2fs.h>
#include <imapi2error.h>
#include <imapi2fserror.h>
int main(int argc, char *argv[])
{
IDiscFormat2Data* discFormatData = NULL;
HRESULT hr;
CoInitialize ( NULL );
hr = CoCreateInstance( __uuidof(MsftDiscFormat2Data),
NULL,
CLSCTX_ALL,
__uuidof(IDiscFormat2Data),
(void**)&discFormatData);
if ( SUCCEEDED(hr) )
{
IMAPI_MEDIA_PHYSICAL_TYPE mediaType = IMAPI_MEDIA_TYPE_UNKNOWN;
hr = discFormatData->get_CurrentPhysicalMediaType(&mediaType);
if ( SUCCEEDED(hr) )
{
std::cout << "MediaPhysicalType: " << mediaType << std::endl;
}
else
{
std::stringstream str;
str << "get_CurrentPhysicalMediaType() failed with the error: 0x";
str << std::hex << hr << ".";
std::cout << str.str() << std::endl;
}
// Release the interface.
// Tell the COM object that we're done with it.
discFormatData->Release();
}
else
{
std::stringstream str;
str << "CoCreateInstance() failed with the error: 0x" << std::hex << hr;
std::cout << str.str() << std::endl;
}
cin.get();
return 0;
}
at the moment my problem is that i get the following error: E_IMAPI_RECORDER_REQUIRED which means
"The request requires a current disc recorder to be selected."
Assuming i have at least two optical drivers, how can i differ between them?
Any ideas?
On Windows 2000 and later, you can use IOCTL_CDROM_GET_CONFIGURATION with the SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT flag to query an optical device for its current profile, which will tell you which type of disc (CD, DVD+-R/W, HDDVD, BluRay, etc) has been inserted, if any. On earlier versions, you will have to manually send SCSI MMC commands directly to the device to query the same info.
Related
I'm super new to C++ and I'm trying to download an executable file from a URL and write it to disk.
I have the below code which successfully downloads the file and stores it in memory. The issue I am having is then writing that to disk.
I am pretty sure this is down to where I am creating the buffer where the downloaded data will be written to before being going to the new file.
char buffer[4096];
The 4096 is an arbitrary number from the template code I got elsewhere. What I can't figure out or don't know is how to dynamically allocate that buffer size based on the size of the data at &pStream.
I have tried using functions such as sizeof() but these just get me the memory address size rather than the value itself.
Alternatively, is there better way to try and accomplish this download and write?
#include <Windows.h>
#include <Urlmon.h> // URLOpenBlockingStreamW()
#include <atlbase.h> // CComPtr
#include <iostream>
#include "download.h"
#include <fstream>
#include <assert.h>
#include <chrono>
#include <thread>
#pragma comment( lib, "Urlmon.lib" )
struct ComInit
{
HRESULT hr;
ComInit() : hr(::CoInitialize(nullptr)) {}
~ComInit() { if (SUCCEEDED(hr)) ::CoUninitialize(); }
};
int download_file()
{
ComInit init;
HRESULT hr;
// use CComPtr so you don't have to manually call Release()
CComPtr<IStream> pStream;
bool success = false;
while (success == false)
{
try {
// Open the HTTP request.
hr = URLOpenBlockingStreamW(nullptr, L"https://www.foo.bar/download/somefile.exe", &pStream, 0, nullptr);
if (FAILED(hr))
{
std::cout << "ERROR: Could not connect. HRESULT: 0x" << std::hex << hr << std::dec << "\n";
}
else
{
success = true;
}
}
catch (const std::exception& ex) {
std::cout << ex.what();
}
}
// Download the response and write it to stdout.
char buffer[4096]; // Issue is here I think
do
{
DWORD bytesRead = 0;
hr = pStream->Read(buffer, sizeof(buffer), &bytesRead);
if (bytesRead > 0)
{
//std::cout.write(buffer, bytesRead);
std::ofstream file;
file.open("some_path_dot_exe", std::ios_base::binary);
assert(file.is_open());
for (int i = 0; i < sizeof(buffer) / sizeof(buffer[0]); ++i)
file.write((char*)(buffer + i * sizeof(buffer[0])), sizeof(buffer[0]));
file.close();
}
} while (SUCCEEDED(hr) && hr != S_FALSE);
if (FAILED(hr))
{
std::cout << "ERROR: Download failed. HRESULT: 0x" << std::hex << hr << std::dec << "\n";
return 2;
}
std::cout << "\n";
return 0;
}
The IStream that URLOpenBlockingStreamW() gives you isn't guaranteed to be able to give you the full file size up front, so if you want to hold the entire file in memory, you will have to use std::vector or other dynamically-growing buffer.
Though, you don't actually need to hold the entire file in memory just to save it to disk, you can use a fixed array and write it to disk as it is being downloaded, as you already are doing.
The real problem is, you are opening and closing the file on every Read(), wiping out all previous data written. And you are ignoring the bytesRead value that Read() gives you.
You need to open the file one time, leave it open until you are done with the download, and don't write more than is actually in the buffer on each write().
Try this:
#include <Windows.h>
#include <Urlmon.h> // URLOpenBlockingStreamW()
#include <atlbase.h> // CComPtr
#include <iostream>
#include "download.h"
#include <fstream>
#include <assert.h>
#include <chrono>
#include <thread>
#pragma comment( lib, "Urlmon.lib" )
struct ComInit
{
HRESULT hr;
ComInit() : hr(::CoInitialize(nullptr)) {}
~ComInit() { if (SUCCEEDED(hr)) ::CoUninitialize(); }
};
int download_file()
{
ComInit init;
HRESULT hr;
// use CComPtr so you don't have to manually call Release()
CComPtr<IStream> pStream;
do
{
try {
// Open the HTTP request.
hr = URLOpenBlockingStreamW(nullptr, L"https://www.foo.bar/download/somefile.exe", &pStream, 0, nullptr);
if (SUCCEEDED(hr)) break;
std::cout << "ERROR: Could not connect. HRESULT: 0x" << std::hex << hr << std::dec << "\n";
}
catch (const std::exception& ex) {
std::cout << ex.what();
}
}
while (true);
std::ofstream file("some_path_dot_exe", std::ios_base::binary);
if (!file.is_open()) {
std::cout << "ERROR: Download failed. Unable to create output file.\n";
return 1;
}
// Download the response and write it to file.
char buffer[4096];
DWORD bytesRead;
do
{
hr = pStream->Read(buffer, sizeof(buffer), &bytesRead);
if (bytesRead > 0)
file.write(buffer, bytesRead);
} while (SUCCEEDED(hr) && hr != S_FALSE);
file.close();
if (FAILED(hr))
{
std::cout << "ERROR: Download failed. HRESULT: 0x" << std::hex << hr << std::dec << "\n";
return 2;
}
std::cout << "\n";
return 0;
}
I have been trying to write a file in path returned by SHGetFolderPath . But as File Is created, it has been given Write Protected. Following is my Code:
#include <Windows.h>
#include <Shlobj.h>
#include <iostream>
#include <Shlwapi.h>
int main()
{
HANDLE hfile;
TCHAR szPath[MAX_PATH];
char dataBuffer[] = "Some data to write here";
DWORD dwBytesWritten = 0;
if(SUCCEEDED(SHGetFolderPath(NULL,CSIDL_COMMON_APPDATA,NULL,0, szPath)))
{
std::cout << szPath << std::endl;
PathAppend(szPath,TEXT("lpa"));
std::cout << szPath << std::endl;
PathAppend(szPath,TEXT("config"));
std::cout << szPath << std::endl;
CreateDirectory(szPath, NULL);
PathAppend(szPath, TEXT("lpa.config"));
std::cout << szPath << std::endl;
hfile = CreateFile(szPath,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
/*WriteFile(hfile,dataBuffer,(DWORD)strlen(dataBuffer),&dwBytesWritten,NULL);
std::cout << szPath <<std::endl;*/
}
}
The code creates a file in C:\ProgramData\lpa\config\lpa.config but editing the file pops up dialog saying WriteProtection. What am I doing wrong here?
Yes, When you run VS instance with Admin privileges, special permissions are assigned to the created file. Either run as the program as Non-Admin or use SECURITY_DESCRIPTOR so that other user can access the file.
Creating a Security Descriptor for a New Object in C++
the example in the link shows how a registry key is created, you can put CreateFile() instead.
I solved the issue by using CSIDL_LOCAL_APPDATA instead of CSIDL_COMMON_APPDATA . I have the modified code given as below:
#include <Windows.h>
#include <Shlobj.h>
#include <iostream>
#include <Shlwapi.h>
int main()
{
HANDLE hfile;
TCHAR szPath[MAX_PATH];
char dataBuffer[] = "Some data to write here";
DWORD dwBytesWritten = 0;
if(SUCCEEDED(SHGetFolderPath(NULL,CSIDL_LOCAL_APPDATA,NULL,0, szPath)))
{
std::cout << szPath << std::endl;
PathAppend(szPath,TEXT("lpa"));
if(!CreateDirectory(szPath, NULL))
{
std::cout << "Create directory failed" <<std::endl;
}
std::cout << szPath << std::endl;
PathAppend(szPath,TEXT("config"));
if(!CreateDirectory(szPath, NULL))
{
std::cout << "Create directory failed" <<std::endl;
}
std::cout << szPath << std::endl;
PathAppend(szPath, TEXT("lpa.config"));
std::cout << szPath << std::endl;
hfile = CreateFile(szPath,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
WriteFile(hfile,dataBuffer,(DWORD)strlen(dataBuffer),&dwBytesWritten,NULL);
std::cout << szPath <<std::endl;
}
}
I need to open a certain named pipe so I can fuzz test it, however my test code does not have access to the same data used to generate the name of the named pipe. However I can recognize the name of the pipe and then use that name to open up the pipe for fuzzing.
I used this forum post to start enumerating names of the handles on the system:
http://forum.sysinternals.com/howto-enumerate-handles_topic18892.html
However it seems that won't work with named pipes for some reason.
TL;DR: What API(s) do I need to use to list the names of all named pipes in the current process on Windows?
This will enumerate all named pipes in the system, or at the very least put you a step in the right direction.
This works in MinGW when built with -fpermissive. It should work with similar settings in MSVC.
#ifndef _WIN32_WINNT
// Windows XP
#define _WIN32_WINNT 0x0501
#endif
#include <Windows.h>
#include <Psapi.h>
// mycreatepipeex.c is at http://www.davehart.net/remote/PipeEx.c
// I created a simple header based on that.
#include "mycreatepipeex.h"
#include <iostream>
#include <cstdio>
#include <errno.h>
void EnumeratePipes()
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
#define TARGET_PREFIX "//./pipe/"
const char *target = TARGET_PREFIX "*";
memset(&FindFileData, 0, sizeof(FindFileData));
hFind = FindFirstFileA(target, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
std::cerr << "FindFirstFileA() failed: " << GetLastError() << std::endl;
return;
}
else
{
do
{
std::cout << "Pipe: " << TARGET_PREFIX << FindFileData.cFileName << std::endl;
}
while (FindNextFile(hFind, &FindFileData));
FindClose(hFind);
}
#undef TARGET_PREFIX
return;
}
int main(int argc, char**argv)
{
HANDLE read = INVALID_HANDLE_VALUE;
HANDLE write = INVALID_HANDLE_VALUE;
unsigned char pipe_name[MAX_PATH+1];
BOOL success = MyCreatePipeEx(&read, &write, NULL, 0, 0, 0, pipe_name);
EnumeratePipes();
if ( success == FALSE )
{
std::cerr << "MyCreatePipeEx() failed: " << GetLastError() << std::endl;
return 1;
}
FILE *f = fopen((const char*)pipe_name, "rwb");
if ( f == NULL )
{
std::cerr << "fopen(\"" << pipe_name << "\") failed: " << (int)errno << std::endl;
}
CloseHandle(read);
CloseHandle(write);
return 0;
}
Here's a very simple program using the function:
#include <windows.h>
#include <tchar.h>
#include <atlstr.h>
#include <mmdeviceapi.h>
#include <devicetopology.h>
#include <functiondiscoverykeys.h>
#include <iostream>
using namespace std;
int main()
{
HRESULT hr;
CComPtr<IMMDeviceEnumerator> pMMDeviceEnumerator;
pMMDeviceEnumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, 0);
//cout << hr;
return 0;
}
When I try to run this, I get the following error:
Debug Assertion Failed!
Program: ...
File: c:\program files\microsoft visual studio 8\vc\atlmfc\include\atlcomcli.h
Line: 154
Expression: p!=0
What's wrong with this? I'm just now trying to learn how to use this function. Thanks!
EDIT:
I've changed the program to this:
//#include <windows.h>
//#include <tchar.h>
#include <atlstr.h>
#include <mmdeviceapi.h>
//#include <devicetopology.h>
//#include <functiondiscoverykeys.h>
#include <iostream>
using namespace std;
// helper class to CoInitialize/CoUninitialize
class CCoInitialize {
private:
HRESULT m_hr;
public:
CCoInitialize(PVOID pReserved, HRESULT &hr)
: m_hr(E_UNEXPECTED) { hr = m_hr = CoInitialize(pReserved); }
~CCoInitialize() { if (SUCCEEDED(m_hr)) { CoUninitialize(); } }
};
int main()
{
CComPtr<IMMDeviceEnumerator> pMMDeviceEnumerator;
HRESULT hr = pMMDeviceEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator));
if (FAILED(hr)) {
cout << "failed" << endl;
return __LINE__;
}
CCoInitialize ci(NULL, hr);
pMMDeviceEnumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, 0);
//cout << hr;
return 0;
}
When I run it, I get the output of "failed". What's happening?
EDIT:
Alright, now I've changed the code enough to get it running all the way through without any failures. i.e.,
HRESULT hr = S_OK;
cout << hr;
// initialize COM
CCoInitialize ci(NULL, hr);
if (FAILED(hr)) {
cout << "failed1" << endl;
return __LINE__;
}
cout << hr;
// get enumerator
CComPtr<IMMDeviceEnumerator> pMMDeviceEnumerator;
hr = pMMDeviceEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator));
if (FAILED(hr)) {
cout << "failed2" << endl;
return __LINE__;
}
cout << hr;
// get default render/capture endpoints
CComPtr<IMMDevice> pRenderEndpoint;
hr = pMMDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pRenderEndpoint);
if (FAILED(hr)) {
cout << "failed3" << endl;
return __LINE__;
}
cout << hr;
return 0;
Some of the trouble I was having earlier with this example (see comments on the answers) was fixed just by removing some of the code. But as I run this new body of the main() function, I get the output "0000", meaning that cout << hr always evaluates to "0". Is this a good thing? What info can I get about the default device now? hr. and hr-> don't really bring up any menus, so I'm kind of in the dark. Thanks!
pMMDeviceEnumerator variable holds a pointer, which is NULL. When you try to call an interface method on this pointer, -> operator checks this nullness and issues an assertion failure.
Windows SDK samples show how to use this function and API, check them under: \Samples\multimedia\audio, e.g. osd sample.
This sample is a Win32-based application that demonstrates the use of the Vista APIs for monitoring the default audio output device and
its current volume setting. The sample is written in C++.
OSD does not run on earlier versions of Windows, including Windows XP, Windows 2000, Windows Me, and Windows 98.
UPD: Things in main one needs to reach the GetDefaultAudioEndpoint API call - Sample: find out if your default audio playback and audio capture devices are on the same hardware.
I am having a really hard time with some API calls to the Wininet dll. I am trying to read cookies client side set by IE 9. Here's the code.
#include "stdafx.h"
#include <Windows.h>
#include <WinInet.h>
#include <iostream>
int _tmain(int argc, _TCHAR* argv[])
{
LPTSTR lpData = NULL;
DWORD dwSz = 500;
std::cout << "Hello Chris" << std::endl;
lpData = new TCHAR[dwSz];
std::wcout << "Arg 0: " << argv[1] << std::endl;
bool val = InternetGetCookieEx(argv[1], argv[2], lpData, &dwSz, INTERNET_COOKIE_THIRD_PARTY | INTERNET_FLAG_RESTRICTED_ZONE, NULL);
if (!val)
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
std::cout << "Insufficent Buffer size" << std::endl;
lpData = new TCHAR[dwSz];
val = InternetGetCookieEx(argv[1], argv[2], lpData, &dwSz, INTERNET_COOKIE_THIRD_PARTY | INTERNET_FLAG_RESTRICTED_ZONE, NULL);
if (val)
{
std::cout << "Cookie Data: " << lpData << std::endl;
}
else
{
std::cout << "ERROR Code: " << GetLastError() << std::endl;
}
}
else
{
int err = GetLastError();
std::cout << "ERROR Code: " << err << std::endl;
}
}
else
{
std::cout << "Cookie Data: " << lpData << std::endl;
}
//}
return 0;
}
The problem that I am having is that when I call InternetGetCookeEx I always return false and get an error code of 259, which means no more data available. When you consult the API essentially what that means is that it couldn't find my cookie.
Because I am using IE 9 the names for files that the cookie is being stored in are obviously mangled , which is why I am trying to read my cookie data that way.
I have removed the company name to protect the company. Essentially what I am trying to do is. Find the lUsrCtxPersist cookie value. Therefore I am calling the code as such CookieReader.ext http://[CompanyDomain].com lUsrCtxPersist.
However I always get a false and an error code of 259. Any light you might be able to shed on this would be greatly appreciated.
http://msdn.microsoft.com/en-us/library/ms537312%28v=vs.85%29.aspx
Try to use IEGetProtectedModeCookie
Assuming the cookie name is correct, then try removing the INTERNET_COOKIE_THIRD_PARTY and/or INTERNET_FLAG_RESTRICTED_ZONE flags and see what happens. Or try calling InternetGetCookie() instead, which has no such flags available.
On a separate note, when InternetGetCookieEx() returns ERROR_INSUFFICIENT_BUFFER, you are leaking memory. You need to delete[] your existing buffer before then calling new[] to allocate a new buffer.