What the DeviceIocontrol API function will do? - delphi

Please explain what does this VC++ code do? Is it possible to convert this code to Delphi2010?
void CDMOnLineView::OnActionGetdata()
{
bool retCode;
DWORD retByte = 0;
int TmpHigh, TmpLow;
UCHAR HIDData[64];
int LastX, LastY;
UCHAR Button;
CDC* pViewDC = GetDC();
if(yPos > 500) yPos = 0;
else yPos = yPos + 16;
if(hDriver == NULL)
{
pViewDC->TextOut(10,yPos,"Driver not connect yet.");
}
else
{
IO_Param.CallerHandle = m_hWnd;
IO_Param.Model = DM_A4;
retCode = DeviceIoControl(hDriver, IOCTL_DM_READ_DATA, &IO_Param, sizeof(DM_PARAM), HIDData,
6, &retByte, NULL);
if(retCode)
{
if(retByte != 0)
{
Button = HIDData[1] & 0x01;
TmpLow = (int)HIDData[2];
TmpHigh = (int)HIDData[3];
LastX = (TmpLow & 0x00FF) | ((TmpHigh << 8) & 0xFF00);
TmpLow = (int)HIDData[4];
TmpHigh = (int)HIDData[5];
LastY = (TmpLow & 0x00FF) | ((TmpHigh << 8) & 0xFF00);
sprintf(szStringBuffer, "Button: %d, X: %.5d, Y: %.5d", Button, LastX, LastY);
pViewDC->TextOut(10,yPos,szStringBuffer, strlen(szStringBuffer));
}
else pViewDC->TextOut(10,yPos,"Return bytes incorrect.");
}
else
{
ErrorCode = GetLastError();
sprintf(szStringBuffer, "Call IOCTL_DM_READ_DATA fail. Error: %d", ErrorCode);
pViewDC->TextOut(10,yPos,szStringBuffer, strlen(szStringBuffer));
}
}
ReleaseDC(pViewDC);
}
What the DeviceIocontrol function will do? Please try to explain the parameters also.
thanks all.

Here's the "translation" of all those bitwise operations in the code, hopefully those would get you going:
The operators you need to know about:
& as the bitwise AND operator.
| is the bitwise OR operator
<< is the bitwise SHIFT LEFT operator
The translations:
Button = HIDData[1] & 0x01; // C
Button := HIDData[1] and $01; // Delphi
TmpLow = (int)HIDData[2]; // C
TmpLow := Integer(HIDData[2]); // Delphi
TmpHigh = (int)HIDData[3]; // C
TmpHigh := Integer(HidData[3]); // Delphi
LastX = (TmpLow & 0x00FF) | ((TmpHigh << 8) & 0xFF00); // C
LastX := (TmpLow and $00FF) or ((TmpHigh shl 8) and $FF00); // Delphi
TmpLow = (int)HIDData[4]; // C
TmpLow := Integer(HIDData[4]); // Delphi
TmpHigh = (int)HIDData[5]; // C
TmpHigh := Integer(HIDData[5]); // Delphi
LastY = (TmpLow & 0x00FF) | ((TmpHigh << 8) & 0xFF00); // C
LastY := (TmpLow and $00FF) or ((TmpHigh shl 8) and $FF00); // Delphi
sprintf(szStringBuffer, "Button: %d, X: %.5d, Y: %.5d", Button, LastX, LastY); // C
pViewDC->TextOut(10,yPos,szStringBuffer, strlen(szStringBuffer)); // C
Caption := Format('Button: %d, x: %.5d, y: %.5d', [Button, LastX, LastY]); // Delphi

DeviceIoControl calls custom driver function. Driver is kernel-mode program representing some computer device. Drivers have standard operations (like open, close, read, write, which are called using CreateFile, CloseHandle, ReadFile and WriteFile API) and custom driver-specific operations, called using DeviceIoControl. Details about these operations are described in the driver documentation.
Every custom operation has generic interface: operation code, input and output buffers, which may contain any information.

The DeviceIoControl function is documented at MSDN. User mode programs use it to interact with device drivers.
Converting this code is pretty simple. The call to DeviceIoControl maps across trivially. The only area that you are likely to struggle with is the C bitwise operations. If you don't have a copy of K&R to hand, then you should!

Related

RDP ActiveX SendKeys Win+L to Lock Screen

Working on an application that uses RDP ActiveX controls. Trying to use IMsRdpClientNonScriptable::SendKeys to simulate Win + L combo to Lock the screen within RDP session, but its not working. Only L key seems to go through?
long nKeyCount = 4;
VARIANT_BOOL keyUp[4];
long keyData[4];
keyData[0] = 92;
keyData[1] = SC_L;
keyData[2] = SC_L;
keyData[3] = 92;
keyUp[0] = VARIANT_FALSE;
keyUp[1] = VARIANT_FALSE;
keyUp[2] = VARIANT_TRUE;
keyUp[3] = VARIANT_TRUE;
rdpclient.SendKeys(nKeyCount, &keyUp[0], &keyData[0]);
Edit: Tried assigning values using LPARAM format. This didn't work either.
keyData[0] = WmKeyDown_lParam(92, 0, 1);
keyData[1] = WmKeyDown_lParam(SC_L, 0, 1);
keyData[2] = WmKeyDown_lParam(SC_L, 1, 1);
keyData[3] = WmKeyDown_lParam(92, 1, 1);
long Rdp::WmKeyDown_lParam(uint scanCode, uint prevState, uint extended)
{
//scan does works
uint repeatCount = 0;
uint context = 0;
uint previousState = prevState;
uint transition = 0;
// combine the parameters above according to the bit
// fields described in the MSDN page for WM_KEYDOWN
long lParam = repeatCount
| (scanCode << 16)
| (extended << 24)
| (context << 29)
| (previousState << 30)
| (transition << 31);
//lParam = scanCode << 16;
return lParam;
}

Manual CBC encryption handing with Crypto++

I am trying to play around with a manual encryption in CBC mode but still use Crypto++, just to know can I do it manually.
The CBC algorithm is (AFAIK):
Presume we have n block K[1]....k[n]
0. cipher = empty;
1. xor(IV, K1) -> t1
2. encrypt(t1) -> r1
3. cipher += r1
4. xor (r1, K2) -> t2
5. encrypt(t2) -> r2
6. cipher += r2
7. xor(r2, K3)->t3
8. ...
So I tried to implement it with Crypto++. I have a text file with alphanumeric characters only. Test 1 is read file chunk by chunk (16 byte) and encrypt them using CBC mode manually, then sum up the cipher. Test 2 is use Crypto++ built-in CBC mode.
Test 1
char* key;
char* iv;
//Iterate in K[n] array of n blocks
BSIZE = 16;
std::string vectorToString(vector<char> v){
string s ="";
for (int i = 0; i < v.size(); i++){
s[i] = v[i];
}
return s;
}
vector<char> xor( vector<char> s1, vector<char> s2, int len){
vector<char> r;
for (int i = 0; i < len; i++){
int u = s1[i] ^ s2[i];
r.push_back(u);
}
return r;
}
vector<char> byteToVector(byte *b, int len){
vector<char> v;
for (int i = 0; i < len; i++){
v.push_back( b[i]);
}
return v;
}
string cbc_manual(byte [n]){
int i = 0;
//Open a file and read from it, buffer size = 16
// , equal to DEFAULT_BLOCK_SIZE
std::ifstream fin(fileName, std::ios::binary | std::ios::in);
const int BSIZE = 16;
vector<char> encryptBefore;
//This function will return cpc
string cpc ="";
while (!fin.eof()){
char buffer[BSIZE];
//Read a chunk of file
fin.read(buffer, BSIZE);
int sb = sizeof(buffer);
if (i == 0){
encryptBefore = byteToVector( iv, BSIZE);
}
//If i == 0, xor IV with current buffer
//else, xor encryptBefore with current buffer
vector<char> t1 = xor(encryptBefore, byteToVector((byte*) buffer, BSIZE), BSIZE);
//After xored, encrypt the xor result, it will be current step cipher
string r1= encrypt(t1, BSIZE).c_str();
cpc += r1;
const char* end = r1.c_str() ;
encryptBefore = stringToVector( r1);
i++;
}
return cpc;
}
This is my encrypt() function, because we have only one block so I use ECB (?) mode
string encrypt(string s, int size){
ECB_Mode< AES >::Encryption e;
e.SetKey(key, size);
string cipher;
StringSource ss1(s, true,
new StreamTransformationFilter(e,
new StringSink(cipher)
) // StreamTransformationFilter
); // StringSource
return cipher;
}
And this is 100% Crypto++ made solution:
Test 2
encryptCBC(char * plain){
CBC_Mode < AES >::Encryption encryption(key, sizeof(key), iv);
StreamTransformationFilter encryptor(encryption, NULL);
for (size_t j = 0; j < plain.size(); j++)
encryptor.Put((byte)plain[j]);
encryptor.MessageEnd();
size_t ready = encryptor.MaxRetrievable();
string cipher(ready, 0x00);
encryptor.Get((byte*)&cipher[0], cipher.size());
}
Result of Test 1 and Test 2 are different. In the fact, ciphered text from Test 1 is contain the result of Test 2. Example:
Test 1's result aaa[....]bbb[....]ccc[...]...
Test 2 (Crypto++ built-in CBC)'s result: aaabbbccc...
I know the xor() function may cause a problem relate to "sameChar ^ sameChar = 0", but is there any problem relate to algorithm in my code?
This is my Test 2.1 after the 1st solution of jww.
static string auto_cbc2(string plain, long size){
CBC_Mode< AES >::Encryption e;
e.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
string cipherText;
CryptoPP::StringSource ss(plain, true,
new CryptoPP::StreamTransformationFilter(e,
new CryptoPP::StringSink(cipherText)
, BlockPaddingSchemeDef::NO_PADDING
) // StreamTransformationFilter
); // StringSource
return cipherText;
}
It throw an error:
Unhandled exception at 0x7407A6F2 in AES-CRPP.exe: Microsoft C++
exception: CryptoPP::InvalidDataFormat at memory location 0x00EFEA74
I only got this error when use BlockPaddingSchemeDef::NO_PADDING, tried to remove BlockPaddingSchemeDef or using BlockPaddingSchemeDef::DEFAULT_PADDING, I got no error . :?
StringSource ss1(s, true,
new StreamTransformationFilter(e,
new StringSink(cipher)));
This uses PKCS padding by default. It takes a 16-byte input and produces a 32-byte output due to padding. You should do one of two things.
First, you can use BlockPaddingScheme::NO_PADDING. Something like:
StringSource ss1(s, true,
new StreamTransformationFilter(e,
new StringSink(cipher)
BlockPaddingScheme::NO_PADDING));
Second, you can process blocks manually, 16 bytes at a time. Something like:
AES::Encryption encryptor(key, keySize);
byte ibuff[<some size>] = ...;
byte obuff[<some size>];
ASSERT(<some size> % AES::BLOCKSIZE == 0);
unsigned int BLOCKS = <some size>/AES::BLOCKSIZE;
for (unsigned int i=0; i<BLOCKS; i==)
{
encryptor.ProcessBlock(&ibuff[i*16], &obuff[i*16]);
// Do the CBC XOR thing...
}
You may be able to call ProcessAndXorBlock from the BlockCipher base class and do it in one shot.

Rough Edges With Lanczos Resampling in Golang

I've been writing some basic methods to resize images in Golang. I've seen several posts about resizing images, but for the life of me I can't figure out what I'm missing...
Essentially, my issue is that when resizing an image in Golang, my results seem to have a lot of aliasing.
I've tried iteratively downsampling the image, but that didn't yield much of an improvement.
Here's my code:
func resize(original image.Image,
edgeSize int, filterSize int) image.Image {
oldBounds := original.Bounds()
if oldBounds.Dx() < edgeSize && oldBounds.Dy() < edgeSize {
// No resize necessary
return original
}
threshold := edgeSize * 4 / 3
if oldBounds.Dx() > threshold || oldBounds.Dy() > threshold {
fmt.Println("Upstream")
original = customResizeImageToFitBounds(original, threshold, filterSize)
oldBounds = original.Bounds()
}
newBounds := getNewBounds(oldBounds, edgeSize)
resized := image.NewRGBA(newBounds)
var ratioX = float64(oldBounds.Dx()) / float64(newBounds.Dx())
var ratioY = float64(oldBounds.Dy()) / float64(newBounds.Dy())
for x := 0; x < newBounds.Dx(); x++ {
for y := 0; y < newBounds.Dy(); y++ {
sourceX := ratioX * float64(x)
minX := int(math.Floor(sourceX))
sourceY := ratioY * float64(y)
minY := int(math.Floor(sourceY))
sampleSize := filterSize<<1 + 1
var xCoeffs = make([]float64, sampleSize)
var yCoeffs = make([]float64, sampleSize)
var sumX = 0.0
var sumY = 0.0
for i := 0; i < sampleSize; i++ {
xCoeffs[i] = lanczos(filterSize, sourceX-float64(minX+i-filterSize))
yCoeffs[i] = lanczos(filterSize, sourceY-float64(minY+i-filterSize))
sumX += xCoeffs[i]
sumY += yCoeffs[i]
}
for i := 0; i < sampleSize; i++ {
xCoeffs[i] /= sumX
yCoeffs[i] /= sumY
}
rgba := make([]float64, 4)
for i := 0; i < sampleSize; i++ {
if yCoeffs[i] == 0.0 {
continue
}
currY := minY + i - filterSize
rgbaRow := make([]float64, 4)
for j := 0; j < sampleSize; j++ {
if xCoeffs[j] == 0.0 {
continue
}
currX := minX + i - filterSize
rij, gij, bij, aij := original.At(
clamp(currX, currY, oldBounds)).RGBA()
rgbaRow[0] += float64(rij) * xCoeffs[j]
rgbaRow[1] += float64(gij) * xCoeffs[j]
rgbaRow[2] += float64(bij) * xCoeffs[j]
rgbaRow[3] += float64(aij) * xCoeffs[j]
}
rgba[0] += float64(rgbaRow[0]) * yCoeffs[i]
rgba[1] += float64(rgbaRow[1]) * yCoeffs[i]
rgba[2] += float64(rgbaRow[2]) * yCoeffs[i]
rgba[3] += float64(rgbaRow[3]) * yCoeffs[i]
}
rgba[0] = clampRangeFloat(0, rgba[0], 0xFFFF)
rgba[1] = clampRangeFloat(0, rgba[1], 0xFFFF)
rgba[2] = clampRangeFloat(0, rgba[2], 0xFFFF)
rgba[3] = clampRangeFloat(0, rgba[3], 0xFFFF)
var rgbaF [4]uint64
rgbaF[0] = (uint64(math.Floor(rgba[0]+0.5)) * 0xFF) / 0xFFFF
rgbaF[1] = (uint64(math.Floor(rgba[1]+0.5)) * 0xFF) / 0xFFFF
rgbaF[2] = (uint64(math.Floor(rgba[2]+0.5)) * 0xFF) / 0xFFFF
rgbaF[3] = (uint64(math.Floor(rgba[3]+0.5)) * 0xFF) / 0xFFFF
rf := uint8(clampRangeUint(0, uint32(rgbaF[0]), 255))
gf := uint8(clampRangeUint(0, uint32(rgbaF[1]), 255))
bf := uint8(clampRangeUint(0, uint32(rgbaF[2]), 255))
af := uint8(clampRangeUint(0, uint32(rgbaF[3]), 255))
resized.Set(x, y, color.RGBA{R: rf, G: gf, B: bf, A: af})
}
}
return resized
}
// Machine epsilon
var epsilon = math.Nextafter(1.0, 2.0) - 1
func lanczos(filterSize int, x float64) float64 {
x = math.Abs(x)
fs := float64(filterSize)
if x < epsilon {
return 1.0
}
if x > fs {
return 0
}
piX := math.Pi * x
piXOverFS := piX / fs
return (math.Sin(piX) / piX) * (math.Sin(piXOverFS) / (piXOverFS))
}
It isn't particularly performant, because I want to get a good quality result before I look at optimization.
Does anyone who has experience with image resampling see anything potentially problematic?
For reference, here is my source image:
Here is my result:
Here is my result if I remove the recursive call:
Here is the result using RMagick/ImageMagick through Ruby (what I'm shooting for):
Does anyone have advice for how I can get a smoother downscale result?
This particular example is a pretty drastic downscale, but Rmagick was able to downscale it very quickly with great quality, so it must be possible.
I'm told that Lanczos3 Resampling yields good results, and that's what I'm trying to use here - I'm not sure if my implementation is correct though.
Also, as a side note: the 0xFF / 0xFFFF conversion is because golang's "At" function returns rgba values in the range [0, 0xFFFF] ([0, 65535]) but "Set" takes a color which is initialized with the range [0, 0xFF] ([0, 255])
For now, I'm more concerned with quality than performance.
Alright, I think I've found one way to solve the aliasing problem. Instead of using lanczos3, I used bilinear interpolation to resample the source image at a size slightly higher than what I was going for (edgeSize = 1080), gaussian blurred the image, then scaled the image down to the target size (edgeSize = 600), this time with bicubic interpolation. This gave me results just about the same as the ones RMagick was giving me.

Getting the nearest free memory VirtualAllocEx

I want get the nearest free memory address to allocate memory for CodeCave but i want it to be within the jmp instruction limit 0xffffffff-80000000 , Im trying the following code but without much luck.
DWORD64 MemAddr = 0;
DWORD64 Address = 0x0000000140548AE6 & 0xFFFFFFFFFFFFF000;
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, NULL, ProcessID);
if (hProc){
for (DWORD offset = 0; (Address + 0x000000007FFFEFFF)>((Address - 0x000000007FFFEFFF) + offset); offset += 100)
{
MemAddr = (DWORD64)VirtualAllocEx(hProc, (DWORD64*)((Address - 0x000000007FFFEFFF) + offset),MemorySize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if ((DWORD64)MemAddr){
break;
}
}
CloseHandle(hProc);
return (DWORD64)MemAddr;
}
return 0;
Target Process is 64bit .
If the target process is x64 then make sure you're compiling for x64 as well.
I have used this code for the same purpose, to find free memory within a 4GB address range for doing x64 jmps for a x64 hook.
char* AllocNearbyMemory(HANDLE hProc, char* nearThisAddr)
{
char* begin = nearThisAddr;
char* end = nearThisAddr + 0x7FFF0000;
MEMORY_BASIC_INFORMATION mbi{};
auto curr = begin;
while (VirtualQueryEx(hProc, curr, &mbi, sizeof(mbi)))
{
if (mbi.State == MEM_FREE)
{
char* addr = (char*)VirtualAllocEx(hProc, mbi.BaseAddress, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (addr) return addr;
}
curr += mbi.RegionSize;
}
return 0;
}
Keep in mind there is no error checking, just a simple PoC

Manually focus webcam from openCV

How can i set from openCV the focus of a webcam or any other camera? I would like to find the distance of on object, but I want to write the program, so I need to manually be able to focus, manually meaning from code.
I'm using Logitech webcams (tested C525, C920 and C931e). The key 28 is for setting focus. Note that the focus value should be multiples of 5 (0, 5, 10... 255), otherwise the VideoCapture object would simply not respond.
import cv2
cam = cv2.VideoCapture(0)
focus = 0 # min: 0, max: 255, increment:5
cam.set(28, focus)
You can't set focus from opencv, but windows SDK allows it. Take a look at: http://msdn.microsoft.com/en-us/library/windows/hardware/ff567802(v=vs.85).aspx
I've used setting of minidriver properties for focus control, and it works perfect with logitch 905c and 920c.
I found the code example on my disk, hope it'll be userful:
/*****************************************************************************
* DirectShow Pan/Tilt/Zoom sample for Logitech QuickCam devices
*
* Copyright 2007 (c) Logitech. All Rights Reserved.
*
* This code and information is provided "as is" without warranty of
* any kind, either expressed or implied, including but not limited to
* the implied warranties of merchantability and/or fitness for a
* particular purpose.
*
* Version: 1.1
****************************************************************************/
#include <dshow.h>
#include <Ks.h> // Required by KsMedia.h
#include <KsMedia.h> // For KSPROPERTY_CAMERACONTROL_FLAGS_*
struct ControlInfo {
long min;
long max;
long step;
long def;
long flags;
};
/*
* Print information about a control in an easily readable fashion.
*/
void print_control_info(ControlInfo *info)
{
char flags[32] = "";
if(info->flags & KSPROPERTY_CAMERACONTROL_FLAGS_AUTO)
{
strcat_s(flags, sizeof(flags), "AUTO | ");
}
else if(info->flags & KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL)
{
strcat_s(flags, sizeof(flags), "MANUAL | ");
}
if(info->flags & KSPROPERTY_CAMERACONTROL_FLAGS_RELATIVE)
{
strcat_s(flags, sizeof(flags), "RELATIVE");
}
else
{
strcat_s(flags, sizeof(flags), "ABSOLUTE");
}
printf(
" min: %d\n"
" max: %d\n"
" step: %d\n"
" def: %d\n"
" flags: 0x%08X (%s)\n",
info->min, info->max, info->step, info->def, info->flags, flags
);
}
/*
* Pans the camera by a given angle.
*
* The angle is given in degrees, positive values are clockwise rotation (seen from the top),
* negative values are counter-clockwise rotation. If the "Mirror horizontal" option is
* enabled, the panning sense is reversed.
*/
HRESULT set_mechanical_pan_relative(IAMCameraControl *pCameraControl, long value)
{
HRESULT hr = 0;
long flags = KSPROPERTY_CAMERACONTROL_FLAGS_RELATIVE | KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
hr = pCameraControl->Set(CameraControl_Pan, value, flags);
if(hr != S_OK)
fprintf(stderr, "ERROR: Unable to set CameraControl_Pan property value to %d. (Error 0x%08X)\n", value, hr);
// Note that we need to wait until the movement is complete, otherwise the next request will
// fail with hr == 0x800700AA == HRESULT_FROM_WIN32(ERROR_BUSY).
Sleep(500);
return hr;
}
/*
* Tilts the camera by a given angle.
*
* The angle is given in degrees, positive values are downwards, negative values are upwards.
* If the "Mirror vertical" option is enabled, the tilting sense is reversed.
*/
HRESULT set_mechanical_tilt_relative(IAMCameraControl *pCameraControl, long value)
{
HRESULT hr = 0;
long flags = KSPROPERTY_CAMERACONTROL_FLAGS_RELATIVE | KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
hr = pCameraControl->Set(CameraControl_Tilt, value, flags);
if(hr != S_OK)
fprintf(stderr, "ERROR: Unable to set CameraControl_Tilt property value to %d. (Error 0x%08X)\n", value, hr);
// Note that we need to wait until the movement is complete, otherwise the next request will
// fail with hr == 0x800700AA == HRESULT_FROM_WIN32(ERROR_BUSY).
Sleep(500);
return hr;
}
/*
* Resets the camera's pan/tilt position by moving into a corner and then back to the center.
*/
void reset_machanical_pan_tilt(IAMCameraControl *pCameraControl)
{
set_mechanical_pan_relative(pCameraControl, 180);
Sleep(500);
set_mechanical_tilt_relative(pCameraControl, 180);
Sleep(500);
set_mechanical_pan_relative(pCameraControl, -64);
Sleep(500);
set_mechanical_tilt_relative(pCameraControl, -24);
Sleep(500);
}
/*
* Sets the digital pan angle.
*
* Positive values pan to the right, negative values pan to the left. Note that the digital pan
* angle only has an influence if the digital zoom is active.
*/
HRESULT set_digital_pan_absolute(IAMCameraControl *pCameraControl, long value)
{
HRESULT hr = 0;
// Specifying the KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE flag instructs the driver
// to use digital instead of mechanical pan.
long flags = KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE | KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
hr = pCameraControl->Set(CameraControl_Pan, value, flags);
if(hr != S_OK)
fprintf(stderr, "ERROR: Unable to set CameraControl_Pan property value to %d. (Error 0x%08X)\n", value, hr);
return hr;
}
/*
* Sets the digital tilt angle.
*
* Positive values tilt downwards, negative values tilt upwards. Note that the digital pan
* angle only has an influence if the digital zoom is active.
*/
HRESULT set_digital_tilt_absolute(IAMCameraControl *pCameraControl, long value)
{
HRESULT hr = 0;
// Specifying the KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE flag instructs the driver
// to use digital instead of mechanical tilt.
long flags = KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE | KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
hr = pCameraControl->Set(CameraControl_Tilt, value, flags);
if(hr != S_OK)
fprintf(stderr, "ERROR: Unable to set CameraControl_Tilt property value to %d. (Error 0x%08X)\n", value, hr);
return hr;
}
/*
* Sets the digital zoom value.
*
* The minimum value is 50 and means no zoom (100%). The maximum value is 200
* and means 4x zoom (400%).
*/
HRESULT set_digital_zoom_absolute(IAMCameraControl *pCameraControl, long value)
{
HRESULT hr = 0;
long flags = KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE | KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
hr = pCameraControl->Set(CameraControl_Zoom, value, flags);
if(hr != S_OK)
fprintf(stderr, "ERROR: Unable to set CameraControl_Zoom property value to %d. (Error 0x%08X)\n", value, hr);
return hr;
}
/*
* Resets the digital pan and tilt angles.
*/
void reset_digital_pan_tilt(IAMCameraControl *pCameraControl)
{
set_digital_pan_absolute(pCameraControl, 0);
set_digital_tilt_absolute(pCameraControl, 0);
}
/*
* Resets the digital zoom.
*/
void reset_digital_zoom(IAMCameraControl *pCameraControl)
{
set_digital_zoom_absolute(pCameraControl, 50);
}
/*
* Test a camera's pan/tilt properties
*
* See also:
*
* IAMCameraControl Interface
* http://msdn2.microsoft.com/en-us/library/ms783833.aspx
* PROPSETID_VIDCAP_CAMERACONTROL
* http://msdn2.microsoft.com/en-us/library/aa510754.aspx
*/
HRESULT test_pan_tilt(IBaseFilter *pBaseFilter)
{
HRESULT hr = 0;
IAMCameraControl *pCameraControl = NULL;
ControlInfo panInfo = { 0 };
ControlInfo tiltInfo = { 0 };
ControlInfo zoomInfo = { 0 };
long value = 0, flags = 0;
printf(" Reading pan/tilt property information ...\n");
// Get a pointer to the IAMCameraControl interface used to control the camera
hr = pBaseFilter->QueryInterface(IID_IAMCameraControl, (void **)&pCameraControl);
if(hr != S_OK)
{
fprintf(stderr, "ERROR: Unable to access IAMCameraControl interface.\n");
return hr;
}
// Retrieve information about the pan and tilt controls
hr = pCameraControl->GetRange(CameraControl_Pan, &panInfo.min, &panInfo.max, &panInfo.step, &panInfo.def, &panInfo.flags);
if(hr != S_OK)
{
fprintf(stderr, "ERROR: Unable to retrieve CameraControl_Pan property information.\n");
return hr;
}
printf(" Pan control:\n");
print_control_info(&panInfo);
hr = pCameraControl->GetRange(CameraControl_Tilt, &tiltInfo.min, &tiltInfo.max, &tiltInfo.step, &tiltInfo.def, &tiltInfo.flags);
if(hr != S_OK)
{
fprintf(stderr, "ERROR: Unable to retrieve CameraControl_Tilt property information.\n");
return hr;
}
printf(" Tilt control:\n");
print_control_info(&tiltInfo);
hr = pCameraControl->GetRange(CameraControl_Zoom, &zoomInfo.min, &zoomInfo.max, &zoomInfo.step, &zoomInfo.def, &zoomInfo.flags);
if(hr != S_OK)
{
fprintf(stderr, "ERROR: Unable to retrieve CameraControl_Zoom property information.\n");
return hr;
}
printf(" Zoom control:\n");
print_control_info(&zoomInfo);
//*
printf(" Resetting pan/tilt/zoom ...\n");
reset_machanical_pan_tilt(pCameraControl);
reset_digital_pan_tilt(pCameraControl);
reset_digital_zoom(pCameraControl);
Sleep(3000);
//*/
//*
printf(" Testing mechanical pan ...\n");
set_mechanical_pan_relative(pCameraControl, 40);
set_mechanical_pan_relative(pCameraControl, 20);
set_mechanical_pan_relative(pCameraControl, -20);
set_mechanical_pan_relative(pCameraControl, -40);
Sleep(3000);
//*/
//*
printf(" Testing mechanical tilt ...\n");
set_mechanical_tilt_relative(pCameraControl, 20);
set_mechanical_tilt_relative(pCameraControl, 10);
set_mechanical_tilt_relative(pCameraControl, -10);
set_mechanical_tilt_relative(pCameraControl, -20);
Sleep(3000);
//*/
//*
printf(" Testing digital pan/tilt/zoom ...\n");
set_digital_zoom_absolute(pCameraControl, 100); // Zoom to 200%
Sleep(1000);
set_digital_pan_absolute(pCameraControl, 40);
Sleep(1000);
set_digital_pan_absolute(pCameraControl, 80);
Sleep(1000);
set_digital_zoom_absolute(pCameraControl, 200); // Zoom to 400%
Sleep(1000);
set_digital_tilt_absolute(pCameraControl, 40);
Sleep(1000);
set_digital_tilt_absolute(pCameraControl, 60);
Sleep(1000);
reset_digital_pan_tilt(pCameraControl);
Sleep(1000);
reset_digital_zoom(pCameraControl);
Sleep(3000);
//*/
//*
printf(" Testing digital zoom ...\n");
for(int i = zoomInfo.min; i <= zoomInfo.max; i += zoomInfo.step)
{
set_digital_zoom_absolute(pCameraControl, i);
Sleep(10);
}
Sleep(1000);
for(int i = zoomInfo.max; i >= zoomInfo.min; i -= zoomInfo.step)
{
set_digital_zoom_absolute(pCameraControl, i);
Sleep(10);
}
//*/
return S_OK;
}
/*
* Do something with the filter. In this sample we just test the pan/tilt properties.
*/
void process_filter(IBaseFilter *pBaseFilter)
{
test_pan_tilt(pBaseFilter);
}
/*
* Enumerate all video devices
*
* See also:
*
* Using the System Device Enumerator:
* http://msdn2.microsoft.com/en-us/library/ms787871.aspx
*/
int enum_devices()
{
HRESULT hr;
printf("Enumerating video input devices ...\n");
// Create the System Device Enumerator.
ICreateDevEnum *pSysDevEnum = NULL;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void **)&pSysDevEnum);
if(FAILED(hr))
{
fprintf(stderr, "ERROR: Unable to create system device enumerator.\n");
return hr;
}
// Obtain a class enumerator for the video input device category.
IEnumMoniker *pEnumCat = NULL;
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
if(hr == S_OK)
{
// Enumerate the monikers.
IMoniker *pMoniker = NULL;
ULONG cFetched;
while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
{
IPropertyBag *pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
(void **)&pPropBag);
if(SUCCEEDED(hr))
{
// To retrieve the filter's friendly name, do the following:
VARIANT varName;
VariantInit(&varName);
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
{
// Display the name in your UI somehow.
wprintf(L" Found device: %s\n", varName.bstrVal);
}
VariantClear(&varName);
// To create an instance of the filter, do the following:
IBaseFilter *pFilter;
hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter,
(void**)&pFilter);
process_filter(pFilter);
//Remember to release pFilter later.
pPropBag->Release();
}
pMoniker->Release();
}
pEnumCat->Release();
}
pSysDevEnum->Release();
return 0;
}
int wmain(int argc, wchar_t* argv[])
{
int result;
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
result = enum_devices();
CoUninitialize();
return result;
}

Resources