camhook: move camera hook facilities to their own module
makes the number of cameras configurable (up to 2), as SDVX only needs 1
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
libs += camhook
|
||||
|
||||
libs_camhook := \
|
||||
hook \
|
||||
hooklib \
|
||||
cconfig \
|
||||
util \
|
||||
|
||||
src_camhook := \
|
||||
cam.c \
|
||||
config-cam.c \
|
||||
@@ -0,0 +1,815 @@
|
||||
#define LOG_MODULE "cam-hook"
|
||||
|
||||
// clang-format off
|
||||
// Don't format because the order is important here
|
||||
#include <windows.h>
|
||||
#include <initguid.h>
|
||||
// clang-format on
|
||||
|
||||
#include <mfapi.h>
|
||||
#include <mfidl.h>
|
||||
#include <mfobjects.h>
|
||||
|
||||
#include <cfgmgr32.h>
|
||||
#include <setupapi.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "hook/com-proxy.h"
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "camhook/cam.h"
|
||||
|
||||
#include "util/defs.h"
|
||||
#include "util/log.h"
|
||||
#include "util/str.h"
|
||||
#include "util/time.h"
|
||||
|
||||
#define CAMERA_DATA_STRING_SIZE 0x100
|
||||
|
||||
EXTERN_GUID(
|
||||
MY_MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
|
||||
0xc60ac5fe,
|
||||
0x252a,
|
||||
0x478f,
|
||||
0xa0,
|
||||
0xef,
|
||||
0xbc,
|
||||
0x8f,
|
||||
0xa5,
|
||||
0xf7,
|
||||
0xca,
|
||||
0xd3);
|
||||
EXTERN_GUID(
|
||||
MY_MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID,
|
||||
0x8ac3587a,
|
||||
0x4ae7,
|
||||
0x42d8,
|
||||
0x99,
|
||||
0xe0,
|
||||
0x0a,
|
||||
0x60,
|
||||
0x13,
|
||||
0xee,
|
||||
0xf9,
|
||||
0x0f);
|
||||
EXTERN_GUID(
|
||||
MY_MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
|
||||
0x58f0aad8,
|
||||
0x22bf,
|
||||
0x4f8a,
|
||||
0xbb,
|
||||
0x3d,
|
||||
0xd2,
|
||||
0xc4,
|
||||
0x97,
|
||||
0x8c,
|
||||
0x6e,
|
||||
0x2f);
|
||||
// define ourselves cause mingw has these wrong
|
||||
|
||||
struct CameraData {
|
||||
bool setup;
|
||||
char name[CAMERA_DATA_STRING_SIZE];
|
||||
char deviceInstancePath[CAMERA_DATA_STRING_SIZE];
|
||||
wchar_t deviceSymbolicLink[CAMERA_DATA_STRING_SIZE];
|
||||
char extra_upper[CAMERA_DATA_STRING_SIZE];
|
||||
int address;
|
||||
char parent_name[CAMERA_DATA_STRING_SIZE];
|
||||
char parent_deviceInstancePath[CAMERA_DATA_STRING_SIZE];
|
||||
int parent_address;
|
||||
|
||||
bool fake_addressed;
|
||||
int fake_address;
|
||||
|
||||
bool fake_located;
|
||||
size_t fake_located_node;
|
||||
};
|
||||
|
||||
static struct CameraData camData[CAMHOOK_CONFIG_CAM_MAX];
|
||||
int camAddresses[CAMHOOK_CONFIG_CAM_MAX] = {
|
||||
1,
|
||||
7,
|
||||
};
|
||||
static size_t num_addressed_cams = 0;
|
||||
static size_t num_located_cams = 0;
|
||||
|
||||
static CONFIGRET my_CM_Locate_DevNodeA(
|
||||
PDEVINST pdnDevInst, DEVINSTID_A pDeviceID, ULONG ulFlags);
|
||||
|
||||
static CONFIGRET
|
||||
my_CM_Get_Parent(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags);
|
||||
|
||||
static CONFIGRET my_CM_Get_Device_IDA(
|
||||
DEVINST dnDevInst, PSTR Buffer, ULONG BufferLen, ULONG ulFlags);
|
||||
|
||||
static CONFIGRET (*real_CM_Locate_DevNodeA)(
|
||||
PDEVINST pdnDevInst, DEVINSTID_A pDeviceID, ULONG ulFlags);
|
||||
|
||||
static CONFIGRET (*real_CM_Get_Parent)(
|
||||
PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags);
|
||||
|
||||
static CONFIGRET (*real_CM_Get_Device_IDA)(
|
||||
DEVINST dnDevInst, PSTR Buffer, ULONG BufferLen, ULONG ulFlags);
|
||||
|
||||
static HRESULT my_MFEnumDeviceSources(
|
||||
IMFAttributes *pAttributes,
|
||||
IMFActivate ***pppSourceActivate,
|
||||
UINT32 *pcSourceActivate);
|
||||
|
||||
static HRESULT (*real_MFEnumDeviceSources)(
|
||||
IMFAttributes *pAttributes,
|
||||
IMFActivate ***pppSourceActivate,
|
||||
UINT32 *pcSourceActivate);
|
||||
|
||||
static BOOL my_SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet);
|
||||
|
||||
static BOOL (*real_SetupDiDestroyDeviceInfoList)(HDEVINFO DeviceInfoSet);
|
||||
|
||||
static BOOL my_SetupDiEnumDeviceInfo(
|
||||
HDEVINFO DeviceInfoSet, DWORD MemberIndex, PSP_DEVINFO_DATA DeviceInfoData);
|
||||
|
||||
static BOOL (*real_SetupDiEnumDeviceInfo)(
|
||||
HDEVINFO DeviceInfoSet, DWORD MemberIndex, PSP_DEVINFO_DATA DeviceInfoData);
|
||||
|
||||
static BOOL my_SetupDiGetDeviceRegistryPropertyA(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
PSP_DEVINFO_DATA DeviceInfoData,
|
||||
DWORD Property,
|
||||
PDWORD PropertyRegDataType,
|
||||
PBYTE PropertyBuffer,
|
||||
DWORD PropertyBufferSize,
|
||||
PDWORD RequiredSize);
|
||||
|
||||
static BOOL (*real_SetupDiGetDeviceRegistryPropertyA)(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
PSP_DEVINFO_DATA DeviceInfoData,
|
||||
DWORD Property,
|
||||
PDWORD PropertyRegDataType,
|
||||
PBYTE PropertyBuffer,
|
||||
DWORD PropertyBufferSize,
|
||||
PDWORD RequiredSize);
|
||||
|
||||
static HDEVINFO my_SetupDiGetClassDevsA(
|
||||
CONST GUID *ClassGuid, PCSTR Enumerator, HWND hwndParent, DWORD Flags);
|
||||
|
||||
static HDEVINFO (*real_SetupDiGetClassDevsA)(
|
||||
CONST GUID *ClassGuid, PCSTR Enumerator, HWND hwndParent, DWORD Flags);
|
||||
|
||||
static const struct hook_symbol camhook_cfgmgr32_syms[] = {
|
||||
{.name = "CM_Locate_DevNodeA",
|
||||
.patch = my_CM_Locate_DevNodeA,
|
||||
.link = (void **) &real_CM_Locate_DevNodeA},
|
||||
{.name = "CM_Get_Parent",
|
||||
.patch = my_CM_Get_Parent,
|
||||
.link = (void **) &real_CM_Get_Parent},
|
||||
{.name = "CM_Get_Device_IDA",
|
||||
.patch = my_CM_Get_Device_IDA,
|
||||
.link = (void **) &real_CM_Get_Device_IDA},
|
||||
{.name = "SetupDiDestroyDeviceInfoList",
|
||||
.patch = my_SetupDiDestroyDeviceInfoList,
|
||||
.link = (void **) &real_SetupDiDestroyDeviceInfoList},
|
||||
{.name = "SetupDiEnumDeviceInfo",
|
||||
.patch = my_SetupDiEnumDeviceInfo,
|
||||
.link = (void **) &real_SetupDiEnumDeviceInfo},
|
||||
{.name = "SetupDiGetDeviceRegistryPropertyA",
|
||||
.patch = my_SetupDiGetDeviceRegistryPropertyA,
|
||||
.link = (void **) &real_SetupDiGetDeviceRegistryPropertyA},
|
||||
{.name = "SetupDiGetClassDevsA",
|
||||
.patch = my_SetupDiGetClassDevsA,
|
||||
.link = (void **) &real_SetupDiGetClassDevsA},
|
||||
};
|
||||
|
||||
static const struct hook_symbol camhook_mf_syms[] = {
|
||||
{.name = "MFEnumDeviceSources",
|
||||
.patch = my_MFEnumDeviceSources,
|
||||
.link = (void **) &real_MFEnumDeviceSources},
|
||||
};
|
||||
|
||||
DEVINST camhook_custom_nodes[CAMHOOK_CONFIG_CAM_MAX] = {
|
||||
0x04040004,
|
||||
0x04040008,
|
||||
};
|
||||
DEVINST camhook_custom_parent_nodes[CAMHOOK_CONFIG_CAM_MAX] = {
|
||||
0x04040014,
|
||||
0x04040018,
|
||||
};
|
||||
const char *camhook_custom_parent_device_id[CAMHOOK_CONFIG_CAM_MAX] = {
|
||||
"USB\\VEN_1022&DEV_7908",
|
||||
"USB\\VEN_1022&DEV_7914",
|
||||
};
|
||||
|
||||
static CONFIGRET
|
||||
my_CM_Locate_DevNodeA(PDEVINST pdnDevInst, DEVINSTID_A pDeviceID, ULONG ulFlags)
|
||||
{
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
|
||||
char builtString[CAMERA_DATA_STRING_SIZE] = {0};
|
||||
if (pdnDevInst) {
|
||||
for (size_t i = 0; i < CAMHOOK_CONFIG_CAM_MAX; ++i) {
|
||||
if (camData[i].setup) {
|
||||
snprintf(
|
||||
builtString,
|
||||
CAMERA_DATA_STRING_SIZE,
|
||||
"USB\\VID_288C&PID_0002&MI_00\\%s",
|
||||
camData[i].extra_upper);
|
||||
if (strcmp(pDeviceID, builtString) == 0) {
|
||||
if (!camData[i].fake_located) {
|
||||
camData[i].fake_located_node = num_located_cams;
|
||||
camData[i].fake_located = true;
|
||||
++num_located_cams;
|
||||
}
|
||||
log_info(
|
||||
"Injecting custom device %d to node %x",
|
||||
(int) i,
|
||||
(int) camData[i].fake_located_node);
|
||||
*pdnDevInst =
|
||||
camhook_custom_nodes[camData[i].fake_located_node];
|
||||
return CR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return real_CM_Locate_DevNodeA(pdnDevInst, pDeviceID, ulFlags);
|
||||
}
|
||||
|
||||
static CONFIGRET
|
||||
my_CM_Get_Parent(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags)
|
||||
{
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
|
||||
if (pdnDevInst) {
|
||||
for (size_t i = 0; i < CAMHOOK_CONFIG_CAM_MAX; ++i) {
|
||||
if (dnDevInst == camhook_custom_nodes[i]) {
|
||||
log_info("Injecting custom parent %d", (int) i);
|
||||
*pdnDevInst = camhook_custom_parent_nodes[i];
|
||||
return CR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return real_CM_Get_Parent(pdnDevInst, dnDevInst, ulFlags);
|
||||
}
|
||||
|
||||
static CONFIGRET my_CM_Get_Device_IDA(
|
||||
DEVINST dnDevInst, PSTR Buffer, ULONG BufferLen, ULONG ulFlags)
|
||||
{
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
if (Buffer) {
|
||||
for (size_t i = 0; i < CAMHOOK_CONFIG_CAM_MAX; ++i) {
|
||||
if (dnDevInst == camhook_custom_parent_nodes[i]) {
|
||||
log_info("Injecting custom parent %d ID", (int) i);
|
||||
strncpy(Buffer, camhook_custom_parent_device_id[i], BufferLen);
|
||||
Buffer[BufferLen - 1] = '\0';
|
||||
log_info("%s", Buffer);
|
||||
return CR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
return real_CM_Get_Device_IDA(dnDevInst, Buffer, BufferLen, ulFlags);
|
||||
}
|
||||
|
||||
static HRESULT(STDCALL *real_GetAllocatedString)(
|
||||
IMFActivate *self, REFGUID guidKey, LPWSTR *ppwszValue, UINT32 *pcchLength);
|
||||
|
||||
HRESULT my_GetAllocatedString(
|
||||
IMFActivate *self, REFGUID guidKey, LPWSTR *ppwszValue, UINT32 *pcchLength)
|
||||
{
|
||||
HRESULT ret;
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
|
||||
// should probably check GUID, oh well
|
||||
ret = real_GetAllocatedString(self, guidKey, ppwszValue, pcchLength);
|
||||
log_info("Obtained: %ls", *ppwszValue);
|
||||
|
||||
wchar_t *pwc = NULL;
|
||||
|
||||
// look for a matching deviceSymbolicLink
|
||||
for (size_t i = 0; i < CAMHOOK_CONFIG_CAM_MAX; ++i) {
|
||||
if (!pwc) {
|
||||
if (camData[i].setup) {
|
||||
pwc = wcsstr(*ppwszValue, camData[i].deviceSymbolicLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if matches, replace with target device ID
|
||||
if (pwc) {
|
||||
// \\?\usb#vid_288c&pid_0002&mi_00
|
||||
pwc[12] = L'2';
|
||||
pwc[13] = L'8';
|
||||
pwc[14] = L'8';
|
||||
pwc[15] = L'c';
|
||||
|
||||
pwc[21] = L'0';
|
||||
pwc[22] = L'0';
|
||||
pwc[23] = L'0';
|
||||
pwc[24] = L'2';
|
||||
|
||||
pwc[29] = L'0';
|
||||
pwc[30] = L'0';
|
||||
log_info("Replaced: %ls", *ppwszValue);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static HRESULT my_MFEnumDeviceSources(
|
||||
IMFAttributes *pAttributes,
|
||||
IMFActivate ***pppSourceActivate,
|
||||
UINT32 *pcSourceActivate)
|
||||
{
|
||||
IMFActivate *api;
|
||||
IMFActivateVtbl *api_vtbl;
|
||||
struct com_proxy *api_proxy;
|
||||
|
||||
UINT32 nsrcs;
|
||||
|
||||
HRESULT ret;
|
||||
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
ret = real_MFEnumDeviceSources(
|
||||
pAttributes, pppSourceActivate, pcSourceActivate);
|
||||
nsrcs = *pcSourceActivate;
|
||||
|
||||
for (UINT32 i = 0; i < nsrcs; ++i) {
|
||||
api = (*pppSourceActivate)[i];
|
||||
api_proxy = com_proxy_wrap(api, sizeof(*api->lpVtbl));
|
||||
api_vtbl = api_proxy->vptr;
|
||||
|
||||
real_GetAllocatedString = api_vtbl->GetAllocatedString;
|
||||
api_vtbl->GetAllocatedString = my_GetAllocatedString;
|
||||
|
||||
(*pppSourceActivate)[i] = (IMFActivate *) api_proxy;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CUSTOM_DEVICE_HANDLE (void *) 0x04041110
|
||||
static HDEVINFO RealReplacedHandle;
|
||||
|
||||
static BOOL my_SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet)
|
||||
{
|
||||
if (DeviceInfoSet == CUSTOM_DEVICE_HANDLE) {
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
DeviceInfoSet = RealReplacedHandle;
|
||||
RealReplacedHandle = NULL;
|
||||
|
||||
return real_SetupDiDestroyDeviceInfoList(DeviceInfoSet);
|
||||
}
|
||||
|
||||
return real_SetupDiDestroyDeviceInfoList(DeviceInfoSet);
|
||||
}
|
||||
|
||||
static BOOL my_SetupDiEnumDeviceInfo(
|
||||
HDEVINFO DeviceInfoSet, DWORD MemberIndex, PSP_DEVINFO_DATA DeviceInfoData)
|
||||
{
|
||||
if (DeviceInfoSet == CUSTOM_DEVICE_HANDLE) {
|
||||
// log_info("Inside: %s", __FUNCTION__);
|
||||
return real_SetupDiEnumDeviceInfo(
|
||||
RealReplacedHandle, MemberIndex, DeviceInfoData);
|
||||
}
|
||||
|
||||
return real_SetupDiEnumDeviceInfo(
|
||||
DeviceInfoSet, MemberIndex, DeviceInfoData);
|
||||
}
|
||||
|
||||
static BOOL my_SetupDiGetDeviceRegistryPropertyA(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
PSP_DEVINFO_DATA DeviceInfoData,
|
||||
DWORD Property,
|
||||
PDWORD PropertyRegDataType,
|
||||
PBYTE PropertyBuffer,
|
||||
DWORD PropertyBufferSize,
|
||||
PDWORD RequiredSize)
|
||||
{
|
||||
if (DeviceInfoSet == CUSTOM_DEVICE_HANDLE) {
|
||||
BOOL ret = real_SetupDiGetDeviceRegistryPropertyA(
|
||||
RealReplacedHandle,
|
||||
DeviceInfoData,
|
||||
Property,
|
||||
PropertyRegDataType,
|
||||
PropertyBuffer,
|
||||
PropertyBufferSize,
|
||||
RequiredSize);
|
||||
|
||||
if (Property == SPDRP_DEVICEDESC) {
|
||||
if (PropertyBuffer) {
|
||||
char *PropertyBufferChar = (char *) PropertyBuffer;
|
||||
for (size_t i = 0; i < CAMHOOK_CONFIG_CAM_MAX; ++i) {
|
||||
if (camData[i].setup) {
|
||||
if (strcmp(
|
||||
PropertyBufferChar, camData[i].parent_name) ==
|
||||
0) {
|
||||
log_info(
|
||||
"%s: replacing %s",
|
||||
__FUNCTION__,
|
||||
camData[i].parent_name);
|
||||
strncpy(
|
||||
PropertyBufferChar,
|
||||
"USB Composite Device",
|
||||
PropertyBufferSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else if (Property == SPDRP_ADDRESS) {
|
||||
if (PropertyBuffer) {
|
||||
int addr = *(int *) PropertyBuffer;
|
||||
for (size_t i = 0; i < CAMHOOK_CONFIG_CAM_MAX; ++i) {
|
||||
if (camData[i].setup) {
|
||||
if (addr == camData[i].parent_address) {
|
||||
if (!camData[i].fake_addressed) {
|
||||
camData[i].fake_address =
|
||||
camAddresses[num_addressed_cams];
|
||||
camData[i].fake_addressed = true;
|
||||
++num_addressed_cams;
|
||||
}
|
||||
log_info(
|
||||
"%s: assigning cam %d to addr %d",
|
||||
__FUNCTION__,
|
||||
(int) i,
|
||||
camData[i].fake_address);
|
||||
*(int *) PropertyBuffer = camData[i].fake_address;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return real_SetupDiGetDeviceRegistryPropertyA(
|
||||
DeviceInfoSet,
|
||||
DeviceInfoData,
|
||||
Property,
|
||||
PropertyRegDataType,
|
||||
PropertyBuffer,
|
||||
PropertyBufferSize,
|
||||
RequiredSize);
|
||||
}
|
||||
|
||||
static HDEVINFO my_SetupDiGetClassDevsA(
|
||||
CONST GUID *ClassGuid, PCSTR Enumerator, HWND hwndParent, DWORD Flags)
|
||||
{
|
||||
if (ClassGuid == NULL && Enumerator != NULL && hwndParent == NULL &&
|
||||
Flags == (DIGCF_PRESENT | DIGCF_ALLCLASSES)) {
|
||||
if (RealReplacedHandle) {
|
||||
log_info("Replacement handle is already set?");
|
||||
}
|
||||
|
||||
if (strcmp(Enumerator, "USB") == 0) {
|
||||
log_info("Inside: %s", __FUNCTION__);
|
||||
RealReplacedHandle = real_SetupDiGetClassDevsA(
|
||||
ClassGuid, Enumerator, hwndParent, Flags);
|
||||
|
||||
if (RealReplacedHandle == INVALID_HANDLE_VALUE) {
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
return CUSTOM_DEVICE_HANDLE;
|
||||
}
|
||||
}
|
||||
return real_SetupDiGetClassDevsA(ClassGuid, Enumerator, hwndParent, Flags);
|
||||
}
|
||||
|
||||
bool check_four(const char inA[4], const char inB[4])
|
||||
{
|
||||
return (*(uint32_t *) inA == *(uint32_t *) inB);
|
||||
}
|
||||
|
||||
char *grab_next_camera_id(char *buffer, size_t bsz)
|
||||
{
|
||||
static size_t gotten = 0;
|
||||
|
||||
IMFAttributes *pAttributes = NULL;
|
||||
IMFActivate **ppDevices = NULL;
|
||||
|
||||
buffer[0] = '\0';
|
||||
|
||||
HRESULT hr = MFCreateAttributes(&pAttributes, 1);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_info("MFCreateAttributes failed: %ld", hr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
hr = pAttributes->lpVtbl->SetGUID(
|
||||
pAttributes,
|
||||
&MY_MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
|
||||
&MY_MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
|
||||
if (FAILED(hr)) {
|
||||
log_info("SetGUID failed: %ld", hr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
UINT32 count;
|
||||
hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_info("MFEnumDeviceSources failed: %ld", hr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (count <= gotten) {
|
||||
log_info("gotten failed: %d < %d", count, (int) gotten);
|
||||
// not enough remaining
|
||||
goto done;
|
||||
}
|
||||
|
||||
wchar_t wSymLink[CAMERA_DATA_STRING_SIZE];
|
||||
UINT32 sz;
|
||||
|
||||
hr = ppDevices[gotten]->lpVtbl->GetString(
|
||||
ppDevices[gotten],
|
||||
&MY_MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
|
||||
wSymLink,
|
||||
CAMERA_DATA_STRING_SIZE,
|
||||
&sz);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_info("GetString failed: %ld", hr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
log_info("Detected webcam: %s\n", buffer);
|
||||
wcstombs(buffer, wSymLink, bsz);
|
||||
++gotten;
|
||||
|
||||
done:
|
||||
if (pAttributes) {
|
||||
pAttributes->lpVtbl->Release(pAttributes);
|
||||
}
|
||||
|
||||
for (DWORD i = 0; i < count; i++) {
|
||||
if (ppDevices != NULL && ppDevices[i]) {
|
||||
ppDevices[i]->lpVtbl->Release(ppDevices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
CoTaskMemFree(ppDevices);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool convert_sym_to_path(const char *sym, char *path)
|
||||
{
|
||||
HDEVINFO DeviceInfoSet = SetupDiCreateDeviceInfoList(NULL, NULL);
|
||||
|
||||
if (DeviceInfoSet == INVALID_HANDLE_VALUE) {
|
||||
log_info("Could not open SetupDiCreateDeviceInfoList\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData = {0};
|
||||
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
||||
|
||||
if (!SetupDiOpenDeviceInterfaceA(
|
||||
DeviceInfoSet, sym, 0, &DeviceInterfaceData)) {
|
||||
log_info("Could not SetupDiOpenDeviceInterfaceA\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SP_DEVINFO_DATA DeviceInfoData = {0};
|
||||
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||
|
||||
if (!SetupDiGetDeviceInterfaceDetailA(
|
||||
DeviceInfoSet,
|
||||
&DeviceInterfaceData,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
&DeviceInfoData)) {
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
log_info("Could not SetupDiGetDeviceInterfaceDetailA\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD sz;
|
||||
|
||||
if (!SetupDiGetDeviceInstanceIdA(
|
||||
DeviceInfoSet,
|
||||
&DeviceInfoData,
|
||||
path,
|
||||
CAMERA_DATA_STRING_SIZE,
|
||||
&sz)) {
|
||||
log_info("Could not SetupDiGetDeviceInstanceIdA\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (DeviceInfoSet != INVALID_HANDLE_VALUE) {
|
||||
if (!SetupDiDeleteDeviceInterfaceData(
|
||||
DeviceInfoSet, &DeviceInterfaceData)) {
|
||||
log_info("Could not SetupDiDeleteDeviceInterfaceData\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void strtolower(char *str)
|
||||
{
|
||||
for (size_t i = 0; str[i]; i++) {
|
||||
str[i] = tolower(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool convert_path_to_fakesym(const char *path, wchar_t *sym, char *extra_o)
|
||||
{
|
||||
char root[16] = {0};
|
||||
char vidstr[16] = {0};
|
||||
char pidstr[16] = {0};
|
||||
char mistr[16] = {0};
|
||||
char extra[64] = {0};
|
||||
sscanf(
|
||||
path,
|
||||
"%[^\\]\\%[^&]&%[^&]&%[^\\]\\%s",
|
||||
root,
|
||||
vidstr,
|
||||
pidstr,
|
||||
mistr,
|
||||
extra);
|
||||
strcpy(extra_o, extra);
|
||||
|
||||
strtolower(root);
|
||||
strtolower(vidstr);
|
||||
strtolower(pidstr);
|
||||
strtolower(mistr);
|
||||
strtolower(extra);
|
||||
|
||||
swprintf(
|
||||
sym,
|
||||
CAMERA_DATA_STRING_SIZE,
|
||||
L"\\\\?\\%S#%S&%S&%S#%S",
|
||||
root,
|
||||
vidstr,
|
||||
pidstr,
|
||||
mistr,
|
||||
extra);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void fill_cam_struct(struct CameraData *data, const char *devid)
|
||||
{
|
||||
char buffer[CAMERA_DATA_STRING_SIZE];
|
||||
|
||||
data->setup = false;
|
||||
|
||||
if (!devid || strlen(devid) == 0) {
|
||||
devid = grab_next_camera_id(buffer, CAMERA_DATA_STRING_SIZE);
|
||||
}
|
||||
|
||||
if (!devid || strlen(devid) == 0) {
|
||||
// no more cameras remain?
|
||||
return;
|
||||
}
|
||||
|
||||
if (strlen(devid) >= CAMERA_DATA_STRING_SIZE) {
|
||||
// error probably log something?
|
||||
return;
|
||||
}
|
||||
|
||||
// detect input type
|
||||
if (check_four(devid, "\\\\?\\")) {
|
||||
// SYMBOLIC_LINK
|
||||
if (!convert_sym_to_path(devid, data->deviceInstancePath)) {
|
||||
log_info("Could not convert %s to path", devid);
|
||||
return;
|
||||
}
|
||||
} else if (check_four(devid, "USB\\")) {
|
||||
// Device instance path
|
||||
strcpy(data->deviceInstancePath, devid);
|
||||
// continue
|
||||
} else {
|
||||
// UNKNOWN ENTRY
|
||||
log_info("UNK: %s", devid);
|
||||
log_info("Please enter the device instance path");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!convert_path_to_fakesym(
|
||||
data->deviceInstancePath,
|
||||
data->deviceSymbolicLink,
|
||||
data->extra_upper)) {
|
||||
log_info("Could not convert %s to sym", data->deviceInstancePath);
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("dev path: %s", data->deviceInstancePath);
|
||||
|
||||
// locate device nodes
|
||||
DEVINST dnDevInst;
|
||||
DEVINST parentDev;
|
||||
CONFIGRET cmret;
|
||||
|
||||
cmret = CM_Locate_DevNodeA(
|
||||
&dnDevInst, data->deviceInstancePath, CM_LOCATE_DEVNODE_NORMAL);
|
||||
|
||||
if (cmret != CR_SUCCESS) {
|
||||
log_info("CM_Locate_DevNodeA fail: %s", data->deviceInstancePath);
|
||||
return;
|
||||
}
|
||||
|
||||
cmret = CM_Get_Parent(&parentDev, dnDevInst, 0);
|
||||
|
||||
if (cmret != CR_SUCCESS) {
|
||||
log_info("CM_Get_Parent fail: %s", data->deviceInstancePath);
|
||||
return;
|
||||
}
|
||||
cmret = CM_Get_Device_IDA(
|
||||
parentDev, data->parent_deviceInstancePath, CAMERA_DATA_STRING_SIZE, 0);
|
||||
|
||||
if (cmret != CR_SUCCESS) {
|
||||
log_info("CM_Get_Device_IDA parent fail: %s", data->deviceInstancePath);
|
||||
return;
|
||||
}
|
||||
|
||||
ULONG szAddr;
|
||||
ULONG szDesc;
|
||||
|
||||
szAddr = 4;
|
||||
szDesc = CAMERA_DATA_STRING_SIZE;
|
||||
cmret = CM_Get_DevNode_Registry_PropertyA(
|
||||
dnDevInst, CM_DRP_ADDRESS, NULL, &data->address, &szAddr, 0);
|
||||
|
||||
if (cmret != CR_SUCCESS) {
|
||||
log_info(
|
||||
"CM_Get_DevNode_Registry_PropertyA fail: %s",
|
||||
data->deviceInstancePath);
|
||||
return;
|
||||
}
|
||||
|
||||
cmret = CM_Get_DevNode_Registry_PropertyA(
|
||||
dnDevInst, CM_DRP_DEVICEDESC, NULL, &data->name, &szDesc, 0);
|
||||
|
||||
if (cmret != CR_SUCCESS) {
|
||||
log_info(
|
||||
"CM_Get_DevNode_Registry_PropertyA fail: %s",
|
||||
data->deviceInstancePath);
|
||||
return;
|
||||
}
|
||||
|
||||
szAddr = 4;
|
||||
szDesc = CAMERA_DATA_STRING_SIZE;
|
||||
cmret = CM_Get_DevNode_Registry_PropertyA(
|
||||
parentDev, CM_DRP_ADDRESS, NULL, &data->parent_address, &szAddr, 0);
|
||||
|
||||
if (cmret != CR_SUCCESS) {
|
||||
log_info(
|
||||
"CM_Get_DevNode_Registry_PropertyA parent fail: %s",
|
||||
data->deviceInstancePath);
|
||||
return;
|
||||
}
|
||||
|
||||
cmret = CM_Get_DevNode_Registry_PropertyA(
|
||||
parentDev, CM_DRP_DEVICEDESC, NULL, &data->parent_name, &szDesc, 0);
|
||||
|
||||
if (cmret != CR_SUCCESS) {
|
||||
log_info(
|
||||
"CM_Get_DevNode_Registry_PropertyA parent fail: %s",
|
||||
data->deviceInstancePath);
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("Found %s @ %d", data->name, data->address);
|
||||
log_info("Parent %s @ %d", data->parent_name, data->parent_address);
|
||||
data->setup = true;
|
||||
}
|
||||
|
||||
void camhook_init(struct camhook_config_cam *config_cam)
|
||||
{
|
||||
// fill before applying hooks
|
||||
for (size_t i = 0; i < config_cam->num_devices; ++i) {
|
||||
fill_cam_struct(&camData[i], config_cam->device_id[i]);
|
||||
}
|
||||
|
||||
size_t num_setup = 0;
|
||||
for (size_t i = 0; i < config_cam->num_devices; ++i) {
|
||||
if (camData[i].setup) {
|
||||
num_setup++;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_setup > 0) {
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"setupapi.dll",
|
||||
camhook_cfgmgr32_syms,
|
||||
lengthof(camhook_cfgmgr32_syms));
|
||||
hook_table_apply(
|
||||
NULL, "Mf.dll", camhook_mf_syms, lengthof(camhook_mf_syms));
|
||||
|
||||
log_info("Inserted cam hooks for %d cams", (int) num_setup);
|
||||
} else {
|
||||
log_info("No cams detected, not hooking");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef CAMHOOK_CAM_H
|
||||
#define CAMHOOK_CAM_H
|
||||
|
||||
#include "camhook/config-cam.h"
|
||||
|
||||
void camhook_init(struct camhook_config_cam *config_cam);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
#include "cconfig/cconfig-util.h"
|
||||
|
||||
#include "camhook/config-cam.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
#define CAMHOOK_CONFIG_CAM_DISABLE_EMU_KEY "cam.disable_emu"
|
||||
#define CAMHOOK_CONFIG_CAM_DEFAULT_DISABLE_EMU_VALUE false
|
||||
|
||||
const char *camhook_config_device_id_keys[CAMHOOK_CONFIG_CAM_MAX] = {
|
||||
"cam.device_id1",
|
||||
"cam.device_id2",
|
||||
};
|
||||
|
||||
const char *camhook_config_device_default_values[CAMHOOK_CONFIG_CAM_MAX] = {
|
||||
"",
|
||||
"",
|
||||
};
|
||||
|
||||
void camhook_config_cam_init(struct cconfig *config, size_t num_cams)
|
||||
{
|
||||
cconfig_util_set_bool(
|
||||
config,
|
||||
CAMHOOK_CONFIG_CAM_DISABLE_EMU_KEY,
|
||||
CAMHOOK_CONFIG_CAM_DEFAULT_DISABLE_EMU_VALUE,
|
||||
"Disables the camera emulation");
|
||||
|
||||
for (size_t i = 0; i < num_cams; ++i) {
|
||||
cconfig_util_set_str(
|
||||
config,
|
||||
camhook_config_device_id_keys[i],
|
||||
camhook_config_device_default_values[i],
|
||||
"Override camera device ID detection (copy from device manager, do "
|
||||
"not escape)");
|
||||
}
|
||||
}
|
||||
|
||||
void camhook_config_cam_get(
|
||||
struct camhook_config_cam *config_cam,
|
||||
struct cconfig *config,
|
||||
size_t num_cams)
|
||||
{
|
||||
config_cam->num_devices = num_cams;
|
||||
|
||||
if (!cconfig_util_get_bool(
|
||||
config,
|
||||
CAMHOOK_CONFIG_CAM_DISABLE_EMU_KEY,
|
||||
&config_cam->disable_emu,
|
||||
CAMHOOK_CONFIG_CAM_DEFAULT_DISABLE_EMU_VALUE)) {
|
||||
log_warning(
|
||||
"Invalid value for key '%s' specified, fallback "
|
||||
"to default '%d'",
|
||||
CAMHOOK_CONFIG_CAM_DISABLE_EMU_KEY,
|
||||
CAMHOOK_CONFIG_CAM_DEFAULT_DISABLE_EMU_VALUE);
|
||||
}
|
||||
for (size_t i = 0; i < num_cams; ++i) {
|
||||
if (!cconfig_util_get_str(
|
||||
config,
|
||||
camhook_config_device_id_keys[i],
|
||||
config_cam->device_id[i],
|
||||
sizeof(config_cam->device_id[i]) - 1,
|
||||
camhook_config_device_default_values[i])) {
|
||||
log_warning(
|
||||
"Invalid value for key '%s' specified, fallback "
|
||||
"to default '%s'",
|
||||
camhook_config_device_id_keys[i],
|
||||
camhook_config_device_default_values[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef CAMHOOK_CONFIG_CAM_H
|
||||
#define CAMHOOK_CONFIG_CAM_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "cconfig/cconfig.h"
|
||||
|
||||
#define CAMHOOK_CONFIG_CAM_MAX 2
|
||||
|
||||
struct camhook_config_cam {
|
||||
bool disable_emu;
|
||||
size_t num_devices;
|
||||
char device_id[CAMHOOK_CONFIG_CAM_MAX][MAX_PATH];
|
||||
};
|
||||
|
||||
void camhook_config_cam_init(struct cconfig *config, size_t num_cams);
|
||||
|
||||
void camhook_config_cam_get(
|
||||
struct camhook_config_cam *config_cam,
|
||||
struct cconfig *config,
|
||||
size_t num_cams);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user