I want to access and edit multiple addresses in memory.
In case it's vague, the question is: If I used memory scanner and the results were a list of addresses, how would I be able to access and edit them all?
I've already been told to try putting all the addresses in an array, how do I do this?
Here's the code so far:
//
#include "stdafx.h"
#include "iostream"
#include "Windows.h"
#include <cstdint>
#include <stdint.h>
using namespace std;
int main()
{
int newValue = 0;
int* p;
p = (int*)0x4F6DCFE3DC; // now p points to address 0x220202
HWND hwnd = FindWindowA(NULL, "Call of Duty®: Modern Warfare® 3 Multiplayer");// Finds Window
if (hwnd == NULL) {// Tests for success
cout << "The window is not open" << endl;
Sleep(3000);
exit(-1);
}
else {
cout << "It's open boss!";
}
else {// If Successful Begins the following
DWORD procID;
GetWindowThreadProcessId(hwnd, &procID);
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procID);//Gets handle on process
if (procID == NULL) {
cout << "Cannot obtain process." << endl;
Sleep(3000);
exit(-1);
}
else {//Begins writing to memory
while (newValue == 0) {
/*This Writes*/WriteProcessMemory(handle, (LPVOID)0x04F6DCFE3DC, &newValue, sizeof(newValue), 0);
cout << p;
Sleep(3000);
}
}
}
}
It's fairly easy. Just use a std::vector<std::pair<int*,int>> to contain all these addresses you want to modify along with the value they should achieve:
std::vector<std::pair<int*,int>> changeMap = {
{ (int*)0x4F6DCFE3DC , 0 }
// more address value pairs ...
};
Then you can process them in a loop:
for(auto it = std::begin(changeMap); it != std::end(changeMap); ++it)
{
WriteProcessMemory(handle, (LPVOID)it->first, &(it->second),
sizeof(it->second), 0);
}
Whatever you want to achieve with that1.
I've already been told to try putting all the addresses in an array, how do I do this?
If you want to set all the address contents to 0 you may use a simpler construct:
int newValue = 0;
std::vector<int*> changeAddrList = {
(int*)0x4F6DCFE3DC ,
// more addresses to change ...
};
// ...
for(auto addr : changeAddrList)
{
WriteProcessMemory(handle, (LPVOID)addr , &newValue ,
sizeof(newValue), 0);
}
1Fiddling around in another processes memory is error prone and might lead to all kinds of unexpected behavior!
Your code may fail miserably at a newer version of that program, where you're trying to apply your cheat codez.
Related
I wrote some code (with mdsm manual help of course), which can add new record in arp table. But I have problem with understand couple lines of code. I marked these lines between start and stop marks. I don't know how excatly this parts of code works. Event if I remove marked paragraph and replace with
GetIpAddrTable(pIpAddrtable, &dwSize, 0)
GetIpAddrTable(pIpAddrtable, &dwSize, 0)
program runs "correctly" but something must be wrong, and I want to understand what and why? I think it has to do with memory allocation.
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <winsock2.h>
#include <ws2ipdef.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
using namespace std;
int main()
{
ULONG ulOutBufLen;
DWORD dwRetVal;
PIP_ADAPTER_INFO pAdapterInfo;
ulOutBufLen = sizeof(IP_ADAPTER_INFO);
pAdapterInfo = (IP_ADAPTER_INFO *) malloc( sizeof(IP_ADAPTER_INFO) );
ulOutBufLen = sizeof(IP_ADAPTER_INFO);
if (GetAdaptersInfo( pAdapterInfo, &ulOutBufLen) != ERROR_SUCCESS) {
free (pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *) malloc ( ulOutBufLen );
}
if ((dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen)) != ERROR_SUCCESS) {
printf("GetAdaptersInfo call failed with %d\n", dwRetVal);
}
PMIB_IPADDRTABLE pIpAddrtable;
DWORD dwSize = 0;
DWORD dwRetVal2 = 0;
IN_ADDR IPAddr;
free(pIpAddrtable);
pIpAddrtable = (MIB_IPADDRTABLE *) malloc(dwSize*2);
PIP_ADAPTER_INFO pAdapter = pAdapterInfo;
PMIB_IPNETROW pArpEntry;
DWORD ip = inet_addr("182.221.231.1");
//start
if (pIpAddrtable)
{
if (GetIpAddrTable(pIpAddrtable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER)
{
free(pIpAddrtable);
cout <<"Za mała ilosc pamięci";
}
if (pIpAddrtable == NULL) {
printf("Memory allocation failed for GetIpAddrTable\n");
exit(1);
}
if (dwRetVal2 = GetIpAddrTable(pIpAddrtable, &dwSize, 0) != NO_ERROR)
{
printf("Mamy error %s", dwRetVal2);
}
}
//stop
pArpEntry->dwIndex = pIpAddrtable->table[0].dwIndex;
pArpEntry->dwPhysAddrLen = 6;
pArpEntry->bPhysAddr[0] = '0x01';
pArpEntry->bPhysAddr[1] = '0xb2';
pArpEntry->bPhysAddr[2] = '0xd3';
pArpEntry->bPhysAddr[3] = '0xd4';
pArpEntry->bPhysAddr[4] = '0x05';
pArpEntry->bPhysAddr[5] = '0x16';
pArpEntry->dwType = MIB_IPNET_TYPE_STATIC;
pArpEntry->dwAddr = ip;
if (CreateIpNetEntry(pArpEntry) == ERROR_ACCESS_DENIED)
{
cout <<"Dostęp zabroniony ";
}
while (pAdapter)
{
printf(TEXT("Nazwa adaptera: %s \n"), pAdapter->AdapterName);
printf("Adres adaptera: %s \n", pAdapter->IpAddressList.IpAddress.String);
printf("Maska: %s \n ", pAdapter->IpAddressList.IpMask.String);
printf("Opis: %s \n ", pAdapter->Description);
printf("Serwer DHCP %s \n ", pAdapter->DhcpServer.IpAddress.String);
printf("Indeks: %5d \n ", pAdapter->Index);
cout <<endl;
pAdapter = pAdapter->Next;
}
return 0;
}
As my comments suggested, instead of taking verbatim the C implementation of the sample, you should adjust it so that it doesn't use raw memory allocation using malloc, and instead used std::vector.
In addition, there are several errors in your sample, the major one being that you are using an uninitialized pArpEntry pointer. I will address this later.
Here is a proper sample that works correctly and uses no dynamic memory allocation.
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <winsock2.h>
#include <ws2ipdef.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
using namespace std;
int main()
{
ULONG ulOutBufLen;
DWORD dwRetVal;
ulOutBufLen = 0;
// create a vector we will use for the PIP_ADAPTER_INFO data
std::vector<char> adapterInfo;
// call the INET API function with the vector contents serving
// as the PIP_ADAPTER_INFO
if (GetAdaptersInfo(reinterpret_cast<PIP_ADAPTER_INFO>(adapterInfo.data()), &ulOutBufLen) == ERROR_BUFFER_OVERFLOW)
// resize the buffer
adapterInfo.resize(ulOutBufLen);
Take note of the last two lines of code. The GetAdaptersInfo function is first called with a buffer size of 0. This will fail with an ERROR_BUFFER_OVERFLOW error (hopefully). Once it does do this, we resize the adapterInfo vector to the size of the ulOutBufLen, not by using malloc, but by merely calling the std::vector::resize function. No dynamic memory allocation, no pointers, etc.
Note that we had to reinterpret_cast the pointer in the API call, since that is the pointer type the call is asking for.
Going on:
if ((dwRetVal = GetAdaptersInfo(reinterpret_cast<PIP_ADAPTER_INFO>(adapterInfo.data()), &ulOutBufLen) != ERROR_SUCCESS))
{
std::cout << "GetAdaptersInfo call failed with " << dwRetVal;
return -1;
}
PIP_ADAPTER_INFO pAdapter = reinterpret_cast<PIP_ADAPTER_INFO>(adapterInfo.data());
We stop the program if after resizing, we get an error. If successful, we make our code a little simpler by assigning the address of the adapter information to pAdapter by reinterpret_cast on the returned adapter information.
Going on:
DWORD dwSize = 0;
DWORD dwRetVal2 = 0;
std::vector<char> pIpAddrtable;
if (GetIpAddrTable(reinterpret_cast<PMIB_IPADDRTABLE>(pIpAddrtable.data()), &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER)
{
pIpAddrtable.resize(dwSize);
if (dwRetVal2 = GetIpAddrTable(reinterpret_cast<PMIB_IPADDRTABLE>(pIpAddrtable.data()), &dwSize, 0) != NO_ERROR)
{
std::cout << "Many error " << dwRetVal2;
return -1;
}
}
This is basically the same pattern as the PIP_ADAPTER_INFO code previously. We create a vector, call the IP function to get the size, resize the vector with the returned size.
Going on:
MIB_IPNETROW arpEntry;
if (CreateIpNetEntry(&arpEntry) == ERROR_ACCESS_DENIED)
{
cout << "Access denied\n";
}
We do not need to allocate anything in the call to CreateIpNetEntry. All we need to do is pass the address of an existing MIB_IONETROW instance. This eliminates the uninitialized pointer error you had in your original code.
Going on:
PMIB_IPADDRTABLE theTable = reinterpret_cast<PMIB_IPADDRTABLE>(pIpAddrtable.data());
arpEntry.dwIndex = theTable->table[0].dwIndex;
arpEntry.dwPhysAddrLen = 6;
arpEntry.bPhysAddr[0] = 0x01;
arpEntry.bPhysAddr[1] = 0xb2;
arpEntry.bPhysAddr[2] = 0xd3;
arpEntry.bPhysAddr[3] = 0xd4;
arpEntry.bPhysAddr[4] = 0x05;
arpEntry.bPhysAddr[5] = 0x16;
arpEntry.dwType = MIB_IPNET_TYPE_STATIC;
arpEntry.dwAddr = ip;
We get a pointer to the PMIB_ADDRTABLE by reinterpret_cast-ing the data in the pIpAddrtable vector (we call the pointer theTable).
Going on:
while (pAdapter)
{
std::cout << pAdapter->AdapterName << "\n";
std::cout << pAdapter->IpAddressList.IpAddress.String << "\n";
std::cout << pAdapter->IpAddressList.IpMask.String << "\n";
std::cout << pAdapter->Description << "\n";
std::cout << pAdapter->DhcpServer.IpAddress.String << "\n";
std::cout << pAdapter->Index << "\n";
std::cout << endl;
pAdapter = pAdapter->Next;
}
return 0;
}
This outputs the adapter information.
Again, the magic into why this works is that we used std::vector<char> and resized the vector whenever the Windows IP function returns to us the correct buffer size. This eliminates the usage of malloc, and instead we simply use std::vector::resize.
The other thing we need to do is to use reinterpret_cast, since the API functions actually need the correct pointer type for the code to compile correctly. It's ugly, but that's how the C interface was coded, so the C++ equivalent needed to do the same thing.
There are no calls to malloc, no calls to free, no pointers to deal with (except the reinterpret_cast's), no memory leaks.
Here is the complete implementation using the on-line Visual Studio 2015 compiler:
Complete Example
I have the following INI file:
[Connection]
Protocol=HTPP
[Connection]
Protocol=HTTPS
Is there some way I can save two protocols in two different variables? I tried to write:
int a = GetPrivateProfileString(_T("Connection"), _T("Protocol"), _T(""), protocolChar, 32, path);
int ab = GetPrivateProfileString(_T("Connection"), _T("Protocol"), _T(""), protocolChar2, 32, path);
And the result is that ProtocolChar, protocolChar2, though both receive the "HTTP".
How can I keep all the protocol in variable differently?
No, GetPrivateProfileString does not support multiple sections with the same name and will always use the first one it encounters. There are a couple of straight forward approaches that can be used. The first is to simply append a number to the end of each section name.
[Connection0]
Protocol=HTPP
[Connection1]
Protocol=HTTPS
[Connection2]
Protocol=FTP
[Connection3]
Protocol=Telnet
With this approach you can iterate through the various Connection sections until you try loading one that does not exist.
#include <windows.h>
#include <iostream>
#include <sstream>
int main()
{
for (DWORD i = 0, size = 1; size != 0; ++i)
{
std::ostringstream name;
name << "Connection" << i;
std::string protocol(100, 0);
size = GetPrivateProfileStringA(
name.str().c_str(),
"Protocol",
NULL,
&protocol[0],
protocol.size(),
"./test1.ini");
if (size != 0)
{
protocol.resize(size);
std::cout
<< name.str().c_str()
<< ":protocol=" << protocol << "\n";
}
}
}
Another way is to have a primary section (i.e. Connections) that defines a list of other sections each with a unique name. The benefit to this is that the sections are much easier to manage one one is deleted and eliminates the need to reorder the remaining sections. In this case you can simply rewrite the contents of Connections.
[Connections]
Connection0=HTTPConnection
Connection1=HTTPSConnection
Connection2=FTPConnection
Connection3=TelnetConnection
[HTTPConnection]
Protocol=HTPP
[HTTPSConnection]
Protocol=HTTPS
[FTPConnection]
Protocol=FTP
[TelnetConnection]
Protocol=Telnet
With this approach you iterate over the entries of Connections and then load each individual sections.
#include <windows.h>
#include <iostream>
#include <sstream>
int main()
{
for (DWORD i = 0, size = 1; size != 0; ++i)
{
std::ostringstream name;
name << "Connection" << i;
std::string section(100, 0);
size = GetPrivateProfileStringA(
"Connections",
name.str().c_str(),
NULL,
§ion[0],
section.size(),
"./test1.ini");
if (size != 0)
{
section.resize(size);
std::string protocol(100, 0);
size = GetPrivateProfileStringA(
section.c_str(),
"Protocol",
NULL,
&protocol[0],
protocol.size(),
"./test1.ini");
if (size != 0)
{
protocol.resize(size);
std::cout
<< name.str().c_str()
<< ":"
<< section
<< ":protocol=" << protocol << "\n";
}
}
}
}
I'm trying to share a pointer of defined class between the parent and the forked child through shared memory.
so in parent's main i create the pointer
mydata *p;
Reader::GetInstance()->Read(p, i+1);
pid = fork();
if (pid == -1){
cout << "error on fork"<<endl;
}else if (pid == 0){
cout << "i will fork now" <<endl;
const char * path = "./mydatamanager";
execl (path, "-", (char *)0);
break;
}else {
writer(shmid, p);
}
writer contains this
void writer(int shmid , mydata * p)
{
void *shmaddr;
shmaddr = shmat(shmid, (void *)0, 0);
if((int)shmaddr == -1)
{
perror("Error in attach in writer");
exit(-1);
}
else
{
memcpy( shmaddr, p, sizeof(*p) );
}
}
and my data is
class mydara {
public:
int var1;
int var2;
int var3;
int var4;
int var5;
int var6;
char *var7;
mydata (int v2, int v3,char *v7, int v6){
var2 = v2;
var3 = v3;
var7 =new char[128];
strcpy(var7, v7);
var6 = v6;
var4 = 0;
var5 = 0;
}
};
and in the mydatamanager i get this pointer this way
void reader(int shmid, mydata *& p)
{
cout << "in reader" << endl;
void *shmaddr;
//sleep(3);
shmaddr = shmat(shmid, (void *)0, SHM_RDONLY|0644);
if((int)shmaddr == -1)
{
perror("Error in reader");
exit(-1);
}
else
{
cout << "in else "<< endl;
p = (mydata*) shmaddr;
cout <<"shared memory address is " <<shmaddr <<endl;
cout <<"var5 "<< p->var5<< endl;
cout <<"var2 "<< p->var2<< " match with "<<getpid() << "?" << endl;
cout <<"var3 "<< p->var3<< endl;
cout <<"var4 "<< p->var4<< endl;
cout <<"var7 "<< p->var7<< endl; // the
//shmdt(shmaddr);
}
}
and mydatamanager main :
int main()
{
cout << "in main" <<endl;
int shmid;
shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT|0644);
cout << "in advanced point" <<endl;
sleep(1);
mydata * p;
reader (shmid, p);
cout << p->var7 <<endl;
return 0;
}
the results are always 0.
how can i share this pointer through the parent and the child and where is the fault in my code?
Hi i had a IPC task some weeks ago and finally decided to use boost.
http://blog.wolfgang-vogl.com/?p=528
http://www.boost.org/doc/libs/1_36_0/doc/html/interprocess/synchronization_mechanisms.html#interprocess.synchronization_mechanisms.semaphores.semaphores_interprocess_semaphores
First of all, you are not synchronising anything. So how do you know which runs first, the reader or the writer. Memory is bound to be zero in a newly allocated block, so hence you get zero as a result.
Any shared memory must ensure that the reader doesn't read until the writer has completed (at least part of) the writing process, at the very least.
Beware of sharing classes - you must not use virtual functions, as that will almost certainly do something ohterthan what you expect (crash, most likely, but other options are available, none of them particularly pleasant)
The simplest way to handle your problem is to create a semaphore in the parent process before the fork, have the child process try to acquire it before the read (instead of doing a sleep) and the parent process release it after the write.
First, here's functions to create, destroy, and retreive the id of the semaphore:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int create_semaphore(const char *path, char id, int count){
key_t k = ftok(path, id);
semid = semget(k, 1, IPC_CREAT | IPC_EXCL | 0600);
semctl(semid, 0, SET_VAL, count);
return semid;
}
int destroy_semaphore(int semid){
semctl(semid, 0, IPC_RMID, 0);
}
int get_semaphore(const char *path, char id){
key_t k = ftok(path, id);
semid = semget(k, 1, 0600);
return semid;
}
Now we need a function to acquire it, and another one to release it:
void acquire_semaphore(int semid){
sembuf op;
op.sem_num = O;
op.sem_op = -1;
op.sem_flg = 0;
semop(semid,&op,1);
}
void release_semaphore(int semid){
sembuf op;
op.sem_num = 0;
op.sem_op = 1;
op.sem_flg = 0;
semop(semid,&op,1);
}
With these boilerplate functions in place, you should be able to synchronize your processes.
So, you will need to provide a path and a unique id (in the form of a simple character) to create and identify your semaphore. If you already used ftok to create your shared memory id (shmid), you should understand the idea. Otherwise, just make sure that both values are the same within both processes.
In your writer code, put the following line:
semid = create_semaphore(argv[0], 'S', 0);
right before the pid = fork(); line, to create and acquire the semaphore at the same time.
Add the line:
release_semaphore(semid);
after the writer(shmid, mydata); instruction to release the semaphore. You will also need to declare semid somewhere in scope. I used the writer program path to create the semaphore, which is good practice to ensure that no other process has already used our path. The only catch is that you need to make sure that reader will use that same path. You can hardcode that value somewhere in reader's code, or better yet, pass it from writer in the execl parameters (left as an exercise).
Assuming that path is known in reader, all is left to do is to acquire the the semaphore likeso:
semid = get_semaphore(path, 'S');
acquire_semaphore(semid);
destroy_semaphore(semid);
before the line reader(shmid, mydata); in the main function of reader.
As other posts have said, sharing class instances through a shared memory segment is usually a very bad idea. It is much safer
to pass simple struct data, and reconstruct your object on the reader side (look up serialization and marshalling on the net for more information).
Ask if you have problems with this (untested) code.
Merry Christmas!
I "copied" a simple code snippet from a site and adjusted it to a game I was trying to hack. An old game with no multiplayer, basically just to practice all this memory editing stuff. Every time my program successfully returns a window handle, but then fails to return the process handle. Here is my code:
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
long address = 0x47C0F04;
int newvalue = 200;
DWORD newvaluesize = sizeof(newvalue);
HWND hWnd = FindWindow(0, L"No One Lives Forever");
HANDLE pHandle;
DWORD pid;
if(hWnd != 0) {
cout << "Found windowx.\n";
GetWindowThreadProcessId(hWnd, &pid);
pHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
}
else {
cout << "Can't find window\n";
}
if(pHandle !=0) {
WriteProcessMemory(pHandle, (LPVOID)address, (LPVOID)newvalue, newvaluesize, 0);
cout << "Written to memory successfully\n";
}
else {
cout << "Couldn't get handle.\n";
}
CloseHandle(pHandle);
return 0;
}
The game is from 2000 if I recall correctly (really awesome game by the way) so I'm assuming it doesn't have any advanced anti-hack shield, since I can also pretty much edit the value of that address in cheat engine and it works with no hassle.
EDIT: I'll just explain what exactly happens. It always prints "Found window" but then it directly prints "Couldn't get handle". I don't get any compiler errors (I'm compiling in Microsoft Visual C++ 2010 Express)
You must run your program as administrator to get a handle with PROCESS_ALL_ACCESS permissions, this will fix your problem.
As GuidedHacking mentioned you need to run program as Admin ,Use this code to check whether your process is running as Admin rights.
BOOL IsElevatedProcess()
{
BOOL is_elevated = FALSE;
HANDLE token = NULL;
if (GT_IsPrivateMethod(gt_private_method, FUNC_NAME, LINE_NO))
{
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
{
TOKEN_ELEVATION elevation;
DWORD token_sz = sizeof(TOKEN_ELEVATION);
if (GetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation), &token_sz))
{
is_elevated = elevation.TokenIsElevated;
}
}
if (token)
{
CloseHandle(token);
}
}
return is_elevated;
}
I'm trying to get the path of a device by using the SetupDiGetDeviceInterfaceDetail() function, but it crashes everytime I call it. I've have been working on this for over 12 hours but still couldn't find out what is wrong with it... Can someone see if they can find what is actually causing this to happen? Heres the code:
//DeviceManager.h
#include <windows.h>
//#include <hidsdi.h>
#include <setupapi.h>
#include <iostream>
#include <cfgmgr32.h>
#include <tchar.h>
#include <devpkey.h>
#include <string>
extern "C"{
#include <hidsdi.h>
}
//#pragma comment (lib, "setupapi.lib")
class DeviceManager
{
public:
DeviceManager();
~DeviceManager();
void ListAllDevices();
void GetDeviceHandler();
//HANDLE PSMove;
//byte reportBuffer[57];
GUID guid;
//private:
HDEVINFO deviceInfoSet; //A list of all the devices
SP_DEVINFO_DATA deviceInfoData; //A device from deviceInfoSet
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailedData;
};
//DeviceManager.cpp
#include"DeviceManager.h"
DeviceManager::DeviceManager()
{
//deviceInterfaceData = new SP_DEVICE_INTERFACE_DATA;
//deviceInterfaceDetailedData = new SP_DEVICE_INTERFACE_DETAIL_DATA;
HidD_GetHidGuid(&guid);
deviceInfoSet = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); //Gets all Devices
GetDeviceHandler();
}
DeviceManager::~DeviceManager()
{
}
void DeviceManager::ListAllDevices()
{
DWORD deviceIndex = 0;
deviceInfoData.cbSize = sizeof(deviceInfoData);
while(SetupDiEnumDeviceInfo(deviceInfoSet, deviceIndex, &deviceInfoData))
{
deviceInfoData.cbSize = sizeof(deviceInfoData);
ULONG tcharSize;
CM_Get_Device_ID_Size(&tcharSize, deviceInfoData.DevInst, 0);
TCHAR* deviceIDBuffer = new TCHAR[tcharSize]; //the device ID will be stored in this array, so the tcharSize needs to be big enough to hold all the info.
//Or we can use MAX_DEVICE_ID_LEN, which is 200
CM_Get_Device_ID(deviceInfoData.DevInst, deviceIDBuffer, MAX_PATH, 0); //gets the devices ID - a long string that looks like a file path.
std::cout << deviceIDBuffer << std::endl;
deviceIndex++;
}
}
void DeviceManager::GetDeviceHandler()
{
DWORD deviceIndex = 0;
SP_DEVINFO_DATA deviceInfoData;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailedData;
deviceInfoData.cbSize = sizeof(deviceInfoData);
while(SetupDiEnumDeviceInfo(deviceInfoSet, deviceIndex, &deviceInfoData))
{
TCHAR deviceID[MAX_DEVICE_ID_LEN];
CM_Get_Device_ID(deviceInfoData.DevInst, deviceID, MAX_DEVICE_ID_LEN, 0);
//std::cout << deviceID << std::endl;
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if(SetupDiEnumDeviceInterfaces(deviceInfoSet, &deviceInfoData, &guid, 0, &deviceInterfaceData))
{
DWORD bufferLength = 0;
//deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
deviceInterfaceData.cbSize = 2048;
//std::cout << "it works not" << std::endl;
if(SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, NULL, 0, &bufferLength, NULL))
{
//deviceInterfaceData.cbSize = sizeof(bufferLength);
std::cout << "It works!" << std::endl;
}
else
{
std::cout << GetLastError() << std::endl;
}
}
else
{
//std::cout << GetLastError() << std::endl;
}
deviceIndex++;
}
}
//mainapp.cpp
#pragma once
int main()
{
DeviceManager deviceManager;
return 0;
}
The SetupDiGetDeviceInterfaceDetail function is called in the GetDeviceHandler() function of DeviceManager.
Please help. Thanks.
UPDATE: I have found out that it failed on the first SetupDiGetDeviceInterfaceDetail and is returning a 122 error (ERROR_INSUFFICIENT_BUFFER). But I am only trying to get the required buffer size, so how can this be??
UPDATE 2: right, I have changed the function a bit (see above code) by setting the deviceInterfaceData.cbsize to 2048 (a huge space for testing purposes) and now I'm getting a ERROR_INVALID_PARAMETER. This is getting more and more confusing... How can the parameters I've given is invalid? Just doesn't make sense. The only difference is I passed in References instead of Pointers because otherwise I will get a access violation error...
Having found this topic, I'd like to share my problem that using exactly the same source, I got ERROR_INVALID_USER_BUFFER from the call.
The reason was the line:
deviceInterfaceDetailedData->cbSize =
sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
which on my quadbyte aligned compiler set the value 8 instead of the required value 5.
You're not allocating memory properly for the SP_DEVICE_INTERFACE_DETAIL_DATA.
Remove SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailedData; and try putting this inside your if block:
// Get the required bufferLength
SetupDiGetDeviceInterfaceDetail(deviceInfoSet,
&deviceInterfaceData,
nullptr,
0,
&bufferLength,
nullptr);
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
std::cout << "Failed to get bufferLength. Error "
<< GetLastError() << '\n';
return;
}
// Create device interface detailed information struct pointer
// and allocate memory to it.
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailedData(nullptr);
deviceInterfaceDetailedData =
static_cast<PSP_INTERFACE_DEVICE_DETAIL_DATA>(malloc(bufferLength));
if(deviceInterfaceDetailedData == nullptr)
{
std::cout << "Failed to allocate memory. Error "
<< GetLastError() << '\n';
return;
}
deviceInterfaceDetailedData->cbSize =
sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
// Get detailed information
if(SetupDiGetDeviceInterfaceDetail(deviceInfoSet,
&deviceInterfaceData,
deviceInterfaceDetailedData,
bufferLength,
&bufferLength,
nullptr))
{
//deviceInterfaceData.cbSize = sizeof(bufferLength);
std::cout << "It works!" << std::endl;
}
else
{
std::cout << GetLastError() << std::endl;
}
free(deviceInterfaceDetailedData);
I haven't looked at the rest of the code, it may have errors too, but this answers your original question.
This is according to MSDN definition:
Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail with a NULLDeviceInterfaceDetailData pointer, a DeviceInterfaceDetailDataSize of zero, and a valid RequiredSize variable. In response to such a call, this function returns the required buffer size at RequiredSize and fails with GetLastError returning ERROR_INSUFFICIENT_BUFFER.
So, after ERROR_INSUFFICIENT_BUFFER error just use requiredSize value.