First commit of the project

Just a first try.
This commit is contained in:
Martin Richter
2022-02-16 15:24:26 +01:00
parent e7e3ddafab
commit ffbe4ef6de
23 changed files with 2674 additions and 1 deletions

View File

@@ -0,0 +1,665 @@
#include "pch.h"
// #include <sstream>
// #include <iomanip>
// #include <iostream> // Including this before DShow.h avoids a bunch of C4995 warnings for unsafe
// // string functions if (and only if) strsafe.h is not included above.
#include <initguid.h>
#include <comdef.h>
#define NO_DSHOW_STRSAFE // Avoid more C4995 warnings in intrin.h
#include <DShow.h>
#include <Ks.h>
#include <KsMedia.h>
#pragma comment(lib, "strmiids.lib")
#include "ExtensionUnit.h"
#define NONODE 0xFFFFFFFF
//////////////////////////////////////////////////////////////////////////
void MySleep(int mSec)
{
// TIcks per second
LARGE_INTEGER li;
QueryPerformanceFrequency(&li);
LARGE_INTEGER liStart;
QueryPerformanceCounter(&liStart);
LARGE_INTEGER liEnd;
liEnd.QuadPart = liStart.QuadPart + (li.QuadPart*mSec)/1000;
LARGE_INTEGER liNow;
do
{
QueryPerformanceCounter(&liNow);
}
while (liNow.QuadPart<liEnd.QuadPart);
TRACE(__FUNCTION__ " %d\n", DWORD((liNow.QuadPart-liStart.QuadPart)*1000/li.QuadPart));
}
CWebcamController::CWebcamController()
{
CloseDevice();
}
CWebcamController::~CWebcamController()
{
CloseDevice();
}
HRESULT CWebcamController::OpenDevice(BSTR bstrDevicePath, DWORD wVID, DWORD wPID)
{
// Create the System Device Enumerator
CComPtr<ICreateDevEnum> pSysDevEnum;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, __uuidof(ICreateDevEnum), (void **)&pSysDevEnum);
if(FAILED(hr))
return hr;
// Obtain a class enumerator for the video input device category
CComPtr<IEnumMoniker> pEnumCat;
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
if(hr == S_OK)
{
hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
// Enumerate the monikers and check if we can find a matching device
CComPtr<IMoniker> pMoniker;
ULONG cFetched;
while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
{
if(DeviceMatches(pMoniker, bstrDevicePath, wVID, wPID))
{
hr = OpenDevice(pMoniker);
break; // We're done searching (even if the OpenDevice() call above failed)
}
pMoniker = nullptr;
}
}
return hr;
}
void CWebcamController::CloseDevice()
{
m_spKsControl = nullptr;
m_spAMCameraControl = nullptr;
m_spsPropertySet = nullptr;
m_spCameraControl = nullptr;
m_dwXUDeviceInformationNodeId =
m_dwXUVideoPipeControlNodeId =
m_dwXUTestDebugNodeId =
m_dwXUPeripheralControlNodeId = NONODE;
// Use IAMCameraControl motion control
m_bUseLogitechMotionControl = false;
m_iMotorIntervalTimer = DEFAULT_MOTOR_INTERVAL_TIMER;
// The PTZ Pro 2 has a mechanical pan tilt
m_bMechanicalPanTilt = false;
m_lDigitalTiltMin = m_lDigitalTiltMax = m_lDigitalPanMin = m_lDigitalPanMax = -1;
}
HRESULT CWebcamController::IsPeripheralPropertySetSupported()
{
if (!m_spKsControl)
return -1;
KSP_NODE extProp{};
extProp.Property.Set = LOGITECH_XU_PERIPHERAL_CONTROL;
extProp.Property.Id = 0;
extProp.Property.Flags = KSPROPERTY_TYPE_SETSUPPORT | KSPROPERTY_TYPE_TOPOLOGY;
extProp.NodeId = m_dwXUPeripheralControlNodeId;
extProp.Reserved = 0;
ULONG ulBytesReturned = 0;
return m_spKsControl->KsProperty((PKSPROPERTY)&extProp, sizeof(extProp), NULL, 0, &ulBytesReturned);
}
HRESULT CWebcamController::GetProperty(LOGITECH_XU_PROPERTYSET lPropertySet,ULONG ulPropertyId, ULONG ulSize, VOID *pValue)
{
if (!m_spKsControl)
return -1;
ASSERT(pValue!=0 && ulSize!=0);
KSP_NODE extprop{};
extprop.Property.Id = ulPropertyId;
extprop.Property.Flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_TOPOLOGY;
switch(lPropertySet)
{
case XU_DEVICE_INFORMATION:
extprop.NodeId = m_dwXUDeviceInformationNodeId;
extprop.Property.Set = LOGITECH_XU_DEVICE_INFORMATION;
break;
case XU_VIDEOPIPE_CONTROL:
extprop.NodeId = m_dwXUVideoPipeControlNodeId;
extprop.Property.Set = LOGITECH_XU_VIDEOPIPE_CONTROL;
break;
case XU_TEST_DEBUG:
extprop.NodeId = m_dwXUTestDebugNodeId;
extprop.Property.Set = LOGITECH_XU_TEST_DEBUG;
break;
case XU_PERIPHERAL_CONTROL:
extprop.NodeId = m_dwXUPeripheralControlNodeId;
extprop.Property.Set = LOGITECH_XU_PERIPHERAL_CONTROL;
break;
}
HRESULT hr = m_spKsControl->KsProperty(
(PKSPROPERTY)&extprop,
sizeof(extprop),
pValue,
ulSize,
&ulSize
);
return hr;
}
HRESULT CWebcamController::SetProperty(LOGITECH_XU_PROPERTYSET lPropertySet,ULONG ulPropertyId, ULONG ulSize, VOID *pValue)
{
if (!m_spKsControl)
return -1;
ASSERT(pValue != 0 && ulSize != 0);
KSP_NODE extprop{};
extprop.Property.Id = ulPropertyId;
extprop.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY;
switch(lPropertySet)
{
case XU_DEVICE_INFORMATION:
extprop.NodeId = m_dwXUDeviceInformationNodeId;
extprop.Property.Set = LOGITECH_XU_DEVICE_INFORMATION;
break;
case XU_VIDEOPIPE_CONTROL:
extprop.NodeId = m_dwXUVideoPipeControlNodeId;
extprop.Property.Set = LOGITECH_XU_VIDEOPIPE_CONTROL;
break;
case XU_TEST_DEBUG:
extprop.NodeId = m_dwXUTestDebugNodeId;
extprop.Property.Set = LOGITECH_XU_TEST_DEBUG;
break;
case XU_PERIPHERAL_CONTROL:
extprop.NodeId = m_dwXUPeripheralControlNodeId;
extprop.Property.Set = LOGITECH_XU_PERIPHERAL_CONTROL;
break;
}
ULONG ulBytesReturned;
HRESULT hr = m_spKsControl->KsProperty(
(PKSPROPERTY)&extprop,
sizeof(extprop),
pValue,
ulSize,
&ulBytesReturned
);
return hr;
}
/*
* Checks whether the device represented by the given IMoniker matches the given device path
* or the given VID/PID.
*
* If the device path is NULL no device path matching is performed.
* A VID or PID of 0 is considered to always match. If the VID and PID are both 0 no VID/PID
* matching is performed.
*/
bool CWebcamController::DeviceMatches(CComPtr<IMoniker> pMoniker, BSTR devicePath, DWORD wVID, DWORD wPID)
{
bool match = false;
CComPtr<IPropertyBag> pPropBag;
CComVariant varPath;
// Open the device properties
HRESULT hr = pMoniker->BindToStorage(NULL, NULL, __uuidof(IPropertyBag), (void **)&pPropBag);
if(FAILED(hr))
goto done;
// Retrieve the device path
hr = pPropBag->Read(L"DevicePath", &varPath, 0);
if(FAILED(hr) || varPath.bstrVal == NULL)
goto done;
// Return true if the device path matches
if(devicePath!=NULL)
{
// Parse the device path for vid pid
m_dwVid = m_dwPid = 0;
if (FAILED(varPath.ChangeType(VT_BSTR)))
return false;
if (_wcsicmp(varPath.bstrVal, devicePath) == 0)
{
// Lowercase
_wcslwr_s(varPath.bstrVal, SysStringLen(varPath.bstrVal) + 1);
ParseDevicePath(varPath.bstrVal, m_dwVid, m_dwPid);
match = true;
goto done;
}
}
// Return true if the USB information matches
if(wVID || wPID)
{
// Parse the device path (Convert it to lower-case first for safer parsing)
_wcslwr_s(varPath.bstrVal, SysStringLen(varPath.bstrVal) + 1);
DWORD vid = 0, pid = 0;
if(ParseDevicePath(varPath.bstrVal, vid, pid))
{
match =
(wVID == 0 || vid == wVID) &&
(wPID == 0 || pid == wPID);
}
}
done:
VariantClear(&varPath);
return match;
}
HRESULT CWebcamController::OpenDevice(CComPtr<IMoniker> pMoniker)
{
CComPtr<IKsControl> pKsControl;
// Get a pointer to the IKsControl interface
HRESULT hr = pMoniker->BindToObject(NULL, NULL, __uuidof(IKsControl), (void **)&pKsControl);
if(FAILED(hr))
return hr;
// Find the H.264 XU node
hr = InitializeXUNodesArray(pKsControl);
if(SUCCEEDED(hr))
{
// save the pointer, we succeeded
m_spKsControl = pKsControl;
m_spAMCameraControl = pKsControl;
m_spsPropertySet = pKsControl;
m_spCameraControl = pKsControl; // not supported
}
if (m_spAMCameraControl!=nullptr)
{
long lValue = 0, lMin = 0, lMax = 0, lSteppingSize = 0, lDefaults = 0, lFlags = 0;
HRESULT hResult = m_spAMCameraControl->Get(KSPROPERTY_CAMERACONTROL_PAN_RELATIVE, &lValue, &lFlags);
m_bMechanicalPanTilt = SUCCEEDED(hr);
{
for (int i=0; i<=19; ++i)
{
hResult = m_spAMCameraControl->Get(i, &lValue, &lFlags);
if (SUCCEEDED(hr))
TRACE(__FUNCTION__ " m_spAMCameraControl-%d val=%d, flag=%d\n",i, lValue, lFlags);
}
}
// The PTZ Pro 2 has a mechanical pan tilt
ASSERT(m_bMechanicalPanTilt);
// {
// HRESULT hResult = GetProperty( KSPROPERTY_CAMERACONTROL_PANTILT_RELATIVE, &lValue, &lFlags);
// }
hResult = m_spAMCameraControl->GetRange(CameraControl_Pan, &lMin, &lMax, &lSteppingSize, &lDefaults, &lFlags);
if (S_OK == hResult)
{
m_lDigitalPanMin = lMin;
m_lDigitalPanMax = lMax;
}
lMin = lMax = lSteppingSize = lDefaults = lFlags = 0;
hResult = m_spAMCameraControl->GetRange(CameraControl_Tilt, &lMin, &lMax, &lSteppingSize, &lDefaults, &lFlags);
if (S_OK == hResult)
{
m_lDigitalTiltMin = lMin;
m_lDigitalTiltMax = lMax;
}
}
return hr;
}
bool CWebcamController::ParseDevicePath(const wchar_t *devicePath, DWORD &vid, DWORD &pid)
{
if(swscanf_s(devicePath, L"\\\\?\\usb#vid_%04x&pid_%04x", &vid, &pid) != 2)
return false;
return true;
}
void CWebcamController::GetVidPid(DWORD& vid, DWORD& pid)
{
vid = m_dwVid;
pid = m_dwPid;
}
void CWebcamController::GotoHome()
{
// Zoom to Home
{
DWORD dwValue = 0;
SetProperty(XU_VIDEOPIPE_CONTROL, XU_VIDEO_FW_ZOOM_CONTROL, sizeof(dwValue), &dwValue);
}
// Zoom to Home
// Home = No Action
// 1 ?
// 2 ?
// Goto Home = 3
// 8 Presets
// Preset 1-8 = 4-11,
// Goto Preset 1-8 = 12-19
// Test 22
{
DWORD dwValue(3);
SetProperty(XU_PERIPHERAL_CONTROL, XU_PERIPHERALCONTROL_PANTILT_MODE_CONTROL, sizeof(DWORD), &dwValue);
}
return;
}
void CWebcamController::SavePreset(int iNum)
{
if (iNum<0 || iNum>=NUM_PRESETS)
return;
// Zoom to Home
// Home = No Action
// 1 ?
// 2 ?
// Goto Home = 3
// 8 Presets
// Preset 1-8 = 4-11,
// Goto Preset 1-8 = 12-19
// Test 22
DWORD dwValue(iNum+4);
SetProperty(XU_PERIPHERAL_CONTROL, XU_PERIPHERALCONTROL_PANTILT_MODE_CONTROL, sizeof(DWORD), &dwValue);
}
void CWebcamController::GotoPreset(int iNum)
{
if (iNum<0 || iNum>=NUM_PRESETS)
return;
// Zoom to Home
// Home = No Action
// 1 ?
// 2 ?
// Goto Home = 3
// 8 Presets
// Preset 1-8 = 4-11,
// Goto Preset 1-8 = 12-19
// Test 22
DWORD dwValue(iNum + 12);
SetProperty(XU_PERIPHERAL_CONTROL, XU_PERIPHERALCONTROL_PANTILT_MODE_CONTROL, sizeof(DWORD), &dwValue);
}
int CWebcamController::GetCurrentZoom()
{
if (!m_spAMCameraControl)
return -1;
long oldZoom = 0, oldFlags = 0;
oldFlags = CameraControl_Flags_Manual;
m_spAMCameraControl->Get(CameraControl_Zoom, &oldZoom, &oldFlags);
return oldZoom;
}
int CWebcamController::Zoom(int direction)
{
if (!m_spAMCameraControl)
return -1;
long lZoomMin = 0, lZoomMax = 0, lZoomDefault = 0, lZoomStep = 0, lFlags = CameraControl_Flags_Manual;
m_spAMCameraControl->GetRange(CameraControl_Zoom, &lZoomMin, &lZoomMax, &lZoomStep, &lZoomDefault, &lFlags);
long lOldZoom = GetCurrentZoom();
if (lOldZoom<lZoomMin || lOldZoom>lZoomMax)
lOldZoom = lZoomDefault;
long lNewZoom = lOldZoom;
// Devide in 150 parts
int iStep = (lZoomMax-lZoomMin)/150;
if (iStep==0)
iStep = 1;
// calculate new zoom
lNewZoom = lOldZoom + lZoomStep*direction*iStep; // Just get 100 steps
m_spAMCameraControl->Set(CameraControl_Zoom, lNewZoom, CameraControl_Flags_Manual);
return lNewZoom;
}
void CWebcamController::Tilt(int yDirection)
{
if (m_spAMCameraControl)
m_spAMCameraControl->Set(KSPROPERTY_CAMERACONTROL_TILT_RELATIVE, yDirection!=0 ? (yDirection < 0 ? -1 : 1) : 0, 0);
}
void CWebcamController::MoveTilt(int yDirection)
{
if (m_bUseLogitechMotionControl && m_dwXUPeripheralControlNodeId!=NONODE)
{
DWORD dwValue = MAKELONG(MAKEWORD(0, 0), MAKEWORD(0, yDirection < 0 ? 1 : -1));
SetProperty(XU_PERIPHERAL_CONTROL, XU_PERIPHERALCONTROL_PANTILT_RELATIVE_CONTROL, sizeof(DWORD), &dwValue);
}
else
{
if (!m_spAMCameraControl)
return;
if (m_bMechanicalPanTilt)
{
if (yDirection != 0)
{
Tilt(yDirection);
MySleep(m_iMotorIntervalTimer);
Tilt(0);
}
}
else
{
long lValue(0), lFlags(0);
if (yDirection != 0)
{
HRESULT hResult = m_spAMCameraControl->Get(CameraControl_Tilt, &lValue, &lFlags);
if (S_OK == hResult)
{
lValue += yDirection;
if (yDirection > 0 && lValue > m_lDigitalTiltMax)
lValue = m_lDigitalTiltMax;
if (yDirection < 0 && lValue < m_lDigitalTiltMin)
lValue = m_lDigitalTiltMin;
hResult = m_spAMCameraControl->Set(CameraControl_Tilt, lValue, lFlags);
}
}
}
}
return;
}
void CWebcamController::Pan(int xDirection)
{
if (m_spAMCameraControl)
m_spAMCameraControl->Set(KSPROPERTY_CAMERACONTROL_PAN_RELATIVE, xDirection!=0 ? (xDirection < 0 ? -1 : 1) : 0, 0);
}
void CWebcamController::MovePan(int xDirection)
{
if (m_bUseLogitechMotionControl)
{
DWORD dwValue = MAKELONG(MAKEWORD(0, xDirection), MAKEWORD(0, 0));
SetProperty(XU_PERIPHERAL_CONTROL, XU_PERIPHERALCONTROL_PANTILT_RELATIVE_CONTROL, sizeof(DWORD), &dwValue);
}
else
{
if (!m_spAMCameraControl)
return;
if (m_bMechanicalPanTilt)
{
if (xDirection != 0)
{
Pan(xDirection);
MySleep(m_iMotorIntervalTimer);
Pan(0);
}
}
else
{
long lValue(0), lFlags(0);
if (xDirection != 0)
{
HRESULT hResult = m_spAMCameraControl->Get(CameraControl_Pan, &lValue, &lFlags);
if (S_OK == hResult)
{
lValue += xDirection;
if (xDirection > 0 && lValue > m_lDigitalPanMax)
lValue = m_lDigitalPanMax;
if (xDirection < 0 && lValue < m_lDigitalPanMin)
lValue = m_lDigitalPanMin;
hResult = m_spAMCameraControl->Set(CameraControl_Pan, lValue, lFlags);
}
}
}
}
return;
}
/*
* Tries to locate the node that carries H.264 XU extension and saves its ID.
*/
HRESULT CWebcamController::InitializeXUNodesArray(CComPtr<IKsControl> pKsControl)
{
// Get the IKsTopologyInfo interface
CComQIPtr<IKsTopologyInfo> pKsTopologyInfo = pKsControl;
if (!pKsTopologyInfo)
return E_NOINTERFACE;
// Retrieve the number of nodes in the filter
DWORD dwNumNodes = 0;
HRESULT hr = pKsTopologyInfo->get_NumNodes(&dwNumNodes);
if(FAILED(hr))
return hr;
// Go through all extension unit nodes and try to find the required XU node
hr = E_FAIL;
std::set<CString> setGuids;
for(unsigned int nodeId = 0; nodeId < dwNumNodes; nodeId++)
{
GUID guidNodeType;
hr = pKsTopologyInfo->get_NodeType(nodeId, &guidNodeType);
if(FAILED(hr))
continue;
// All Node types we have
// { 941C7AC0 - C559 - 11D0 - 8A2B - 00A0C9255AC1 } KSNODETYPE_DEV_SPECIFIC
// { DFF229E1 - F70F - 11D0 - B917 - 00A0C9223196 } KSNODETYPE_VIDEO_STREAMING
// { DFF229E5 - F70F - 11D0 - B917 - 00A0C9223196 } KSNODETYPE_VIDEO_PROCESSING
// { DFF229E6 - F70F - 11D0 - B917 - 00A0C9223196 } KSNODETYPE_VIDEO_CAMERA_TERMINAL
{
wchar_t szText[100];
StringFromGUID2(guidNodeType, szText, _countof(szText));
setGuids.emplace(szText);
}
if(!IsEqualGUID(guidNodeType, KSNODETYPE_DEV_SPECIFIC))
continue;
if(IsExtensionUnitSupported(pKsControl,LOGITECH_XU_DEVICE_INFORMATION,nodeId))
{
m_dwXUDeviceInformationNodeId = nodeId;
}
else if(IsExtensionUnitSupported(pKsControl,LOGITECH_XU_VIDEOPIPE_CONTROL,nodeId))
{
m_dwXUVideoPipeControlNodeId = nodeId;
}
else if(IsExtensionUnitSupported(pKsControl,LOGITECH_XU_TEST_DEBUG,nodeId))
{
m_dwXUTestDebugNodeId = nodeId;
}
else if(IsExtensionUnitSupported(pKsControl,LOGITECH_XU_PERIPHERAL_CONTROL,nodeId))
{
m_dwXUPeripheralControlNodeId = nodeId;
}
// else if (IsExtensionUnitSupported(pKsControl, PROPSETID_VIDCAP_CAMERACONTROL, nodeId))
// {
// // DWORD dwNodeId = nodeId;
// }
}
for (const auto &str : setGuids)
TRACE(__FUNCTION__ " - %ls\n", str.GetString());
return hr;
}
bool CWebcamController::IsExtensionUnitSupported(CComPtr<IKsControl> pKsControl,const GUID& guidExtension,unsigned int nodeId)
{
KSP_NODE extProp{};
extProp.Property.Set = guidExtension;
extProp.Property.Id = 0;
extProp.Property.Flags = KSPROPERTY_TYPE_SETSUPPORT | KSPROPERTY_TYPE_TOPOLOGY;
extProp.NodeId = nodeId;
extProp.Reserved = 0;
ULONG ulBytesReturned = 0;
HRESULT hr = pKsControl->KsProperty((PKSPROPERTY)&extProp, sizeof(extProp), NULL, 0, &ulBytesReturned);
return SUCCEEDED(hr);
}
void CWebcamController::ListDevices(CStringArray &aDevices)
{
aDevices.RemoveAll();
// Get a device list
CComPtr<ICreateDevEnum> pSysDevEnum;
HRESULT hr;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pSysDevEnum);
if (SUCCEEDED(hr))
{
//create a device class enumerator
CComPtr<IEnumMoniker> pIEnumMoniker;
HRESULT hResult = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pIEnumMoniker, 0);
if (SUCCEEDED(hr))
{
ULONG pFetched = NULL;
CComPtr<IMoniker> pImoniker;
while (S_OK == pIEnumMoniker->Next(1, &pImoniker, &pFetched))
{
CComPtr<IPropertyBag> pPropBag;
hResult = pImoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPropBag);
if (SUCCEEDED(hResult) && pPropBag!=nullptr)
{
CComVariant varCameraName, varDevicePath;
pPropBag->Read(L"FriendlyName", &varCameraName, 0);
pPropBag->Read(L"DevicePath", &varDevicePath, 0);
if (SUCCEEDED(varCameraName.ChangeType(VT_BSTR)) &&
SUCCEEDED(varDevicePath.ChangeType(VT_BSTR)))
{
CString strCameraName(varCameraName.bstrVal), strDevicePath(varDevicePath.bstrVal);
aDevices.Add(strCameraName + _T('\t') + strDevicePath);
}
}
// Set to null
pImoniker = nullptr;
}
}
}
}

View File

@@ -0,0 +1,75 @@
#pragma once
#include <Ks.h>
#include <KsProxy.h> // For IKsControl
#include <vidcap.h> // For IKsNodeControl
#include "ExtensionUnitDefines.h"
#define DEFAULT_MOTOR_INTERVAL_TIMER 70
/**
* CWebcamExtensionUnit encapsulates the USB extension unit capability of the device.
* (see https://msdn.microsoft.com/en-us/library/windows/hardware/ff568656(v=vs.85).aspx).
*/
class CWebcamController
{
public:
CWebcamController(void);
~CWebcamController(void);
HRESULT OpenDevice(BSTR bstrDevicePath, DWORD wVID, DWORD wPID);
void CloseDevice();
HRESULT IsPeripheralPropertySetSupported();
HRESULT GetProperty(LOGITECH_XU_PROPERTYSET lPropertySet, ULONG ulPropertyId, ULONG ulSize, VOID* pValue);
HRESULT SetProperty(LOGITECH_XU_PROPERTYSET lPropertySet, ULONG ulPropertyId, ULONG ulSize, VOID* pValue);
void GetVidPid(DWORD& vid, DWORD& pid);
int GetCurrentZoom();
int Zoom(int direction);
void MoveTilt(int yDirection);
void MovePan(int xDirection);
void Tilt(int yDirection);
void Pan(int xDirection);
void GotoHome();
void SavePreset(int iNum);
void GotoPreset(int iNum);
static void ListDevices(CStringArray &aDevices);
static const int NUM_PRESETS = 8;
bool UseLogitechMotionControl() const { return m_bUseLogitechMotionControl; }
void UseLogitechMotionControl(bool val) { m_bUseLogitechMotionControl = val; }
int GetMotorIntervalTimer() const { return m_iMotorIntervalTimer; }
void SetMotorIntervalTimer(int val) { m_iMotorIntervalTimer = val; }
private:
bool DeviceMatches(CComPtr<IMoniker> pMoniker, BSTR devicePath, DWORD wVID, DWORD wPID);
HRESULT OpenDevice(CComPtr<IMoniker> pMoniker);
bool ParseDevicePath(const wchar_t* devicePath, DWORD& vid, DWORD& pid);
HRESULT InitializeXUNodesArray(CComPtr<IKsControl> pKsControl);
bool IsExtensionUnitSupported(CComPtr<IKsControl> pKsControl, const GUID& guidExtension, unsigned int nodeId);
private:
CComPtr<IKsControl> m_spKsControl;
CComQIPtr<IAMCameraControl> m_spAMCameraControl;
CComQIPtr<IKsPropertySet> m_spsPropertySet;
CComQIPtr<ICameraControl> m_spCameraControl;
DWORD m_dwXUDeviceInformationNodeId;
DWORD m_dwXUVideoPipeControlNodeId;
DWORD m_dwXUTestDebugNodeId;
DWORD m_dwXUPeripheralControlNodeId;
DWORD m_dwVid;
DWORD m_dwPid;
bool m_bMechanicalPanTilt;
long m_lDigitalTiltMin, m_lDigitalTiltMax,
m_lDigitalPanMin, m_lDigitalPanMax;
bool m_bUseLogitechMotionControl;
int m_iMotorIntervalTimer;
};

View File

@@ -0,0 +1,120 @@
#pragma once
DEFINE_GUID(LOGITECH_XU_DEVICE_INFORMATION, 0x69678EE4, 0x410F, 0x40DB, 0xA8, 0x50, 0x74, 0x20, 0xD7, 0xD8, 0x24, 0x0E);
DEFINE_GUID(LOGITECH_XU_VIDEOPIPE_CONTROL, 0x49E40215, 0xF434, 0x47FE, 0xB1, 0x58, 0x0E, 0x88, 0x50, 0x23, 0xE5, 0x1B);
DEFINE_GUID(LOGITECH_XU_TEST_DEBUG, 0x1F5D4CA9, 0xDE11, 0x4487, 0x84, 0x0D, 0x50, 0x93, 0x3C, 0x8E, 0xC8, 0xD1);
DEFINE_GUID(LOGITECH_XU_PERIPHERAL_CONTROL, 0xFFE52D21, 0x8030, 0x4E2C, 0x82, 0xD9, 0xF5, 0x87, 0xD0, 0x05, 0x40, 0xBD);
enum //LOGITECH_XU_DEVICE_INFORMATION
{
XU_DEVICE_INFORMATION_UNDEFINED_CONTROL = 0x00,
XU_FIRMWARE_VERSION_CONTROL = 0x01,
XU_FIRMWARE_CRC_CONTROL = 0x02,
XU_EEPROM_VERSION_CONTROL = 0x03,
XU_SENSOR_INFORMATION_CONTROL = 0x04,
XU_PROCESSOR_INFORMATION_CONTROL = 0x05,
XU_USB_INFORMATION_CONTROL = 0x06,
XU_Reserved1 = 0x07,
XU_Reserved2 = 0x08,
XU_LENS_FOV_CONTROL = 0x09,
XU_SENSOR_DIMENSION_CONTROL = 0x0A,
XU_EXTENDED_FIRMWARE_VERSION_CONTROL = 0x0B,
};
enum //LOGITECH_XU_VIDEOPIPE_CONTROL
{
XU_VIDEO_UNDEFINED_CONTROL = 0x00,
XU_VIDEO_COLOR_BOOST_CONTROL = 0x01,
XU_VIDEO_NATIVE_MODE_FORCED_CONTROL = 0x02,
XU_VIDEO_NATIVE_MODE_AUTO_CONTROL = 0x03,
XU_VIDEO_RIGHTLIGHT_MODE_CONTROL = 0x04,
XU_VIDEO_RIGHTLIGHT_ZOI_CONTROL = 0x05,
XU_VIDEO_FW_ZOOM_CONTROL = 0x06,
XU_VIDEO_DUAL_ISO_ENABLE_CONTROL = 0x07,
XU_VIDEO_SENSOR_CROPPING_DIMENSION_CONTROL = 0x08,
XU_VIDEO_MJPEG_RESYNC_MARKER_CONTROL = 0x09,
XU_VIDEO_ADVANCE_DIGITAL_ZOOM_CONTROL = 0x0A,
XU_VIDEO_MJPEG_COMPRESS_RATIO_CONTROL = 0x0B,
XU_VIDEO_HDR_CONTROL = 0x0C,
};
enum //LOGITECH_XU_TEST_DEBUG
{
XU_TESTDEBUG_UNDEFINED_CONTROL = 0x00,
XU_TEST_REGISTER_ADDRESS_CONTROL = 0x01,
XU_TEST_REGISTER_ACCESS_CONTROL = 0x02,
XU_TEST_EEPROM_ADDRESS_CONTROL = 0x03,
XU_TEST_EEPROM_ACCESS_CONTROL = 0x04,
XU_TEST_SENSOR_ADDRESS_CONTROL = 0x05,
XU_TEST_SENSOR_ACCESS_CONTROL = 0x06,
XU_PERIPHERAL_MODE_CONTROL = 0x07,
XU_PERIPHERAL_OP_CONTROL = 0x08,
XU_PERIPHERAL_ACCESS_CONTROL = 0x09,
XU_TEST_TDE_MODE_CONTROL = 0x0A,
XU_TEST_GAIN_ACCESS_CONTROL = 0x0B,
XU_TEST_LOW_LIGHT_PRIORITY_CONTROL = 0x0C,
XU_TEST_COLOR_PROCESSING_DISABLE_CONTROL = 0x0D,
XU_TEST_PIXEL_DEFECT_CORRECTION_CONTROL = 0x0E,
XU_TEST_LENS_SHADING_COMPENSATION_CONTROL = 0x0F,
XU_TEST_GAMMA_CONTROL = 0x10,
XU_TEST_INTEGRATION_TIME_CONTROL = 0x11,
XU_TEST_RAW_DATA_BITS_PER_PIXEL_CONTROL = 0x12,
XU_TEST_ISP_ADDRESS_CONTROL = 0x13,
XU_TEST_ISP_ACCESS_CONTROL = 0x14,
XU_PERIPHERAL_ACCESS_EXT_CONTROL = 0x15,
XU_H264_FRAME_NO_CONTROL = 0x16,
};
// Seams that only 2 modes are defined for the PTZ Pro 2
// XU_PERIPHERALCONTROL_PANTILT_RELATIVE_CONTROL = pan tilt
// XU_PERIPHERALCONTROL_PANTILT_MODE_CONTROL = Preset and recall position
enum //LOGITECH_XU_PERIPHERAL_CONTROL
{
XU_PERIPHERAL_UNDEFINED_CONTROL = 0x00,
XU_PERIPHERALCONTROL_PANTILT_RELATIVE_CONTROL = 0x01, // pan tilt
XU_PERIPHERALCONTROL_PANTILT_MODE_CONTROL = 0x02, // Preset and recall position
XU_PERIPHERALCONTROL_MAXIMUM_RESOLUTION_SUPPORT_FOR_PANTILT_CONTROL = 0x03,
XU_PERIPHERALCONTROL_AF_MOTORCONTROL = 0x04,
XU_PERIPHERALCONTROL_AF_BLOB_CONTROL = 0x05,
XU_PERIPHERALCONTROL_AF_VCM_PARAMETERS = 0x06,
XU_PERIPHERALCONTROL_AF_STATUS = 0x07,
XU_PERIPHERALCONTROL_AF_THRESHOLDS = 0x08,
XU_PERIPHERALCONTROL_LED = 0x09,
XU_PERIPHERAL_CONTROL_PERIPHERAL_STATUS = 0x0A,
XU_PERIPHERAL_CONTROL_SPEAKER_VOLUME = 0x0B,
XU_PERIPHERAL_CONTROL_DEVICE_CODEC_STATUS = 0x0C,
XU_PERIPHERAL_CONTROL_SPEAKER = 0x0D,
XU_PERIPHERAL_CONTROL_MODE = 0x0E,
XU_AUDIO_LIBRARY_MODE_CONTROL = 0x0F,
XU_PERIPHERAL_MOTOR_STEPS_CONTROL = 0x10,
};
typedef enum
{
XU_DEVICE_INFORMATION,
XU_VIDEOPIPE_CONTROL,
XU_TEST_DEBUG,
XU_PERIPHERAL_CONTROL,
} LOGITECH_XU_PROPERTYSET;
/**
* Preset enumerations
*/
enum
{
RESET_NOACTION = 0,
SET_PRESET = 1,
GOTO_PRESET = 2,
GOTOHOME = 3
};
// enum
// {
// RESET_NOACTION = 0,
// RESET_PAN = 1,
// RESET_TILT = 2,
// };

BIN
PTZControl/PTZControl.aps Normal file

Binary file not shown.

169
PTZControl/PTZControl.cpp Normal file
View File

@@ -0,0 +1,169 @@
// PTZControl.cpp : Defines the class behaviors for the application.
//
#include "pch.h"
#include "framework.h"
#include "PTZControl.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
/////////////////////////////////////////////////////////////////////////////
// CAgvipCommandLineInfo
// The program must be started with the parameters /conn:<connectionfile>
// and /user:<userid>. For the Debug mode special Options are prepared.
class CPTZControlCommandLineInfo : public CCommandLineInfo
{
public:
// Construction
CPTZControlCommandLineInfo()
: m_bNoReset(false)
, m_bNoGuard(false)
, m_bShowDevices(false)
{
}
// Overwritten virtual
virtual void ParseParam(const TCHAR* pszParam,BOOL bFlag,BOOL bLast);
#ifdef _UNICODE
virtual void ParseParam(const char* pszParam, BOOL bFlag, BOOL bLast);
#endif
public:
// Data
CString m_strDevName; // Device name from the command line to search for
bool m_bNoReset; // No Reset of web cam
bool m_bNoGuard; // Prevent a guard thread
bool m_bShowDevices; // SHow message box with devicenames on open.
// Currently not used (may be used if we ant yes/no/undefined)
enum class Mode
{
False = 0,
True = 1,
Undefined = -1,
};
};
#ifdef _UNICODE
void CPTZControlCommandLineInfo::ParseParam(const TCHAR* pszParam,BOOL bFlag,BOOL bLast)
{
ParseParam(CT2CA(pszParam),bFlag,bLast);
}
#endif
void CPTZControlCommandLineInfo::ParseParam(const char* pszParam,BOOL bFlag,BOOL bLast)
{
if (bFlag)
{
if (_strnicmp(pszParam,"device:",7)==0)
{
// Get address set name
pszParam += 7;
m_strDevName = pszParam;
::PathUnquoteSpaces(CStrBuf(m_strDevName,0));
}
else if (_stricmp(pszParam, "noreset")==0)
{
m_bNoReset = true;
}
else if (_stricmp(pszParam, "noguard") == 0)
{
m_bNoGuard = true;
}
else if (_stricmp(pszParam, "showdevices") == 0)
{
m_bShowDevices = true;
}
else
ParseParamFlag(pszParam);
}
else
ParseParamNotFlag(pszParam);
// Standard implementation
ParseLast(bLast);
}
//////////////////////////////////////////////////////////////////////////
// CPTZControlApp
BEGIN_MESSAGE_MAP(CPTZControlApp, CWinApp)
ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////////
// CPTZControlApp construction
CPTZControlApp::CPTZControlApp()
: m_bNoReset(false)
, m_bNoGuard(false)
, m_bShowDevices(false)
{
}
// The one and only CPTZControlApp object
CPTZControlApp theApp;
//////////////////////////////////////////////////////////////////////////
// CPTZControlApp initialization
BOOL CPTZControlApp::InitInstance()
{
CWinApp::InitInstance();
// Activate "Windows Native" visual manager for enabling themes in MFC controls
CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
// Taken from Logitech
// PTZDemo\ConferenceCamPTZDemoDlg.cpp
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
//-------------Registry-------------------------------------------------
SetRegistryKey(_T("MRi-Software"));
//-------------Commandline parsing--------------------------------------
// Parse command line for standard shell commands, DDE, file open
CPTZControlCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
m_strDevName = cmdInfo.m_strDevName;
// Registry is overruled command line
m_bNoReset = GetProfileInt(REG_OPTIONS,REG_NORESET,FALSE)!=0 || cmdInfo.m_bNoReset;
m_bNoGuard = GetProfileInt(REG_OPTIONS,REG_NOGUARD,FALSE)!=0 || cmdInfo.m_bNoGuard;
m_bShowDevices = cmdInfo.m_bShowDevices;
//-------------Main ----------------------------------------------------
// Create the Dialog
m_pDlg = new CPTZControlDlg();
if (m_pDlg->Create(CPTZControlDlg::IDD))
m_pMainWnd = m_pDlg;
else
return FALSE;
// Succeeded
return TRUE;
}
//////////////////////////////////////////////////////////////////////////
int CPTZControlApp::ExitInstance()
{
#if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS)
ControlBarCleanUp();
#endif
return __super::ExitInstance();
}

76
PTZControl/PTZControl.h Normal file
View File

@@ -0,0 +1,76 @@
// PTZControl.h : main header file for the PROJECT_NAME application
//
#pragma once
#include "PTZControlDlg.h"
#ifndef __AFXWIN_H__
#error "include 'pch.h' before including this file for PCH"
#endif
#include "resource.h" // main symbols
//////////////////////////////////////////////////////////////////////////
#define REG_WINDOW _T("Window")
#define REG_WINDOW_POSX _T("X")
#define REG_WINDOW_POSY _T("Y")
#define REG_TOOLTIP _T("Tooltip%d")
#define REG_DEVICE _T("Device")
#define REG_USELOGOTECHMOTIONCONTROL _T("LogitechMotionControl")
#define REG_MOTORINTERVALTIMER _T("MotorIntervalTimer")
#define REG_DEVICENAME _T("DeviceName")
#define REG_OPTIONS _T("Options")
#define REG_NORESET _T("NoReset")
#define REG_NOGUARD _T("NoGuard")
#define DEFAULT_DEVICE_NAME_1 _T("PTZ Pro 2")
#define DEFAULT_DEVICE_NAME_2 _T("Logi Rally")
#define TIMER_FOCUS_CHECK 4711
#define TIMER_AUTO_REPEAT 4712
#define TIMER_CLEAR_MEMORY 4713
#define FOCUS_CHECK_DELAY 250 // After 250msec we move the focus away from a button.
#define AUTO_REPEAT_DELAY 50 // Autorepeat is on the fastest possible delay of 50msec
#define AUTO_REPEAT_INITIAL_DELAY 500 // after 1/2 second we start autorepeat
#define CLEAR_MEMORY_DELAY 5000 // After 5 seconds clear the memory
#define COLOR_GREEN RGB(0,240,0)
#define COLOR_RED RGB(240,0,0)
#define COLOR_ORANGE RGB(255,140,0)
//////////////////////////////////////////////////////////////////////////
// CPTZControlApp:
// See PTZControl.cpp for the implementation of this class
//
class CPTZControlApp : public CWinApp
{
public:
CPTZControlApp();
// Overrides
public:
virtual BOOL InitInstance();
// Implementation
DECLARE_MESSAGE_MAP()
virtual int ExitInstance();
public:
// command line flags
CString m_strDevName; // Device name from the command line to search for
bool m_bNoReset; // No Reset of web cam
bool m_bNoGuard; // Prevent a guard thread
bool m_bShowDevices;
private:
CPTZControlDlg* m_pDlg;
};
extern CPTZControlApp theApp;

BIN
PTZControl/PTZControl.rc Normal file

Binary file not shown.

31
PTZControl/PTZControl.sln Normal file
View File

@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30804.86
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PTZControl", "PTZControl.vcxproj", "{2E2437DA-35E2-4D0D-B1DF-26E1DFEE1FB9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2E2437DA-35E2-4D0D-B1DF-26E1DFEE1FB9}.Debug|x64.ActiveCfg = Debug|x64
{2E2437DA-35E2-4D0D-B1DF-26E1DFEE1FB9}.Debug|x64.Build.0 = Debug|x64
{2E2437DA-35E2-4D0D-B1DF-26E1DFEE1FB9}.Debug|x86.ActiveCfg = Debug|Win32
{2E2437DA-35E2-4D0D-B1DF-26E1DFEE1FB9}.Debug|x86.Build.0 = Debug|Win32
{2E2437DA-35E2-4D0D-B1DF-26E1DFEE1FB9}.Release|x64.ActiveCfg = Release|x64
{2E2437DA-35E2-4D0D-B1DF-26E1DFEE1FB9}.Release|x64.Build.0 = Release|x64
{2E2437DA-35E2-4D0D-B1DF-26E1DFEE1FB9}.Release|x86.ActiveCfg = Release|Win32
{2E2437DA-35E2-4D0D-B1DF-26E1DFEE1FB9}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {750BD145-2459-46BB-A622-E3902280AE01}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,224 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{2E2437DA-35E2-4D0D-B1DF-26E1DFEE1FB9}</ProjectGuid>
<Keyword>MFCProj</Keyword>
<RootNamespace>PTZControl</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>Static</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>Static</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>Static</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>Static</UseOfMfc>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
</Link>
<Midl>
<MkTypLibCompatible>false</MkTypLibCompatible>
<ValidateAllParameters>true</ValidateAllParameters>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</Midl>
<ResourceCompile>
<Culture>0x0409</Culture>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
</Link>
<Midl>
<MkTypLibCompatible>false</MkTypLibCompatible>
<ValidateAllParameters>true</ValidateAllParameters>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</Midl>
<ResourceCompile>
<Culture>0x0409</Culture>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<Midl>
<MkTypLibCompatible>false</MkTypLibCompatible>
<ValidateAllParameters>true</ValidateAllParameters>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</Midl>
<ResourceCompile>
<Culture>0x0409</Culture>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<Midl>
<MkTypLibCompatible>false</MkTypLibCompatible>
<ValidateAllParameters>true</ValidateAllParameters>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</Midl>
<ResourceCompile>
<Culture>0x0409</Culture>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="ExtensionUnit.h" />
<ClInclude Include="ExtensionUnitDefines.h" />
<ClInclude Include="framework.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="PTZControl.h" />
<ClInclude Include="PTZControlDlg.h" />
<ClInclude Include="Resource.h" />
<ClInclude Include="SettingsDlg.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="ExtensionUnit.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="PTZControl.cpp" />
<ClCompile Include="PTZControlDlg.cpp" />
<ClCompile Include="SettingsDlg.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="PTZControl.rc" />
</ItemGroup>
<ItemGroup>
<None Include="res\PTZControl.rc2" />
</ItemGroup>
<ItemGroup>
<Image Include="res\CameraControl.bmp" />
<Image Include="res\PTZControl.ico" />
</ItemGroup>
<ItemGroup>
<Text Include="Readme.txt" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,829 @@
// PTZControlDlg.cpp : implementation file
//
#include "pch.h"
#include "framework.h"
#include "PTZControl.h"
#include "PTZControlDlg.h"
#include "SettingsDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////////////////////////
#define ON_BN_UNPUSHED(id, memberFxn) \
ON_CONTROL(BN_UNPUSHED, id, memberFxn)
//////////////////////////////////////////////////////////////////////////////////////////
// CPTZButton
IMPLEMENT_DYNAMIC(CPTZButton,CMFCButton)
CPTZButton::CPTZButton()
: m_bAutoRepeat(false)
, m_uiSent(0)
{
}
void CPTZButton::PreSubclassWindow()
{
__super::PreSubclassWindow();
SetTooltip(_T(""));
// Setting delay time doesn't seam to work.
GetToolTipCtrl().SetDelayTime(0);
}
void CPTZButton::OnDrawBorder(CDC* pDC, CRect& rectClient, UINT uiState)
{
__super::OnDrawBorder(pDC,rectClient,uiState);
// Give the button our button face. But only when the mouse isn't over
if (m_bWinXPTheme && m_clrFace!=COLORREF(-1)/* && !m_bHover && !m_bHighlighted*/)
pDC->FillSolidRect(rectClient, m_clrFace);
}
void CPTZButton::OnDrawFocusRect(CDC* pDC, const CRect& rectClient)
{
UNUSED_ALWAYS(pDC); UNUSED_ALWAYS(rectClient);
}
void CPTZButton::OnLButtonDown(UINT nFlags, CPoint point)
{
if (m_bAutoRepeat)
{
SetTimer(TIMER_AUTO_REPEAT, AUTO_REPEAT_INITIAL_DELAY, NULL);
m_uiSent = 0;
}
__super::OnLButtonDown(nFlags, point);
}
void CPTZButton::OnLButtonUp(UINT nFlags, CPoint point)
{
if (m_bAutoRepeat)
{
KillTimer(TIMER_AUTO_REPEAT);
if (GetCapture() != NULL)
{
// If we never sent a message we do it once.
if (m_uiSent==0 && (GetState() & BST_PUSHED) != 0)
GetParent()->SendMessage(WM_COMMAND, MAKELONG(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
else
GetParent()->SendMessage(WM_COMMAND, MAKELONG(GetDlgCtrlID(), BN_UNPUSHED), (LPARAM)m_hWnd);
// release capture
ReleaseCapture();
}
}
else
// Never call the default in auto repeat
__super::OnLButtonUp(nFlags, point);
}
void CPTZButton::OnTimer(UINT_PTR nIDEvent)
{
if (nIDEvent==TIMER_AUTO_REPEAT)
{
if (m_bAutoRepeat)
{
if ((GetState() & BST_PUSHED) == 0)
return;
++m_uiSent;
SetTimer(TIMER_AUTO_REPEAT, AUTO_REPEAT_DELAY, NULL);
GetParent()->SendMessage(WM_COMMAND, MAKELONG(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
}
}
__super::OnTimer(nIDEvent);
}
//////////////////////////////////////////////////////////////////////////////////////////
BOOL AdjustVisibleWindowRect(LPRECT lpRect, HWND hWndParent=NULL)
{
RECT rcOrg(*lpRect);
RECT rcBase;
if (hWndParent)
// Any parent given?
::GetClientRect(hWndParent,&rcBase);
else
{
::MONITORINFO mi;
mi.cbSize = sizeof(mi);
if (!AfxGetMainWnd())
// If we have no main window we just try to use the main screen point 0,0
::GetMonitorInfo(::MonitorFromPoint(CPoint(0,0), MONITOR_DEFAULTTONEAREST), &mi);
else
// Get the main window monitor
::GetMonitorInfo(::MonitorFromWindow(AfxGetMainWnd()->m_hWnd, MONITOR_DEFAULTTONEAREST), &mi);
rcBase = mi.rcWork;
}
// To large?
if (lpRect->bottom-lpRect->top>rcBase.bottom-rcBase.top)
lpRect->bottom -= (lpRect->bottom-lpRect->top)-(rcBase.bottom-rcBase.top);
if (lpRect->right-lpRect->left>rcBase.right-rcBase.left)
lpRect->right -= (lpRect->right-lpRect->left)-(rcBase.right-rcBase.left);
// Check if rect is visible
if (lpRect->bottom>rcBase.bottom)
::OffsetRect(lpRect,0,rcBase.bottom-lpRect->bottom);
if (lpRect->top<rcBase.top)
::OffsetRect(lpRect,0,rcBase.top-lpRect->top);
if (lpRect->right>rcBase.right)
::OffsetRect(lpRect,rcBase.right-lpRect->right,0);
if (lpRect->left<rcBase.left)
::OffsetRect(lpRect,rcBase.left-lpRect->left,0);
// Check if coords changes
return !EqualRect(lpRect,&rcOrg);
}
//////////////////////////////////////////////////////////////////////////////////////////
// CPTZControlDlg dialog
CPTZControlDlg::CPTZControlDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_PTZCONTROL_DIALOG, pParent)
, m_hAccel(NULL)
, m_iCurrentWebCam(0)
, m_iNumWebCams(0)
, m_evTerminating(FALSE,TRUE)
, m_pGuardThread(nullptr)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_hAccel = ::LoadAccelerators(AfxFindResourceHandle(IDR_ACCELERATOR, RT_ACCELERATOR), MAKEINTRESOURCE(IDR_ACCELERATOR));
}
CPTZControlDlg::~CPTZControlDlg()
{
for (auto &webcam : m_aWebCams)
webcam.CloseDevice();
}
void CPTZControlDlg::PostNcDestroy()
{
__super::PostNcDestroy();
// Cleanup the guard thread.
m_evTerminating.SetEvent();
if (m_pGuardThread)
::WaitForSingleObject(m_pGuardThread->m_hThread,INFINITE);
m_pGuardThread = nullptr;
// Finally delete the application.
delete this;
}
BOOL CPTZControlDlg::OnCommand(WPARAM wParam, LPARAM lParam)
{
return __super::OnCommand(wParam,lParam);
}
BOOL CPTZControlDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message>=WM_KEYFIRST && pMsg->message<=WM_KEYLAST)
{
if (m_hAccel)
{
if (::TranslateAccelerator(m_hWnd, m_hAccel, pMsg))
return TRUE;
}
}
return __super::PreTranslateMessage(pMsg);
}
void CPTZControlDlg::DoDataExchange(CDataExchange* pDX)
{
__super::DoDataExchange(pDX);
DDX_Control(pDX, IDC_BT_ZOOM_IN, m_btZoomIn);
DDX_Control(pDX, IDC_BT_ZOOM_OUT, m_btZoomOut);
DDX_Control(pDX, IDC_BT_UP, m_btUp);
DDX_Control(pDX, IDC_BT_DOWN, m_btDown);
DDX_Control(pDX, IDC_BT_HOME, m_btHome);
DDX_Control(pDX, IDC_BT_LEFT, m_btLeft);
DDX_Control(pDX, IDC_BT_RIGHT, m_btRight);
DDX_Control(pDX, IDC_BT_MEMORY, m_btMemory);
DDX_Control(pDX, IDC_BT_PRESET1, m_btPreset[0]);
DDX_Control(pDX, IDC_BT_PRESET2, m_btPreset[1]);
DDX_Control(pDX, IDC_BT_PRESET3, m_btPreset[2]);
DDX_Control(pDX, IDC_BT_PRESET4, m_btPreset[3]);
DDX_Control(pDX, IDC_BT_PRESET5, m_btPreset[4]);
DDX_Control(pDX, IDC_BT_PRESET6, m_btPreset[5]);
DDX_Control(pDX, IDC_BT_PRESET7, m_btPreset[6]);
DDX_Control(pDX, IDC_BT_PRESET8, m_btPreset[7]);
DDX_Control(pDX, IDC_BT_EXIT, m_btExit);
DDX_Control(pDX, IDC_BT_SETTINGS, m_btSettings);
DDX_Control(pDX, IDC_BT_WEBCAM1, m_btWebCam[0]);
DDX_Control(pDX, IDC_BT_WEBCAM2, m_btWebCam[1]);
}
BEGIN_MESSAGE_MAP(CPTZControlDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_CLOSE()
ON_WM_NCHITTEST()
ON_BN_CLICKED(IDC_BT_EXIT, &CPTZControlDlg::OnBtExit)
ON_WM_SETFOCUS()
ON_BN_CLICKED(IDC_BT_MEMORY, &CPTZControlDlg::OnBtMemory)
ON_COMMAND_EX(IDC_BT_WEBCAM1, &CPTZControlDlg::OnBtWebCam)
ON_COMMAND_EX(IDC_BT_WEBCAM2, &CPTZControlDlg::OnBtWebCam)
ON_COMMAND_EX(IDC_BT_PRESET1, &CPTZControlDlg::OnBtPreset)
ON_COMMAND_EX(IDC_BT_PRESET2, &CPTZControlDlg::OnBtPreset)
ON_COMMAND_EX(IDC_BT_PRESET3, &CPTZControlDlg::OnBtPreset)
ON_COMMAND_EX(IDC_BT_PRESET4, &CPTZControlDlg::OnBtPreset)
ON_COMMAND_EX(IDC_BT_PRESET5, &CPTZControlDlg::OnBtPreset)
ON_COMMAND_EX(IDC_BT_PRESET6, &CPTZControlDlg::OnBtPreset)
ON_COMMAND_EX(IDC_BT_PRESET7, &CPTZControlDlg::OnBtPreset)
ON_COMMAND_EX(IDC_BT_PRESET8, &CPTZControlDlg::OnBtPreset)
ON_BN_CLICKED(IDC_BT_ZOOM_IN, &CPTZControlDlg::OnBtZoomIn)
ON_BN_CLICKED(IDC_BT_ZOOM_OUT, &CPTZControlDlg::OnBtZoomOut)
ON_BN_CLICKED(IDC_BT_UP, &CPTZControlDlg::OnBtUp)
ON_BN_CLICKED(IDC_BT_DOWN, &CPTZControlDlg::OnBtDown)
ON_BN_CLICKED(IDC_BT_LEFT, &CPTZControlDlg::OnBtLeft)
ON_BN_CLICKED(IDC_BT_HOME, &CPTZControlDlg::OnBtHome)
ON_BN_CLICKED(IDC_BT_RIGHT, &CPTZControlDlg::OnBtRight)
ON_BN_CLICKED(IDC_BT_SETTINGS, &CPTZControlDlg::OnBtSettings)
ON_BN_UNPUSHED(IDC_BT_UP, &CPTZControlDlg::OnBtUnpushed)
ON_BN_UNPUSHED(IDC_BT_DOWN, &CPTZControlDlg::OnBtUnpushed)
ON_BN_UNPUSHED(IDC_BT_LEFT, &CPTZControlDlg::OnBtUnpushed)
ON_BN_UNPUSHED(IDC_BT_RIGHT, &CPTZControlDlg::OnBtUnpushed)
ON_WM_TIMER()
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////////////////////////
// CPTZControlDlg message handlers
void CPTZControlDlg::ResetAllColors()
{
for (CWnd* pWnd = GetWindow(GW_CHILD); pWnd; pWnd = pWnd->GetWindow(GW_HWNDNEXT))
{
auto *pButton = DYNAMIC_DOWNCAST(CPTZButton, pWnd);
// Don't reset color for web cam button
bool bIsWebCamBtn = false;
for (auto &btn : m_btWebCam)
bIsWebCamBtn |= pButton==&btn;
// Reset color for all other buttons
if (pButton && !bIsWebCamBtn)
pButton->SetFaceColor(COLORREF(-1), TRUE);
}
}
void CPTZControlDlg::ResetMemButton()
{
// Clear the mem button
KillTimer(TIMER_CLEAR_MEMORY);
m_btMemory.SetCheck(0);
m_btMemory.SetFaceColor(COLORREF(-1));
}
CWebcamController& CPTZControlDlg::GetCurrentWebCam()
{
return m_aWebCams[m_iCurrentWebCam];
}
void CPTZControlDlg::SetActiveCam(int iCam)
{
if (iCam >= 0 && iCam < m_iNumWebCams)
{
// Clear mem button
ResetMemButton();
// Save the colors of the current buttons and set the old ones
for (CWnd* pWnd = GetWindow(GW_CHILD); pWnd; pWnd = pWnd->GetWindow(GW_HWNDNEXT))
{
auto* pButton = DYNAMIC_DOWNCAST(CPTZButton, pWnd);
if (pButton)
{
// Save the color of the current buttons for the current web cam and get
// the saved color from the map we have for the new cam.
auto nId = pButton->GetDlgCtrlID();
m_aMapBtnColors[m_iCurrentWebCam][nId] = pButton->GetFaceColor();
auto it = m_aMapBtnColors[iCam].find(nId);
if (it!=m_aMapBtnColors[iCam].end())
pButton->SetFaceColor(it->second);
}
}
// Set the tooltips
for (int i=0; i<CWebcamController::NUM_PRESETS; ++i)
m_btPreset[i].SetTooltip(m_strTooltips[iCam][i]);
// Set the new webcam
m_iCurrentWebCam = iCam;
auto Enable = [&](CPTZButton &btn, bool bActive)
{
btn.SetCheck(bActive);
btn.SetFaceColor(bActive ? COLOR_ORANGE : -1, TRUE);
};
int iWebCam = 0;
for (auto &btn : m_btWebCam)
Enable(btn,m_iCurrentWebCam==iWebCam++);
}
}
//////////////////////////////////////////////////////////////////////////
// It seams that in some cases a camera my block.
// This thread should help that the blocking thread is detected. and the
// application terminates.
UINT AFX_CDECL CPTZControlDlg::GuardThread(LPVOID p)
{
auto *pWnd = static_cast<CPTZControlDlg*>(p);
// This thread end when the application exists.
// For ever all 2000 seconds check if the application still runs and accepts messages.
for (;;)
{
// Check if we have an event, wait for 1 sec
CSingleLock lock(&pWnd->m_evTerminating,FALSE);
if (lock.Lock(1000))
// Event is set.
return 0;
DWORD dwResult = 0;
// Check if the application is blocking
if (::SendMessageTimeout(pWnd->GetSafeHwnd(), WM_NULL, 0, 0, SMTO_ABORTIFHUNG | SMTO_NORMAL, 1000, &dwResult)==0)
{
// Exit the current process
::ExitProcess(10);
}
}
}
BOOL CPTZControlDlg::OnInitDialog()
{
__super::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// Load the bitmap
{
CMFCToolBarImages images;
images.SetImageSize(CSize(16, 16));
images.Load(IDB_BUTTONS);
int iImage = 0;
CPTZButton* apButtons[] =
{
&m_btDown,
&m_btLeft,
&m_btRight,
&m_btUp,
&m_btHome,
&m_btZoomIn,
&m_btZoomOut,
&m_btMemory,
&m_btPreset[0],
&m_btPreset[1],
&m_btPreset[2],
&m_btPreset[3],
&m_btPreset[4],
&m_btPreset[5],
&m_btPreset[6],
&m_btPreset[7],
&m_btExit,
&m_btSettings,
&m_btWebCam[0],
&m_btWebCam[1],
};
for (auto* pBtn : apButtons)
{
HICON hIcon = images.ExtractIcon(iImage++);
pBtn->SetImage(hIcon);
// we have a graphic now, we skip the text
pBtn->SetWindowText(_T(""));
}
}
// Set auto repeat buttons
m_btLeft.SetAutoRepeat(true);
m_btRight.SetAutoRepeat(true);
m_btDown.SetAutoRepeat(true);
m_btUp.SetAutoRepeat(true);
m_btZoomIn.SetAutoRepeat(true);
m_btZoomOut.SetAutoRepeat(true);
// This is a check box style
m_btMemory.SetCheckStyle();
for (auto &btn : m_btWebCam)
btn.SetCheckStyle();
// First Center
CenterWindow();
// Adjust the window
CRect rect;
GetWindowRect(rect);
CPoint pt = rect.TopLeft();
rect.OffsetRect(-pt);
pt.x = theApp.GetProfileInt(REG_WINDOW,REG_WINDOW_POSX,pt.x);
pt.y = theApp.GetProfileInt(REG_WINDOW,REG_WINDOW_POSY,pt.y);
rect.OffsetRect(pt);
AdjustVisibleWindowRect(rect);
// Move it
SetWindowPos(&CWnd::wndTopMost, rect.left, rect.top, 0, 0, SWP_NOSIZE);
// Try to find the Device list
CStringArray aDevices;
CWebcamController::ListDevices(aDevices);
auto OpenWebCam = [](CWebcamController& webCam, CString strDevToken)->bool
{
HRESULT hr = webCam.OpenDevice(CComBSTR(strDevToken), 0, 0);
if (FAILED(hr))
{
AfxMessageBox(IDP_ERR_OPENFAILED);
return false;
}
// Load the default setting
webCam.UseLogitechMotionControl(theApp.GetProfileInt(REG_DEVICE, REG_USELOGOTECHMOTIONCONTROL, FALSE) != 0);
webCam.SetMotorIntervalTimer(theApp.GetProfileInt(REG_DEVICE, REG_MOTORINTERVALTIMER, DEFAULT_MOTOR_INTERVAL_TIMER));
return true;
};
// Find the devices to search for. We have some default devices if no other is set in
// the registry o on the command line.
CStringArray aStrCameraNameToSearch;
aStrCameraNameToSearch.Add(DEFAULT_DEVICE_NAME_1);
aStrCameraNameToSearch.Add(DEFAULT_DEVICE_NAME_2);
CString strCameraNameToSearch = theApp.GetProfileString(REG_DEVICE,REG_DEVICENAME,_T(""));
if (!strCameraNameToSearch.IsEmpty())
aStrCameraNameToSearch.Add(strCameraNameToSearch);
if (!theApp.m_strDevName.IsEmpty())
aStrCameraNameToSearch.Add(theApp.m_strDevName);
// Search for the PTZ PRO 2
CString strDevToken, strCameras;
for (int i = 0; i<aDevices.GetCount() && m_iNumWebCams<NUM_MAX_WEBCAMS; ++i)
{
CString strDevice = aDevices[i], strCameraName, strCameraDevice;
int iPos = strDevice.Find(_T('\t'));
if (iPos != -1)
{
// Get name and device token
strCameraName = strDevice.Left(iPos);
strDevToken = strDevice.Mid(iPos + 1);
// Build list of names found
if (!strCameras.IsEmpty())
strCameras += _T("\r\n");
strCameras += strCameraName;
// Check if the name matches
for (int j=0; j<aStrCameraNameToSearch.GetCount(); ++j)
{
// Check if we have a asterisk. Or a partial name match.
if (aStrCameraNameToSearch[j]==_T("*") || strCameraName.Find(aStrCameraNameToSearch[j]) != -1)
{
if (OpenWebCam(m_aWebCams[m_iNumWebCams], strDevToken))
++m_iNumWebCams;
}
}
}
}
// On SHIFT and CTRL key down we show all found camera device names.
if (theApp.m_bShowDevices || (::GetAsyncKeyState(VK_SHIFT) & 0x8000) && (::GetAsyncKeyState(VK_CONTROL) & 0x8000))
{
CString strMsg(MAKEINTRESOURCE(IDP_TXT_CAMERAS)), strText;
strText.FormatMessage(strMsg, strCameras.GetString());
AfxMessageBox(strText);
}
// Check how many web cams we found
if (m_iNumWebCams==0)
{
// If we have no cam, show message
AfxMessageBox(IDP_ERR_NO_CAMERA, MB_ICONERROR);
}
// Only 1 or none, we don't need the camera selection buttons
if (m_iNumWebCams<=1)
{
// Sow the web cam buttons only if we have 2 cams
for (auto &btn : m_btWebCam)
btn.ShowWindow(SW_HIDE);
}
for (int i = 0; i < CWebcamController::NUM_PRESETS; ++i)
{
for (int j = 0; j < CPTZControlDlg::NUM_MAX_WEBCAMS; ++j)
{
CString str;
str.Format(REG_TOOLTIP, i + 1 + j*100);
m_strTooltips[j][i] = theApp.GetProfileString(REG_WINDOW, str);
}
}
EnableToolTips(TRUE);
// Start a guard thread that takes care about a blocking app.
if (!theApp.m_bNoGuard)
m_pGuardThread = AfxBeginThread(&GuardThread,this);
// Set a time to move the focus to the parent window
SetTimer(TIMER_FOCUS_CHECK,FOCUS_CHECK_DELAY,nullptr);
SetFocus();
// Move all cams to home position. And WebCam 0 will be the active one.
if (theApp.m_bNoReset)
{
// Activate camera 0.
if (m_iNumWebCams>0)
SetActiveCam(0);
}
else
{
// Reset the cameras to home position. and leave the first camera
// (index 0) the active one ((loop backwards).
for (int i = m_iNumWebCams; i > 0; --i)
{
SetActiveCam(i - 1);
OnBtHome();
}
}
return FALSE;
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CPTZControlDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
__super::OnPaint();
}
}
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CPTZControlDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
LRESULT CPTZControlDlg::OnNcHitTest(CPoint point)
{
// Allow drag & drop
LRESULT lResult = __super::OnNcHitTest(point);
if (lResult == HTCLIENT)
lResult = HTCAPTION;
return lResult;
}
void CPTZControlDlg::OnClose()
{
CRect rect;
GetWindowRect(rect);
theApp.WriteProfileInt(REG_WINDOW,REG_WINDOW_POSX,rect.left);
theApp.WriteProfileInt(REG_WINDOW,REG_WINDOW_POSY,rect.top);
DestroyWindow();
}
void CPTZControlDlg::OnBtExit()
{
PostMessage(WM_CLOSE);
}
void CPTZControlDlg::OnOK()
{
// Ignore
}
void CPTZControlDlg::OnCancel()
{
// Ignore
}
void CPTZControlDlg::OnBtMemory()
{
ResetAllColors();
bool bCheck = !m_btMemory.GetCheck();
m_btMemory.SetCheck(bCheck);
if (bCheck)
{
// Remember the mem button, but clear it after some delay.
m_btMemory.SetFaceColor(COLOR_RED, TRUE);
SetTimer(TIMER_CLEAR_MEMORY,CLEAR_MEMORY_DELAY,nullptr);
}
else
m_btMemory.SetFaceColor(COLORREF(-1),TRUE);
}
BEGIN_MESSAGE_MAP(CPTZButton, CMFCButton)
ON_WM_LBUTTONDOWN()
ON_WM_TIMER()
ON_WM_LBUTTONUP()
END_MESSAGE_MAP()
BOOL CPTZControlDlg::OnBtPreset(UINT nId)
{
UINT uiPreset = 0;
while (uiPreset<CWebcamController::NUM_PRESETS)
{
if (static_cast<UINT>(m_btPreset[uiPreset].GetDlgCtrlID())==nId)
break;
++uiPreset;
}
if (uiPreset<CWebcamController::NUM_PRESETS)
{
ResetAllColors();
bool bStore = m_btMemory.GetCheck();
if (bStore)
{
// Save as new preset
GetCurrentWebCam().SavePreset(uiPreset);
ResetMemButton();
}
else
GetCurrentWebCam().GotoPreset(uiPreset);
// Set color
STATIC_DOWNCAST(CPTZButton,GetDlgItem(nId))->SetFaceColor(COLOR_GREEN,TRUE);
}
return TRUE;
}
BOOL CPTZControlDlg::OnBtWebCam(UINT nId)
{
SetActiveCam(nId==IDC_BT_WEBCAM1 ? 0 : 1);
return 1;
}
void CPTZControlDlg::OnBtHome()
{
ResetAllColors();
GetCurrentWebCam().GotoHome();
m_btHome.SetFaceColor(COLOR_GREEN,TRUE);
}
void CPTZControlDlg::OnBtZoomIn()
{
ResetAllColors();
GetCurrentWebCam().Zoom(1);
}
void CPTZControlDlg::OnBtZoomOut()
{
ResetAllColors();
GetCurrentWebCam().Zoom(-1);
}
void CPTZControlDlg::OnBtDown()
{
ResetAllColors();
if (m_btDown.InAutoRepeat())
GetCurrentWebCam().Tilt(-1);
else
GetCurrentWebCam().MoveTilt(-1);
}
void CPTZControlDlg::OnBtUp()
{
ResetAllColors();
if (m_btUp.InAutoRepeat())
GetCurrentWebCam().Tilt(1);
else
GetCurrentWebCam().MoveTilt(1);
}
void CPTZControlDlg::OnBtLeft()
{
ResetAllColors();
if (m_btLeft.InAutoRepeat())
GetCurrentWebCam().Pan(-1);
else
GetCurrentWebCam().MovePan(-1);
}
void CPTZControlDlg::OnBtRight()
{
ResetAllColors();
if (m_btRight.InAutoRepeat())
GetCurrentWebCam().Pan(1);
else
GetCurrentWebCam().MovePan(1);
}
void CPTZControlDlg::OnSetFocus(CWnd* pOldWnd)
{
// Do nothing. Never set the focus to a child.
UNUSED_ALWAYS(pOldWnd);
}
void CPTZControlDlg::OnTimer(UINT_PTR nIDEvent)
{
if (nIDEvent == TIMER_FOCUS_CHECK)
{
CWnd* pWndFocus = GetFocus();
if (pWndFocus &&
pWndFocus->GetParent()==this &&
(GetAsyncKeyState(VK_LBUTTON) & 0x8000)==0)
// only move the focus, when a button has the focus and the mouse is not down.
SetFocus();
}
else if (nIDEvent == TIMER_CLEAR_MEMORY)
{
// Clear the mem button after some delay
ResetMemButton();
}
__super::OnTimer(nIDEvent);
}
void CPTZControlDlg::OnBtUnpushed()
{
GetCurrentWebCam().Pan(0);
GetCurrentWebCam().Tilt(0);
}
void CPTZControlDlg::OnBtSettings()
{
CSettingsDlg dlg;
dlg.m_strCameraName = m_strCameraDeviceName;
dlg.m_bLogitechCameraControl = GetCurrentWebCam().UseLogitechMotionControl();
dlg.m_iMotorIntervalTimer = GetCurrentWebCam().GetMotorIntervalTimer();
// Get a copy of the tooltips
for (int i = 0; i < CWebcamController::NUM_PRESETS; ++i)
{
for (int j = 0; j < CPTZControlDlg::NUM_MAX_WEBCAMS; ++j)
{
dlg.m_strTooltip[j][i] = m_strTooltips[j][i];
}
}
if (dlg.DoModal()!=IDOK)
return;
// Copy back and save
for (int i = 0; i < CWebcamController::NUM_PRESETS; ++i)
{
for (int j = 0; j < CPTZControlDlg::NUM_MAX_WEBCAMS; ++j)
{
m_strTooltips[j][i] = dlg.m_strTooltip[j][i];
CString str;
str.Format(REG_TOOLTIP, i + 1 + j*100);
theApp.WriteProfileString(REG_WINDOW, str, m_strTooltips[j][i]);
}
}
// Camera control
GetCurrentWebCam().UseLogitechMotionControl(dlg.m_bLogitechCameraControl!=0);
theApp.WriteProfileInt(REG_DEVICE, REG_USELOGOTECHMOTIONCONTROL, dlg.m_bLogitechCameraControl);
GetCurrentWebCam().SetMotorIntervalTimer(dlg.m_iMotorIntervalTimer);
theApp.WriteProfileInt(REG_DEVICE, REG_USELOGOTECHMOTIONCONTROL, dlg.m_bLogitechCameraControl);
// Set tooltips again
SetActiveCam(m_iCurrentWebCam);
}

151
PTZControl/PTZControlDlg.h Normal file
View File

@@ -0,0 +1,151 @@
// PTZControlDlg.h : header file
//
#pragma once
#include "resource.h"
#include "ExtensionUnit.h"
//////////////////////////////////////////////////////////////////////////////////////////
// CPTZButton
class CPTZButton : public CMFCButton
{
DECLARE_DYNAMIC(CPTZButton)
public:
CPTZButton();
void SetCheckStyle()
{
m_bCheckButton = TRUE;
m_bAutoCheck = FALSE;
}
void SetAutoRepeat(bool bVal)
{
m_bAutoRepeat = bVal;
}
bool InAutoRepeat()
{
return m_uiSent!=0;
}
COLORREF GetFaceColor()
{
return m_clrFace;
}
void SetTooltip(LPCTSTR lpszToolTipText)
{
// We keep an internal copy of the tooltip
m_strTooltip = lpszToolTipText;
__super::SetTooltip(lpszToolTipText);
}
CString GetTooltip()
{
return m_strTooltip;
}
protected:
// Data
bool m_bAutoRepeat;
UINT m_uiSent;
CString m_strTooltip;
protected:
void PreSubclassWindow() override;
void OnDrawBorder(CDC* pDC, CRect& rectClient, UINT uiState) override;
void OnDrawFocusRect(CDC* pDC, const CRect& rectClient) override;
public:
DECLARE_MESSAGE_MAP()
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
};
//////////////////////////////////////////////////////////////////////////////////////////
// CPTZControlDlg dialog
class CPTZControlDlg : public CDialogEx
{
// Construction
public:
CPTZControlDlg(CWnd* pParent = nullptr); // standard constructor
~CPTZControlDlg();
// Dialog Data
enum { IDD = IDD_PTZCONTROL_DIALOG };
static const int NUM_MAX_WEBCAMS = 2;
protected:
CPTZButton m_btZoomIn;
CPTZButton m_btZoomOut;
CPTZButton m_btUp;
CPTZButton m_btDown;
CPTZButton m_btHome;
CPTZButton m_btLeft;
CPTZButton m_btRight;
CPTZButton m_btMemory;
CPTZButton m_btPreset[CWebcamController::NUM_PRESETS];
CPTZButton m_btExit;
CPTZButton m_btSettings;
CPTZButton m_btWebCam[NUM_MAX_WEBCAMS];
// The controller
CWebcamController m_aWebCams[NUM_MAX_WEBCAMS];
// Map to save the colors of the buttons per Webcam
typedef std::map<UINT,COLORREF> TMAP_BTNCOLORS;
TMAP_BTNCOLORS m_aMapBtnColors[NUM_MAX_WEBCAMS];
// Tooltips per WebCam
CString m_strTooltips[NUM_MAX_WEBCAMS][CWebcamController::NUM_PRESETS];
HACCEL m_hAccel;
CString m_strCameraDeviceName;
int m_iCurrentWebCam; // zero based index to m_aWebCams
int m_iNumWebCams;
void ResetAllColors();
CWebcamController &GetCurrentWebCam();
void SetActiveCam(int iCam);
// Guard thread
CEvent m_evTerminating;
CWinThread* m_pGuardThread;
static UINT AFX_CDECL GuardThread(LPVOID hWnd); // AFX_THREADPROC
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
virtual BOOL OnInitDialog();
virtual void PostNcDestroy();
virtual void OnOK();
virtual void OnCancel();
virtual BOOL PreTranslateMessage(MSG* pMsg);
virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam) override;
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
afx_msg void OnBtExit();
afx_msg void OnClose();
afx_msg LRESULT OnNcHitTest(CPoint point);
afx_msg void OnBtMemory();
afx_msg BOOL OnBtPreset(UINT nId);
void ResetMemButton();
afx_msg BOOL OnBtWebCam(UINT nId);
afx_msg void OnSetFocus(CWnd* pOldWnd);
afx_msg void OnBtZoomIn();
afx_msg void OnBtZoomOut();
afx_msg void OnBtUp();
afx_msg void OnBtLeft();
afx_msg void OnBtHome();
afx_msg void OnBtRight();
afx_msg void OnBtDown();
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg void OnBtUnpushed();
afx_msg void OnBtSettings();
};

View File

@@ -0,0 +1,77 @@
// SettingsDlg.cpp : implementation file
//
#include "pch.h"
#include "PTZControl.h"
#include "SettingsDlg.h"
#include "afxdialogex.h"
// CSettingsDlg dialog
IMPLEMENT_DYNAMIC(CSettingsDlg, CDialogEx)
CSettingsDlg::CSettingsDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_SETTINGS, pParent)
, m_bLogitechCameraControl(FALSE)
, m_iMotorIntervalTimer(0)
{
}
CSettingsDlg::~CSettingsDlg()
{
}
void CSettingsDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_ED_CAMERA, m_strCameraName);
DDX_Text(pDX, IDC_ED_TOOLTIP_1_1, m_strTooltip[0][0]);
DDX_Text(pDX, IDC_ED_TOOLTIP_1_2, m_strTooltip[0][1]);
DDX_Text(pDX, IDC_ED_TOOLTIP_1_3, m_strTooltip[0][2]);
DDX_Text(pDX, IDC_ED_TOOLTIP_1_4, m_strTooltip[0][3]);
DDX_Text(pDX, IDC_ED_TOOLTIP_1_5, m_strTooltip[0][4]);
DDX_Text(pDX, IDC_ED_TOOLTIP_1_6, m_strTooltip[0][5]);
DDX_Text(pDX, IDC_ED_TOOLTIP_1_7, m_strTooltip[0][6]);
DDX_Text(pDX, IDC_ED_TOOLTIP_1_8, m_strTooltip[0][7]);
DDX_Text(pDX, IDC_ED_TOOLTIP_2_1, m_strTooltip[1][0]);
DDX_Text(pDX, IDC_ED_TOOLTIP_2_2, m_strTooltip[1][1]);
DDX_Text(pDX, IDC_ED_TOOLTIP_2_3, m_strTooltip[1][2]);
DDX_Text(pDX, IDC_ED_TOOLTIP_2_4, m_strTooltip[1][3]);
DDX_Text(pDX, IDC_ED_TOOLTIP_2_5, m_strTooltip[1][4]);
DDX_Text(pDX, IDC_ED_TOOLTIP_2_6, m_strTooltip[1][5]);
DDX_Text(pDX, IDC_ED_TOOLTIP_2_7, m_strTooltip[1][6]);
DDX_Text(pDX, IDC_ED_TOOLTIP_2_8, m_strTooltip[1][7]);
DDX_Check(pDX, IDC_CH_LOGITECHCONTROL, m_bLogitechCameraControl);
DDX_Text(pDX, IDC_ED_MOTORTIME, m_iMotorIntervalTimer);
DDX_Control(pDX, IDC_ED_MOTORTIME, m_edMotorInterval);
DDX_Control(pDX, IDC_CH_LOGITECHCONTROL, m_chLogitechControl);
if (pDX->m_bSaveAndValidate)
m_iMotorIntervalTimer = min(max(10,m_iMotorIntervalTimer),1000);
}
BEGIN_MESSAGE_MAP(CSettingsDlg, CDialogEx)
ON_BN_CLICKED(IDC_CH_LOGITECHCONTROL, &CSettingsDlg::OnChLogitechcontrol)
END_MESSAGE_MAP()
// CSettingsDlg message handlers
void CSettingsDlg::OnChLogitechcontrol()
{
m_edMotorInterval.EnableWindow(!m_chLogitechControl.GetCheck());
}
BOOL CSettingsDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
OnChLogitechcontrol();
CenterWindow();
return TRUE;
}

34
PTZControl/SettingsDlg.h Normal file
View File

@@ -0,0 +1,34 @@
#pragma once
#include "ExtensionUnit.h"
#include "PTZControlDlg.h"
// CSettingsDlg dialog
class CSettingsDlg : public CDialogEx
{
DECLARE_DYNAMIC(CSettingsDlg)
public:
CSettingsDlg(CWnd* pParent = nullptr); // standard constructor
virtual ~CSettingsDlg();
// Dialog Data
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_SETTINGS };
#endif
public:
CString m_strCameraName;
CString m_strTooltip[CPTZControlDlg::NUM_MAX_WEBCAMS][CWebcamController::NUM_PRESETS];
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
public:
BOOL m_bLogitechCameraControl;
int m_iMotorIntervalTimer;
afx_msg void OnChLogitechcontrol();
CEdit m_edMotorInterval;
CButton m_chLogitechControl;
virtual BOOL OnInitDialog();
};

31
PTZControl/framework.h Normal file
View File

@@ -0,0 +1,31 @@
#pragma once
#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
#endif
#include "targetver.h"
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit
// turns off MFC's hiding of some common and often safely ignored warning messages
#define _AFX_ALL_WARNINGS
#include <afxwin.h> // MFC core and standard components
#include <afxext.h> // MFC extensions
#ifndef _AFX_NO_OLE_SUPPORT
#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
#endif
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h> // MFC support for Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT
#include <afxcontrolbars.h> // MFC support for ribbons and control bars
#include <afxdialogex.h>
#include <list>
#include <vector>
#include <map>
#include <set>

5
PTZControl/pch.cpp Normal file
View File

@@ -0,0 +1,5 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

13
PTZControl/pch.h Normal file
View File

@@ -0,0 +1,13 @@
// pch.h: This is a precompiled header file.
// Files listed below are compiled only once, improving build performance for future builds.
// This also affects IntelliSense performance, including code completion and many code browsing features.
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
// Do not add files here that you will be updating frequently as this negates the performance advantage.
#ifndef PCH_H
#define PCH_H
// add headers that you want to pre-compile here
#include "framework.h"
#endif //PCH_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

66
PTZControl/resource.h Normal file
View File

@@ -0,0 +1,66 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by PTZControl.rc
//
#define IDD_PTZCONTROL_DIALOG 102
#define IDD_PTZCONTROL 102
#define IDR_MAINFRAME 128
#define IDB_BUTTONS 130
#define IDP_ERR_NO_CAMERA 131
#define IDP_ERR_OPENFAILED 132
#define IDR_ACCELERATOR 132
#define IDD_SETTINGS 133
#define IDP_TXT_CAMERAS 133
#define IDC_BT_LEFT 1000
#define IDC_BT_RIGHT 1001
#define IDC_CHECK1 1001
#define IDC_CH_LOGITECHCONTROL 1001
#define IDC_BT_UP 1002
#define IDC_ED_TOOLTIP_1_1 1002
#define IDC_BT_DOWN 1003
#define IDC_ED_TOOLTIP_1_2 1003
#define IDC_BT_HOME 1004
#define IDC_ED_TOOLTIP_1_3 1004
#define IDC_BT_MEMORY 1005
#define IDC_ED_TOOLTIP_1_4 1005
#define IDC_BT_PRESET1 1006
#define IDC_ED_TOOLTIP_1_5 1006
#define IDC_BT_PRESET2 1007
#define IDC_ED_TOOLTIP_1_6 1007
#define IDC_BT_PRESET3 1008
#define IDC_ED_TOOLTIP_1_7 1008
#define IDC_BT_PRESET4 1009
#define IDC_ED_TOOLTIP_1_8 1009
#define IDC_BT_PRESET5 1010
#define IDC_ED_CAMERA 1010
#define IDC_BT_PRESET6 1011
#define IDC_EDIT1 1011
#define IDC_ED_MOTORTIME 1011
#define IDC_BT_PRESET7 1012
#define IDC_ED_TOOLTIP_2_1 1012
#define IDC_BT_PRESET8 1013
#define IDC_ED_TOOLTIP_2_2 1013
#define IDC_BT_ZOOM_IN 1014
#define IDC_ED_TOOLTIP_2_3 1014
#define IDC_BT_ZOOM_OUT 1015
#define IDC_ED_TOOLTIP_2_4 1015
#define IDC_BT_EXIT 1016
#define IDC_ED_TOOLTIP_2_5 1016
#define IDC_BT_SETTINGS 1017
#define IDC_ED_TOOLTIP_2_6 1017
#define IDC_BT_WEBCAM1 1018
#define IDC_ED_TOOLTIP_2_7 1018
#define IDC_BT_WEBCAM2 1019
#define IDC_ED_TOOLTIP_2_8 1019
#define DC_BT_SETTINGS 32791
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 135
#define _APS_NEXT_COMMAND_VALUE 32793
#define _APS_NEXT_CONTROL_VALUE 1012
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

8
PTZControl/targetver.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#include <SDKDDKVer.h>