I'm using the OLE DB bulk copy operation against a SQL Server database but I'm having trouble while loading data into bit columns - they are always populated with true!
I created a simple reproduction program from Microsoft's sample code with the snippet that I adjusted below. My program includes a little SQL script to create the destination table. I had to download and install the x64 version of the SQL Server OLE DB driver to build this.
// Set up custom bindings.
oneBinding.dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
oneBinding.iOrdinal = 1;
oneBinding.pTypeInfo = NULL;
oneBinding.obValue = ulOffset + offsetof(COLUMNDATA, bData);
oneBinding.obLength = ulOffset + offsetof(COLUMNDATA, dwLength);
oneBinding.obStatus = ulOffset + offsetof(COLUMNDATA, dwStatus);
oneBinding.cbMaxLen = 1; // Size of varchar column.
oneBinding.pTypeInfo = NULL;
oneBinding.pObject = NULL;
oneBinding.pBindExt = NULL;
oneBinding.dwFlags = 0;
oneBinding.eParamIO = DBPARAMIO_NOTPARAM;
oneBinding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
oneBinding.bPrecision = 0;
oneBinding.bScale = 0;
oneBinding.wType = DBTYPE_BOOL;
ulOffset = oneBinding.cbMaxLen + offsetof(COLUMNDATA, bData);
ulOffset = ROUND_UP(ulOffset, COLUMN_ALIGNVAL);
if (FAILED(hr =
pIFastLoad->QueryInterface(IID_IAccessor, (void**)&pIAccessor)))
return hr;
if (FAILED(hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
1,
&oneBinding,
ulOffset,
&hAccessor,
&oneStatus)))
return hr;
// Set up memory buffer.
pData = new BYTE[40];
if (!(pData /* = new BYTE[40]*/)) {
hr = E_FAIL;
goto cleanup;
}
pcolData = (COLUMNDATA*)pData;
pcolData->dwLength = 1;
pcolData->dwStatus = 0;
for (i = 0; i < 10; i++)
{
if (i % 2 == 0)
{
pcolData->bData[0] = 0x00;
}
else
{
pcolData->bData[0] = 0xFF;
}
if (FAILED(hr = pIFastLoad->InsertRow(hAccessor, pData)))
goto cleanup;
}
It's entirely likely that I'm putting the wrong value into the buffer, or have some other constant value incorrect. I did find an article describing the safety of various data type conversions and it looks like byte to bool is safe... but how would the buffer know what kind of data I'm putting in there if it's just a byte array?
Figured this out, I had not correctly switched over the demo from loading strings to fixed-width values. For strings, the data blob gets a 1-width pointer to the value whereas fixed-width values get the actual data.
So my COLUMNDATA struct now looks like this:
// How to lay out each column in memory.
struct COLUMNDATA {
DBLENGTH dwLength; // Length of data (not space allocated).
DWORD dwStatus; // Status of column.
VARIANT_BOOL bData; // Value, or if a string, a pointer to the value.
};
With the relevant length fix here:
pcolData = (COLUMNDATA*)pData;
pcolData->dwLength = sizeof(VARIANT_BOOL); // using a short.. make it two
pcolData->dwStatus = DBSTATUS_S_OK; // Indicates that the data value is to be used, not null
And the little value-setting for loop looks like this:
for (i = 0; i < 10; i++)
{
if (i % 2 == 0)
{
pcolData->bData = VARIANT_TRUE;
}
else
{
pcolData->bData = VARIANT_FALSE;
}
if (FAILED(hr = pIFastLoad->InsertRow(hAccessor, pData)))
goto cleanup;
}
I've updated the repository with the working code. I was inspired to make this change after reading the documentation for the obValue property.
Related
I'm working on a wrapper for MariaDB Connector C. There is a typical situation when a developer doesn't know a length of a data stored in a field. As I figured out, one of the ways to obtain a real length of the field is to pass a buffer of lengths to mysql_stmt_bind_result and then to fetch each column by calling mysql_stmt_fetch_column. But I can't understand how the function mysql_stmt_fetch_column works because I'm getting a memory corruption and app abortion.
Here is how I'm trying to reach my goal
// preparations here
...
if (!mysql_stmt_execute(stmt))
{
int columnNum = mysql_stmt_field_count(stmt);
if (columnNum > 0)
{
MYSQL_RES* metadata = mysql_stmt_result_metadata(stmt);
MYSQL_FIELD* fields = mysql_fetch_fields(metadata);
MYSQL_BIND* result = new MYSQL_BIND[columnNum];
std::memset(result, 0, sizeof (MYSQL_BIND) * columnNum);
std::vector<unsigned long> lengths;
lengths.resize(columnNum);
for (int i = 0; i < columnNum; ++i)
result[i].length = &lengths[i];
if (!mysql_stmt_bind_result(stmt, result))
{
while (true)
{
int status = mysql_stmt_fetch(stmt);
if (status == 1)
{
m_lastError = mysql_stmt_error(stmt);
isOK = false;
break;
}
else if (status == MYSQL_NO_DATA)
{
isOK = true;
break;
}
for (int i = 0; i < columnNum; ++i)
{
my_bool isNull = true;
if (lengths.at(i) > 0)
{
result[i].buffer_type = fields[i].type;
result[i].is_null = &isNull;
result[i].buffer = malloc(lengths.at(i));
result[i].buffer_length = lengths.at(i);
mysql_stmt_fetch_column(stmt, result, i, 0);
if (!isNull)
{
// here I'm trying to read a result and I'm getting a valid result only from the first column
}
}
}
}
}
}
If I put an array to the mysql_stmt_fetch_column then I'm fetching the only first field valid, all other fields are garbage. If I put a single MYSQL_BIND structure to this function, then I'm getting an abortion of the app on approximately 74th field (funny thing that it's always this field). If I use another array of MYSQL_BIND then the situation is the same as the first case.
Please help me to understand how to use it correctly! Thanks
Minimal reproducible example
I have the following code in my COM Add-In for MS Office to go through all hyperlinks in winword document and then parse them:
...
HRESULT hr;
ULONG nRet;
CComQIPtr<MSWORD::Hyperlinks> hylinks = doc->Hyperlinks; // CComQIPtr<_Document> doc
ATLASSERT(hylinks);
IEnumVARIANTPtr pEnum = hylinks->Get_NewEnum();
for (int i = 1; i <= hylinks->Count; i++)
{
VARIANT v = {};
hr = pEnum->Next(1, &v, &nRet);
if (FAILED(hr)) continue;
CComQIPtr<MSWORD::Hyperlink> link;
ATLASSERT(link);
hr = hylinks->raw_Item(&v, &link);
if (FAILED(hr)) continue;
...
// parse hyperlink's address
}
...
The result (hr) when raw_Item() is called, is 80020005 (DISP_E_TYPEMISMATCH)). And there is no trouble with code like this one when I go through Shapes.
Does anyone can help me?
Finally, found out. How many collections have office application, so many ways to iterate them. Here we can do it like following, assign index of type VARIANT manually, not with enumerator:
CComQIPtr<MSWORD::Hyperlinks> hylinks = doc->Hyperlinks; // CComQIPtr<_Document> doc
ATLASSERT(hylinks);
for (int i = 1; i <= hylinks->Count; i++)
{
VARIANT ind;
ind.iVal = i;
ind.vt = VT_I2;
CComQIPtr<MSWORD::Hyperlink> link;
ATLASSERT(link);
link = hylinks->Item(&ind);
// do your magic
}
I managed to create a VHD and attached it. Afterwards, I created a disk(IOCTL CREATE_DISK) and set its layout using IOCTL_DISK_SET_DRIVE_LAYOUT_EX. Now, when I examine disk through Disk Management. I have a 14MB with a 7 MB partition, expectedly.
int sign = 80001;
CREATE_DISK disk;
disk.Mbr.Signature = sign;
disk.PartitionStyle = PARTITION_STYLE_MBR;
auto res = DeviceIoControl(device_handle, IOCTL_DISK_CREATE_DISK, &disk, sizeof(disk), NULL, 0, NULL, NULL);
res = DeviceIoControl(device_handle, IOCTL_DISK_UPDATE_PROPERTIES, 0, 0, NULL, 0, NULL, NULL);
LARGE_INTEGER partition_size;
partition_size.QuadPart = 0xF00;
DWORD driver_layout_ex_len = sizeof(DRIVE_LAYOUT_INFORMATION_EX);
DRIVE_LAYOUT_INFORMATION_EX driver_layout_info;
memset(&driver_layout_info, 0, sizeof(DRIVE_LAYOUT_INFORMATION_EX));
driver_layout_info.Mbr.Signature = sign;
driver_layout_info.PartitionCount = 1;
driver_layout_info.PartitionStyle = PARTITION_STYLE_MBR;
PARTITION_INFORMATION_EX part_info;
PARTITION_INFORMATION_MBR mbr_info;
part_info.StartingOffset.QuadPart = 32256;
part_info.RewritePartition = TRUE;
part_info.PartitionLength.QuadPart = partition_size.QuadPart/2 * 4096;
part_info.PartitionNumber = 1;
part_info.PartitionStyle = PARTITION_STYLE_MBR;
mbr_info.BootIndicator = TRUE;
mbr_info.HiddenSectors = 32256 / 512;
mbr_info.PartitionType = PARTITION_FAT32;
mbr_info.RecognizedPartition = 1;
part_info.Mbr = mbr_info;
driver_layout_info.PartitionEntry[0] = part_info;
auto res_layout = DeviceIoControl(device_handle, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, &driver_layout_info, sizeof(driver_layout_info), NULL, 0, NULL, NULL);
Now, how do I partitionize this disk into two partitions? I want to create another partition out of the unpartitioned part of the disk(the other half basically). It says in the documentation is that PartitionEntry is an array of variable size(No, it is not it is an array of size 1.) Do I call set layout IOCTL for every partition I want to create? If so, how do you go about that? Is multi-partitioning possible through WINAPI interface?
P.S: I am aware that people usually invoke diskpart for this line of work.
Edit:
Adding second partition two layout was messing my stack up so I took another route (heap).
DWORD driver_layout_ex_len = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + sizeof(PARTITION_INFORMATION_EX); // one layout+partition + partition
PDRIVE_LAYOUT_INFORMATION_EX driver_layout_info = (PDRIVE_LAYOUT_INFORMATION_EX) std::calloc(1, driver_layout_ex_len);
driver_layout_info->Mbr.Signature = sign;
driver_layout_info->PartitionCount = 2;
driver_layout_info->PartitionStyle = PARTITION_STYLE_MBR;
// omitted here..
PARTITION_INFORMATION_EX part_info2;
part_info2.StartingOffset.QuadPart = 32256 + part_info.PartitionLength.QuadPart;
part_info2.RewritePartition = TRUE;
part_info2.PartitionLength.QuadPart = partition_size.QuadPart / 2 * 4096;
part_info2.PartitionNumber = 2;
part_info2.PartitionStyle = PARTITION_STYLE_MBR;
part_info2.Mbr = mbr_info;
driver_layout_info->PartitionEntry[0] = part_info;
driver_layout_info->PartitionEntry[1] = part_info2;
auto res_layout = DeviceIoControl(device_handle, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, driver_layout_info, driver_layout_ex_len, NULL, 0, NULL, NULL);
auto res_err = GetLastError();
Since it was overriding my device_handle I could not IOCTL at all. This improvement eliminated that. Do not forget to pass driver_layout_info instead of &driver_layout_info after this change.
It says in the documentation is that PartitionEntry is an array of
variable size(No, it is not it is an array of size 1.)
"Some Windows structures are variable-sized,
beginning with a fixed header, followed by
a variable-sized array. When these structures
are declared,
they often declare an array of size 1 where the
variable-sized array should be." Refer to #Raymond blog.
Here DRIVE_LAYOUT_INFORMATION_EX structure is an example:
typedef struct _DRIVE_LAYOUT_INFORMATION_EX {
DWORD PartitionStyle;
DWORD PartitionCount;
union {
DRIVE_LAYOUT_INFORMATION_MBR Mbr;
DRIVE_LAYOUT_INFORMATION_GPT Gpt;
} DUMMYUNIONNAME;
PARTITION_INFORMATION_EX PartitionEntry[1];
} DRIVE_LAYOUT_INFORMATION_EX, *PDRIVE_LAYOUT_INFORMATION_EX;
With this declaration, you would allocate memory for one such
variable-sized DRIVE_LAYOUT_INFORMATION_EX structure like this:
PDRIVE_LAYOUT_INFORMATION_EX driver_layout_info = (PDRIVE_LAYOUT_INFORMATION_EX)malloc(FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[NumberOfPartitions]));
You would initialize the structure like this (Use 2 partitions as example):
DWORD NumberOfPartitions = 2;
LARGE_INTEGER partition_size;
partition_size.QuadPart = 0xF00;
PARTITION_INFORMATION_MBR mbr_info;
mbr_info.BootIndicator = TRUE;
mbr_info.HiddenSectors = 32256 / 512;
mbr_info.PartitionType = PARTITION_FAT32;
mbr_info.RecognizedPartition = TRUE;
PDRIVE_LAYOUT_INFORMATION_EX driver_layout_info = (PDRIVE_LAYOUT_INFORMATION_EX)malloc(FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[NumberOfPartitions]));
for (DWORD Index = 0; Index < NumberOfPartitions ; Index++) {
driver_layout_info->PartitionEntry[Index].PartitionStyle = PARTITION_STYLE_MBR;
driver_layout_info->PartitionEntry[Index].PartitionNumber = Index + 1;
driver_layout_info->PartitionEntry[Index].RewritePartition = TRUE;
driver_layout_info->PartitionEntry[Index].PartitionLength.QuadPart = partition_size.QuadPart / 2 * 4096;
driver_layout_info->PartitionEntry[Index].Mbr = mbr_info;
}
driver_layout_info->Mbr.Signature = sign;
driver_layout_info->PartitionCount = 1;
driver_layout_info->PartitionStyle = PARTITION_STYLE_MBR;
driver_layout_info->PartitionEntry[0].StartingOffset.QuadPart = 32256;
driver_layout_info->PartitionEntry[1].StartingOffset.QuadPart = 32256 + driver_layout_info->PartitionEntry->StartingOffset.QuadPart;
DWORD driver_layout_ex_len = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + sizeof(PARTITION_INFORMATION_EX);
Call free(driver_layout_info); after you use completely.
I am currently messing the first time with iOS and Objective-C++. Im coming from C/C++ so please excuse my bad coding in the below examples.
I am trying to live stream the microphone audio of my iOS device over tcp, the iOS device is acting as server and sends the data to all clients that connect.
To do so, I am first using AVCaptureDevice and requestAccessForMediaType:AVMediaTypeAudio to request access to the microphone (along with the needed entry in the Info.plist).
Then I create a AVCaptureSession* using the below function:
AVCaptureSession* createBasicARecordingSession(aReceiver* ObjectReceivingAudioFrames){
AVCaptureSession* s = [[AVCaptureSession alloc] init];
AVCaptureDevice* aDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
AVCaptureDeviceInput* aInput = NULL;
if([aDevice lockForConfiguration:NULL] == YES && aDevice){
aInput = [AVCaptureDeviceInput deviceInputWithDevice:aDevice error:nil];
[aDevice unlockForConfiguration];
}
else if(!aDevice){
fprintf(stderr, "[d] could not create device. (%p)\n", aDevice);
return NULL;
}
else{
fprintf(stderr, "[d] could not lock device.\n");
return NULL;
}
if(!aInput){
fprintf(stderr, "[d] could not create input.\n");
return NULL;
}
AVCaptureAudioDataOutput* aOutput = [[AVCaptureAudioDataOutput alloc] init];
dispatch_queue_t aQueue = dispatch_queue_create("aQueue", NULL);
if(!aOutput){
fprintf(stderr, "[d] could not create output.\n");
return NULL;
}
[aOutput setSampleBufferDelegate:ObjectReceivingAudioFrames queue:aQueue];
// the below line does only work on macOS
//aOutput.audioSettings = settings;
[s beginConfiguration];
if([s canAddInput:aInput]){
[s addInput:aInput];
}
else{
fprintf(stderr, "[d] could not add input.\n");
return NULL;
}
if([s canAddOutput:aOutput]){
[s addOutput:aOutput];
}
else{
fprintf(stderr, "[d] could not add output.\n");
return NULL;
}
[s commitConfiguration];
return s;
}
The aReceiver* class (?) is defined below and receives the audio frames provided by the AVCaptureAudioDataOutput* object. The frames are stored inside a std::vector.
(im adding the code as image as I could not get it formatted right...)
Then I start the AVCaptureSession* using [audioSession start]
When a tcp client connects I first create a AudioConverterRef and two AudioStreamBasicDescription to convert the audio frames to AAC, see below:
AudioStreamBasicDescription asbdIn, asbdOut;
AudioConverterRef converter;
asbdIn.mFormatID = kAudioFormatLinearPCM;
//asbdIn.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
asbdIn.mFormatFlags = 12;
asbdIn.mSampleRate = 44100;
asbdIn.mChannelsPerFrame = 1;
asbdIn.mFramesPerPacket = 1;
asbdIn.mBitsPerChannel = 16;
//asbdIn.mBytesPerFrame = (asbdIn.mBitsPerChannel / 8) * asbdIn.mBitsPerChannel;
asbdIn.mBytesPerFrame = 2;
asbdIn.mBytesPerPacket = asbdIn.mBytesPerFrame;
asbdIn.mReserved = 0;
asbdOut.mFormatID = kAudioFormatMPEG4AAC;
asbdOut.mFormatFlags = 0;
asbdOut.mSampleRate = 44100;
asbdOut.mChannelsPerFrame = 1;
asbdOut.mFramesPerPacket = 1024;
asbdOut.mBitsPerChannel = 0;
//asbdOut.mBytesPerFrame = (asbdOut.mBitsPerChannel / 8) * asbdOut.mBitsPerChannel;
asbdOut.mBytesPerFrame = 0;
asbdOut.mBytesPerPacket = asbdOut.mBytesPerFrame;
asbdOut.mReserved = 0;
OSStatus err = AudioConverterNew(&asbdIn, &asbdOut, &converter);
Then I create a AudioBufferList* to store the encoded frames:
while(audioInput.locked){ // audioInput is my aReceiver*
usleep(0.2 * 1000000);
}
audioInput.locked = true;
UInt32 RequestedPackets = 8192;
//AudioBufferList* aBufferList = (AudioBufferList*)malloc(sizeof(AudioBufferList));
AudioBufferList* aBufferList = static_cast<AudioBufferList*>(calloc(1, offsetof(AudioBufferList, mBuffers) + (sizeof(AudioBuffer) * 1)));
aBufferList->mNumberBuffers = 1;
aBufferList->mBuffers[0].mNumberChannels = asbdIn.mChannelsPerFrame;
aBufferList->mBuffers[0].mData = static_cast<void*>(calloc(RequestedPackets, asbdIn.mBytesPerFrame));
aBufferList->mBuffers[0].mDataByteSize = asbdIn.mBytesPerFrame * RequestedPackets;
Then I go through the frames stored in the std::vector mentioned earlier and pass them to AudioConverterFillComplexBuffer(). After conversion, i concat all encoded frames into one NSMutableData which I then write() to the socket connected to the client.
long aBufferListSize = audioInput.aBufferList.size();
while(aBufferListSize > 0){
err = AudioConverterFillComplexBuffer(converter, feedAFrames, static_cast<void*>(&audioInput.aBufferList[audioInput.aBufferList.size() - aBufferListSize]), &RequestedPackets, aBufferList, NULL);
NSMutableData* encodedData = [[NSMutableData alloc] init];
long encodedDataLen = 0;
for(int i = 0; i < aBufferList->mNumberBuffers; i++){
Float32* frame = (Float32*)aBufferList->mBuffers[i].mData;
[encodedData appendBytes:frame length:aBufferList->mBuffers[i].mDataByteSize];
encodedDataLen += aBufferList->mBuffers[i].mDataByteSize;
}
unsigned char* encodedDataBytes = (unsigned char*)[encodedData bytes];
fprintf(stderr, "[d] got %li encoded bytes to send...\n", encodedDataLen);
long bytes = write(Client->GetFD(), encodedDataBytes, encodedDataLen);
fprintf(stderr, "[d] written %li of %li bytes.\n", bytes, encodedDataLen);
usleep(0.2 * 1000000);
aBufferListSize--;
}
audioInput.aBufferList.clear();
audioInput.locked = false;
Below is the feedAFrames() callback used in the AudioConverterFillComplexBuffer() call:
(again this is an image of the code, same reason as above)
Step 5 to 7 are repeated until the tcp connection is closed.
Each step runs without any noticeable error (I know I could include way better error handling here), and I do get data out of step 3 and 7. However it does not seem to be AAC what comes out at the end.
As im rather new to all of this, im really not sure what my error is, im sure there are several things I made wrong. It is kind of hard to find suitable example code of what I am trying to do, and the above is the best I could come up with until now with all that I have found paired with the apple dev documentation.
I hope someone might take some time to explain me what I did wrong and how I can get this to work. Thanks for reading until here!
Currently, I am trying hard to get a safearray of variants to work in my c++ code below. As you can see I call QueueInputReport which has a signature of (SAFEARRAY * psainputreport, UNIT timeoutduration):
CComSafeArray<VARIANT> savt;
//LONG j[5];
LONG length = 4;
//SafeArrayLock(psaValues);
for(LONG i = 0; i <= length; ++i)
{
//j[i] = i;
MessageBox(NULL,L"inputreport assigned to variable",NULL,NULL);
//VariantInit(&pDescriptorData[i]);
//pDescriptorData[i].vt = VT_UI1;
//pDescriptorData[i].bVal = inputreport[i];
//SafeArrayPutElement(psaValues,&i,&pDescriptorData[i]);
// VariantClear(&pDescriptorData[i]);
savt.Add(CComVariant(inputreport[i]));
}
//SafeArrayUnlock(psaValues);
MessageBox(NULL,L"data is successfully assigned to safearray",L"correct data format",NULL);
//FADF_STATIC+FADF_FIXEDSIZE+FADF_HAVEVARTYPE+FADF_VARIANT;
/* _TCHAR szBuffer2[100];
_stprintf_s(szBuffer2, _T("%i"),&psaValues->fFeatures);
MessageBox(NULL,L"safe array type",szBuffer2,NULL);*/
piSoftHidDevice1[devindex]->QueueInputReport(savt,8);
piSoftHidDevice1[devindex]->StartProcessing();
piSoftHidDevice1[devindex]->StopProcessing();
Edit: below is the code for queueinputreport which I needed to pass data to.
STDMETHODIMP CHIDDevice::QueueInputReport( SAFEARRAY* psaInputReport, UINT timeoutDuration )
/*++
Routine Description: Queues additional input reports
Arguments:
IdleTimeout - used to set the value of the log level
Return value:
S_OK
--*/
{
VARIANT * pArrayData = NULL;
UINT cbData = 5;
LONG lLBound = 0;
LONG lUBound = 0;
HRESULT hr = S_OK;
HID_INPUT_REPORT inputReport;
BOOLEAN result = TRUE;
// Initialize Structure
inputReport.timeout = timeoutDuration;
inputReport.cbInputReport = 0;
inputReport.pbInputReport = NULL;
MessageBox(NULL,L"report initialized",L"initial report",NULL);
// Get SAFEARRAY size
IfFailHrGo(SafeArrayGetLBound(psaInputReport, 1, &lLBound));
IfFailHrGo(SafeArrayGetUBound(psaInputReport, 1, &lUBound));
IfFalseHrGo(lUBound > lLBound, E_UNEXPECTED);
cbData = lUBound - lLBound + 1;
//psaInputReport->fFeatures = 0x892;
//psaInputReport->fFeatures = 0x892;
inputReport.pbInputReport = (BYTE*)CoTaskMemAlloc( cbData * sizeof(BYTE) );
_TCHAR szBuffer3[100];
_stprintf_s(szBuffer3, _T("%i"), &psaInputReport->fFeatures);
MessageBox(NULL,L"array content features",szBuffer3,NULL);
// If the memory Allocation fails, then fail and exit
if( inputReport.pbInputReport == NULL )
{
hr = E_UNEXPECTED;
goto Exit;
}
//void HUGEP** cast orginally
IfFailHrGo( SafeArrayAccessData( psaInputReport,
reinterpret_cast<void HUGEP**>(&pArrayData) ) );
// Step through the SAFEARRAY and populating only BYTE input report
// and bail out if the type is not correct
for( LONG i = 0; i <= lUBound; ++i )
{
if (pArrayData[i].vt == VT_UI1)
{
inputReport.pbInputReport[i] = pArrayData[i].bVal;
}
else
{
hr = E_FAIL;
goto Exit;
}
}
SafeArrayUnaccessData(psaInputReport);
inputReport.cbInputReport = cbData;
//MessageBox(NULL,L"report being sent next",L"sent report",NULL);
// Add the report to the input queue (does a shallow copy so no need to free the array data)
result = m_InputReportQueue.insert( inputReport );
if (result == FALSE)
{
MessageBox(NULL,L"failed to queue the input",NULL,NULL);
hr = E_FAIL;
}
return hr;
Exit:
SafeArrayUnaccessData(psaInputReport);
if( FAILED(hr) )
{
CoTaskMemFree(inputReport.pbInputReport);
}
return hr;
}
Edit: The problem is I need the fFeatures to equal 2194 and it is currently its a very high number. What could I be doing wrong?
In vbscript, I have some working code for the queueinputreport:
........(too numerous code to list here but it represents the device I am sending input to (i.e. device #1,#2,#3))
Here's some more information on the fFeatures Iam talking about:
http://msdn.microsoft.com/en-us/library/cc237824.aspx
Dim inputreport(5)
inputreport(0) = CByte(0)
inputreport(1) = CByte(100)
inputreport(2) = CByte(100)
inputreport(3) = CByte(0)
inputreport(4) = Cbyte(0)
pisofthiddevice1(i).QueueInputReport(inputreport, 8)
However, when I try replicating this in C++ above it does not work.