This is probably more of an intermediate problem....

My issue isn't so much with the function as it is to do with the data after the function returns...

1
2
3
4
5
6
7
8
9
10
11
  SetupDiGetDeviceInterfacePropertyW(
       _In_         HDEVINFO         DeviceInfoSet,
       _In_         PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
       _In_   CONST DEVPROPKEY * PropertyKey,
       _Out_        DEVPROPTYPE * PropertyType,
       _Out_writes_bytes_to_opt_(PropertyBufferSize, *RequiredSize) PBYTE PropertyBuffer,
       _In_         DWORD            PropertyBufferSize,
       _Out_opt_    PDWORD           RequiredSize,
       _In_         DWORD            Flags
   );


I have all verifiable good working parameters but it uses the DEVPROPTYPE which is supposed to clue you in as to what to do with the data after its populated the buffer. (or possiby before when making the buffer)

the property types are defined like so

1
2
3
4
5
6
7
8
9
10
11
12
13
14

#define DEVPROP_TYPE_EMPTY                      0x00000000  // nothing, no property data
#define DEVPROP_TYPE_NULL                       0x00000001  // null property data
#define DEVPROP_TYPE_SBYTE                      0x00000002  // 8-bit signed int (SBYTE)
#define DEVPROP_TYPE_BYTE                       0x00000003  // 8-bit unsigned int (BYTE)
#define DEVPROP_TYPE_INT16                      0x00000004  // 16-bit signed int (SHORT)
#define DEVPROP_TYPE_UINT16                     0x00000005  // 16-bit unsigned int (USHORT)
#define DEVPROP_TYPE_INT32                      0x00000006  // 32-bit signed int (LONG)
#define DEVPROP_TYPE_UINT32                     0x00000007  // 32-bit unsigned int (ULONG)
#define DEVPROP_TYPE_INT64                      0x00000008  // 64-bit signed int (LONG64)
#define DEVPROP_TYPE_UINT64                     0x00000009  // 64-bit unsigned int (ULONG64)
#define DEVPROP_TYPE_FLOAT                      0x0000000A  // 32-bit floating-point (FLOAT)
#define DEVPROP_TYPE_DOUBLE                     0x0000000B  // 64-bit floating-point (DOUBLE)
#define DEVPROP_TYPE_DECIMAL                    0x0000000C  // 128-bit data (DECIMAL) 


my question is do i need to drag the whole list into my code and make some type of enum or can i use these keywords in like a template function that takes the keyword as the type, have it do the converstion and have the return be a template as well... just kinda stuck. I believe that i've attempted to cast to the DEVPROPTYPE and that was a bust. I tried a few things and then just kinda gave up and moved on but now i'm begining to think that this is the KEY to what i'm trying to accomplish...but i could be wrong.

Also just to set the record straight, I'm well aware that this function needs to be called twice, first gives you the size of the buffer needed and the DEVPROPTYPE value. that way you can prepare the buffer properly, then you have to call it again to actually fill the buffer.

I guess if worse comes to worst i can put them in a vector and loop through and do comparisons... but Im assuming there has to be an easier way to go about this. I'd also like to say that the list of Proptypes is much longer i just posted like a third of the list
Last edited on
I guess if worse comes to worst i can put them in a vector and loop through and do comparisons... but I'm assuming there has to be an easier way to go about this. I'd also like to say that the list of Proptypes is much longer i just posted like a third of the list

This API returns a discriminated union: a chunk of memory with instructions how to interpret it. You must look at those instructions and tell the computer what to do fore each case. For example, with a switch statement.
1
2
3
4
5
switch (type & ~(DEVPROP_TYPEMOD_ARRAY | DEVPROP_TYPEMOD_LIST)))
{
  case DEVPROP_TYPE_INT16: /* whatever */ ; break; 
  case DEVPROP_TYPE_INT32: /* whatever */ ; break;
}


There are good chances that you do not need to check every case separately -- or, if you do, that some cases will be very similar. Exploit this similarity by writing function templates or macros (if you must) to keep your code short & to avoid repetition.

Consider this program -- it implements the same idea as the WinAPI function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <type_traits>
#include <cstring>
#include <cstdlib>
#include <iostream>

constexpr int type_int    = 0;
constexpr int type_double = 1; 

// Randomly write either an int or double to buf;
// returns type_int or type_double depending on what was written.
int write_something(unsigned char* buf)
{
  int    x = rand() % 32;
  double y = rand() % 32 + 0.5;
  
  int type = rand() % 2;
  
  if (type == type_int) std::memcpy(buf, &x, sizeof x);
  else std::memcpy(buf, &y, sizeof y);
  
  return type;
}

template <typename T> T to_type(void const* buffer) 
  requires std::is_trivially_copyable_v<T> && std::default_initializable<T>
{
  T result; 
  return *reinterpret_cast<T*>(std::memcpy(&result, buffer, sizeof result)); 
}

int main()
{  
  std::aligned_union_t<8, int, double> buffer;

  for (int i = 0; i < 10; ++i) 
    switch (write_something(reinterpret_cast<unsigned char*>(&buffer)))
    {
      case type_int:    std::cout << "int: "    << to_type<int   >(&buffer) << '\n'; break;
      case type_double: std::cout << "double: " << to_type<double>(&buffer) << '\n'; break;
    }
}

In this case, as the number of cases increases, a macro becomes increasingly attractive.
1
2
3
4
5
6
7
8
9
10
  switch (write_something(reinterpret_cast<unsigned char*>(&buffer)))
  {
#define TYPE_CASE(t) \
  case type_##t: std::cout << #t ": " << to_type<t>(&buffer) << '\n'; break
  /**/
  TYPE_CASE(int);
  TYPE_CASE(double);
  // TYPE_CASE(...);
#undef TYPE_CASE
  }


Last edited on
I had just settled on picking out the specific type of data I was looking for using a conditional statement. For the sake of completeness I usually like to extract everything and sort through it at my own discretion. This is just a odd situation where that is possible it just requires alot more work than im willing to put forth. Im attempting to gain access to a system driver and I believe it just has an empty dacl so basically no access.

I keep grinding away doing my research etc. Its amazing to me that nowhere in the documentation about the above mentioned function and associated functions that retrieve the data needed to satisfy the parameters is there mention of the function i'm about to post....

WINDOWS!!!! does it again. their documentation really sux.


The point of this is to take a interface guid associated property key and DEVPROPKEY type and return the relevent data in a struct that makes it readable....
1
2
3
4
5
6
7
8
NTSTATUS WdfDeviceAllocAndQueryInterfaceProperty(
  WDFDEVICE                           Device,
  PWDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData,
  POOL_TYPE                           PoolType,
  PWDF_OBJECT_ATTRIBUTES              PropertyMemoryAttributes,
  WDFMEMORY                           *PropertyMemory,
  PDEVPROPTYPE                        Type
);


unreal...
Last edited on
Topic archived. No new replies allowed.