Windows media foundation enumerating Camera devices - c++

I would like to enumerate the camera devices on my computer using Windows Media Foundation, I used the code on Microsoft : http://msdn.microsoft.com/en-us/library/windows/desktop/dd940326(v=vs.85).aspx
I reproduced the same code they use here : http://msdn.microsoft.com/en-us/library/windows/desktop/ee663604(v=vs.85).aspx
When I used their code I get my webcam device name, however my code doesn't find any camera capture device. I'm enable to find why.
Here is the code :
#pragma once
#include <new>
#include <windows.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <Wmcodecdsp.h>
#include <assert.h>
#include <Dbt.h>
#include <shlwapi.h>
#include <mfplay.h>
#include <iostream>
const UINT WM_APP_PREVIEW_ERROR = WM_APP + 1; // wparam = HRESULT
class DeviceList
{
UINT32 m_cDevices; // contains the number of devices
IMFActivate **m_ppDevices; // contains properties about each device
public:
DeviceList() : m_ppDevices(NULL), m_cDevices(0)
{
}
~DeviceList()
{
Clear();
}
UINT32 Count() const { return m_cDevices; }
void Clear();
HRESULT EnumerateDevices();
HRESULT GetDevice(UINT32 index, IMFActivate **ppActivate);
HRESULT GetDeviceName(UINT32 index, WCHAR **ppszName);
};
#include "DeviceList.h"
/*
* A templated Function SafeRelease releasing pointers memories
* #param ppT the pointer to release
*/
template <class T> void SafeRelease(T **ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}
/*
* A function which copy attribute form source to a destination
* # param pSrc is an Interface to store key/value pairs of an Object
* # param pDest is an Interface to store key/value pairs of an Object
* # param GUID is an unique identifier
* # return HRESULT return errors warning condition on windows
*/
HRESULT CopyAttribute(IMFAttributes *pSrc, IMFAttributes *pDest, const GUID& key);
/*
* A Method form DeviceList which clear the list of Devices
*/
void DeviceList::Clear()
{
for (UINT32 i = 0; i < m_cDevices; i++)
{
SafeRelease(&m_ppDevices[i]);
}
CoTaskMemFree(m_ppDevices);
m_ppDevices = NULL;
m_cDevices = 0;
}
/*
* A function which enumerate the list of Devices.
* # return HRESULT return errors warning condition on windows
*/
HRESULT DeviceList::EnumerateDevices()
{
HRESULT hr = S_OK;
IMFAttributes *pAttributes = NULL;
this->Clear();
// Initialize an attribute store. We will use this to
// specify the enumeration parameters.
std::cout << "Enumerate devices" << std::endl;
hr = MFCreateAttributes(&pAttributes, 1);
// Ask for source type = video capture devices
if (SUCCEEDED(hr))
{
std::cout << "Enumerate devices" << std::endl;
hr = pAttributes->SetGUID(
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
);
}
// Enumerate devices.
if (SUCCEEDED(hr))
{
std::cout << "Enumerate devices:" << m_cDevices << std::endl;
hr = MFEnumDeviceSources(pAttributes, &m_ppDevices, &m_cDevices);
}
SafeRelease(&pAttributes);
return hr;
}
/*
* A function which copy attribute form source to a destination
* # param index the index in an array
* # param ppActivate is an Interface to store key/value pairs of an Object
* # return HRESULT return errors warning condition on windows
*/
HRESULT DeviceList::GetDevice(UINT32 index, IMFActivate **ppActivate)
{
if (index >= Count())
{
return E_INVALIDARG;
}
*ppActivate = m_ppDevices[index];
(*ppActivate)->AddRef();
return S_OK;
}
/*
* A function which get the name of the devices
* # param index the index in an array
* # param ppszName Name of the device
*/
HRESULT DeviceList::GetDeviceName(UINT32 index, WCHAR **ppszName)
{
std::cout << "Get Device name" << std::endl;
if (index >= Count())
{
return E_INVALIDARG;
}
HRESULT hr = S_OK;
hr = m_ppDevices[index]->GetAllocatedString(
MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
ppszName,
NULL
);
return hr;
}
#include <iostream>
#include "DeviceList.h"
HRESULT UpdateDeviceList()
{
HRESULT hr = S_OK;
WCHAR *szFriendlyName = NULL;
DeviceList g_devices;
g_devices.Clear();
hr = g_devices.EnumerateDevices();
if (FAILED(hr)) { goto done; }
std::cout << "Nb devices found:"<< g_devices.Count() << std::endl;
for (UINT32 iDevice = 0; iDevice < g_devices.Count(); iDevice++)
{
//std::cout << "" << std::endl;
hr = g_devices.GetDeviceName(iDevice, &szFriendlyName);
if (FAILED(hr)) { goto done; }
std::cout << szFriendlyName << std::endl;
// The list might be sorted, so the list index is not always the same as the
// array index. Therefore, set the array index as item data.
CoTaskMemFree(szFriendlyName);
szFriendlyName = NULL;
}
std::cout << "End of EnumDeviceList" << std::endl;
done:
return hr;
}
int main()
{
std::cout <<"Main" << std::endl;
UpdateDeviceList();
while (1);
return 0;
}

You are expected to do MFStartup(MF_VERSION); before you start calling other Media Foundation API functions.
Then you print m_cDevices before it is getting initialized one line below by MFEnumDeviceSources.
std::cout << "Enumerate devices:" << m_cDevices << std::endl;
hr = MFEnumDeviceSources(pAttributes, &m_ppDevices, &m_cDevices);
Having this fixed, your code will start getting you the devices.

Related

Windows SAPI error : 'GetVersionExA': was declared deprecated

So all I want in life is to have a program where I can say "Hey Computer" and it responds with "Hello". So I set myself upon the task and after some research produced the code below yet whenever I try to compile it through Visual Studio 2017 on Windows 10 I get this error: 'GetVersionExA': was declared deprecated but I don't understand because I don't call that function anywhere in my code.
#include <sphelper.h>
#include <sapi.h>
#include <iostream>
#include <string>
#include <vector>
#include <locale>
const ULONGLONG grammarId = 0;
const wchar_t* ruleName1 = L"ruleName1";
int start_listening(const std::string& word);
ISpRecoGrammar* init_grammar(ISpRecoContext* recoContext, const std::string& command);
void get_text(ISpRecoContext* reco_context);
void check_result(const HRESULT& result);
ISpVoice * pVoice = NULL;
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
inline std::wstring s2w(const std::string &s, const std::locale &loc = std::locale())
{
typedef std::ctype<wchar_t> wchar_facet;
std::wstring return_value;
if (s.empty())
{
return return_value;
}
if (std::has_facet<wchar_facet>(loc))
{
std::vector<wchar_t> to(s.size() + 2, 0);
std::vector<wchar_t>::pointer toPtr = &to[0];
const wchar_facet &facet = std::use_facet<wchar_facet>(loc);
if (0 != facet.widen(s.c_str(), s.c_str() + s.size(), toPtr))
{
return_value = to.data();
}
}
return return_value;
}
int main(int argc, char** argv)
{
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
std::string hello = "hello";
start_listening("Hey computer");
hr = pVoice->Speak(s2w(hello).c_str(), 0, NULL);
return EXIT_SUCCESS;
}
// This function exits when the word passed as parameter is said by the user
int start_listening(const std::string& word)
{
// Initialize COM library
if (FAILED(::CoInitialize(nullptr))) {
return EXIT_FAILURE;
}
std::cout << "You should start Windows Recognition" << std::endl;
std::cout << "Just say \"" << word << "\"" << std::endl;
HRESULT hr;
ISpRecognizer* recognizer;
hr = CoCreateInstance(CLSID_SpSharedRecognizer,
nullptr, CLSCTX_ALL, IID_ISpRecognizer,
reinterpret_cast<void**>(&recognizer));
check_result(hr);
ISpRecoContext* recoContext;
hr = recognizer->CreateRecoContext(&recoContext);
check_result(hr);
// Disable context
hr = recoContext->Pause(0);
check_result(hr);
ISpRecoGrammar* recoGrammar = init_grammar(recoContext, word);
hr = recoContext->SetNotifyWin32Event();
check_result(hr);
HANDLE handleEvent;
handleEvent = recoContext->GetNotifyEventHandle();
if (handleEvent == INVALID_HANDLE_VALUE) {
check_result(E_FAIL);
}
ULONGLONG interest;
interest = SPFEI(SPEI_RECOGNITION);
hr = recoContext->SetInterest(interest, interest);
check_result(hr);
// Activate Grammar
hr = recoGrammar->SetRuleState(ruleName1, 0, SPRS_ACTIVE);
check_result(hr);
// Enable context
hr = recoContext->Resume(0);
check_result(hr);
// Wait for reco
HANDLE handles[1];
handles[0] = handleEvent;
WaitForMultipleObjects(1, handles, FALSE, INFINITE);
get_text(recoContext);
std::cout << "Hello user" << std::endl;
recoGrammar->Release();
::CoUninitialize();
system("PAUSE");
return EXIT_SUCCESS;
}
/**
* Create and initialize the Grammar.
* Create a rule for the grammar.
* Add word to the grammar.
*/
ISpRecoGrammar* init_grammar(ISpRecoContext* recoContext, const std::string& command)
{
HRESULT hr;
SPSTATEHANDLE sate;
ISpRecoGrammar* recoGrammar;
hr = recoContext->CreateGrammar(grammarId, &recoGrammar);
check_result(hr);
WORD langId = MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH);
hr = recoGrammar->ResetGrammar(langId);
check_result(hr);
// TODO: Catch error and use default langId => GetUserDefaultUILanguage()
// Create rules
hr = recoGrammar->GetRule(ruleName1, 0, SPRAF_TopLevel | SPRAF_Active, true, &sate);
check_result(hr);
// Add a word
const std::wstring commandWstr = std::wstring(command.begin(), command.end());
hr = recoGrammar->AddWordTransition(sate, NULL, commandWstr.c_str(), L" ", SPWT_LEXICAL, 1, nullptr);
check_result(hr);
// Commit changes
hr = recoGrammar->Commit(0);
check_result(hr);
return recoGrammar;
}
void get_text(ISpRecoContext* reco_context)
{
const ULONG maxEvents = 10;
SPEVENT events[maxEvents];
ULONG eventCount;
HRESULT hr;
hr = reco_context->GetEvents(maxEvents, events, &eventCount);
// Warning hr equal S_FALSE if everything is OK
// but eventCount < requestedEventCount
if (!(hr == S_OK || hr == S_FALSE)) {
check_result(hr);
}
ISpRecoResult* recoResult;
recoResult = reinterpret_cast<ISpRecoResult*>(events[0].lParam);
wchar_t* text;
hr = recoResult->GetText(SP_GETWHOLEPHRASE, SP_GETWHOLEPHRASE, FALSE, &text, NULL);
check_result(hr);
CoTaskMemFree(text);
}
void check_result(const HRESULT& result)
{
if (result == S_OK) {
return;
}
std::string message;
switch (result) {
case E_INVALIDARG:
message = "One or more arguments are invalids.";
case E_ACCESSDENIED:
message = "Acces Denied.";
case E_NOINTERFACE:
message = "Interface does not exist.";
case E_NOTIMPL:
message = "Not implemented method.";
case E_OUTOFMEMORY:
message = "Out of memory.";
case E_POINTER:
message = "Invalid pointer.";
case E_UNEXPECTED:
message = "Unexpecter error.";
case E_FAIL:
message = "Failure";
default:
message = "Unknown : " + std::to_string(result);
}
throw std::exception(message.c_str());
}
It is suppressable with a pragma:
#pragma warning(disable:4996)
#include <sphelper.h>
#pragma warning(default: 4996)
GetVersionEx is being used by the header sphelper.h which you're including. It's using it to check that the function SpGetDescription() is running on Vista or later. You could probably work around this issue by targeting the 8.1 SDK version instead of 10. However, it's bad that the shipped MS SAPI API in the Windows 10 SDK is using functions which are deprecated in Windows 10.. I'd say this is a MS issue.
Alternately this would work:
#define FKG_FORCED_USAGE 1
#include <sphelper.h>
#undef FKG_FORCED_USAGE

How do you get the NamePropertyId of a UIAutomationElement by hovering the cursor?

I am trying to build my own screen reader using UIAutomation. I want my program to return the NameProperty of the element that is pointed by my cursor
This is what I have done so far; this is just sample code anyway:
#include <iostream>
#include <windows.h>
#include <UIAutomation.h>
const int MAX_WND_TEXT = 60;
IUIAutomation *automation = NULL;
BOOL InitializeUIAutomation(IUIAutomation **pAutomation)
{
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(__uuidof(CUIAutomation), NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IUIAutomation), (void**)pAutomation);
return (SUCCEEDED(hr));
}
int main()
{
POINT p;
IUIAutomationElement *elem;
wchar_t wndName[MAX_WND_TEXT];
BOOL stat = InitializeUIAutomation(&automation);
while (true)
{
if (stat)
{
GetCursorPos(&p);
HRESULT hr = automation->ElementFromPoint(p, &elem);
if (SUCCEEDED(hr))
{
HRESULT hr = elem->GetCurrentPropertyValue(UIA_NamePropertyId,
(VARIANT*)wndName);
if (SUCCEEDED(hr))
std::cout << wndName << std::endl;
else
wndName[0] = '\0';
}
else
std::cout << "No element selected." << std::endl;
Sleep(100);
elem->Release();
}
}
automation->Release();
CoUninitialize();
return 0;
}
Now the problem is I can't make it to print the values I wanted. The program just output a specific hex number. And also I'm still a beginner in UIAutomation so I am still lost.
Can you help me or give me tips how to solve my problem?
Solved my problem using this code.
#include <iostream>
#include <string>
#include <Windows.h>
#include <UIAutomation.h>
BOOL InitializeUIAutomation(IUIAutomation **automation)
{
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(__uuidof(CUIAutomation), NULL,
CLSCTX_INPROC_SERVER, __uuidof(IUIAutomation),
(void**)automation);
return (SUCCEEDED(hr));
}
int main()
{
IUIAutomation *automation = NULL;
IUIAutomationElement *elem = NULL;
BOOL stat = InitializeUIAutomation(&automation);
POINT mousePt;
BSTR elemName = NULL;
if (stat)
{
while(true)
{
GetCursorPos(&mousePt);
HRESULT hr = automation->ElementFromPoint(mousePt, &elem);
if (SUCCEEDED(hr) && elem != NULL)
{
elem->get_CurrentName(&elemName);
std::wstring ws(elemName, SysStringLen(elemName));
std::wcout << ws << std::endl;
}
SysFreeString(elemName);
elem->Release();
Sleep(200);
}
}
automation->Release();
CoUninitialize();
return 0;
}
The hex numbers printed was the BSTR header after all. Solve my problem by converting BSTR to wstring.

Kinect SDK 2.0 handle and acquire depth frame

I am actually working with the Kinect V2 (the one for Xbox One) and I am trying to have a depth stream. I want to see what the depth sensor of Kinect sees. But I don't succeed to open a stream. I only succeed to open a single frame with another piece of code, but not a video. With a few research, I have tried to use handles, but the code I wrote don't printe on the screen the line 'stream' put at the end of the code. I am working on VS2012, the code is in C++.
I think I have this because I don't know how to use correcty an handle... If anybody could help me and explain to me what an handle is instead of a kind of pointer to something, it would be great. Thank you
Here is my code :
HRESULT hr=S_OK;
WAITABLE_HANDLE *stream=nullptr;
IKinectSensor* kinectSensor=nullptr;
if( SUCCEEDED(hr) )
{
std::cout << "Success IKinectSensor::GetDefaultSensor" << std::endl;
}
else
{
std::cout << "Failed IKinectSensor::GetDefaultSensor" << std::endl;
}
std::cout << "Opening sensors" << std::endl;
if(kinectSensor != NULL)
{
hr = kinectSensor->Open();
Sleep(sleeptime*5);
if( SUCCEEDED( hr ) )
{
std::cout << "Success IKinectSensor::Open" << std::endl;
}
else
{
std::cout << "Failed IKinectSensor::Open" << std::endl;
}
}
}
hr = kinectSensor->OpenMultiSourceFrameReader(FrameSourceTypes_Depth | FrameSourceTypes_Color , &multiSourceReader);
if( SUCCEEDED(hr) )
{
std::cout << "reader open" << std::endl;
hr = multiSourceReader->SubscribeMultiSourceFrameArrived(stream);
if( SUCCEEDED(hr) )
{
std::cout << "stream" << std::endl;
}
}
I didn't use a handle. See the below code snippet for getting the depth frame from a multisource frame reader and display it with OpenCV.
#include <Kinect.h>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
// helper function
template <class Interface> inline void safe_release(Interface **ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}
bool setup_kinect_sensor_and_acquire_frame()
{
IKinectSensor* kinect_sensor
// initialize kinect sensor
HRESULT hr = GetDefaultKinectSensor(&kinect_sensor);
if (FAILED(hr) || !kinect_sensor)
{
safe_release(&p_multisource_frame);
return false;
}
kinect_sensor->Open();
if (FAILED(hr))
{
return false;
}
// initialize kinect multisource frame reader
IMultiSourceFrameReader* kinect_multisource_reader;
hr = kinect_sensor->OpenMultiSourceFrameReader(FrameSourceTypes_Depth, &kinect_multisource_reader;);
if (FAILED(hr))
{
safe_release(&kinect_multisource_reader);
return false;
}
// acquire multisource frame
IMultiSourceFrame* p_multisource_frame = NULL;
HRESULT hr = kinect_multisource_reader->AcquireLatestFrame(&p_multisource_frame);
if (FAILED(hr))
{
safe_release(&p_multisource_frame);
return false;
}
// get depth frame
IDepthFrameReference* p_depth_frame_ref = NULL;
hr = p_multisource_frame->get_DepthFrameReference(&p_depth_frame_ref);
if (FAILED(hr))
{
safe_release(&p_depth_frame_ref);
return false;
}
IDepthFrame* p_depth_frame = NULL;
IFrameDescription* p_frame_description = NULL;
int width = 0;
int height = 0;
unsigned short depth_min_distance = 0;
unsigned short depth_max_distance = 0;
unsigned short* p_depth_buffer = NULL;
hr = p_depth_frame_ref->AcquireFrame(&p_depth_frame);
if (SUCCEEDED(hr))
{
hr = p_depth_frame->get_FrameDescription(&p_frame_description);
}
if (SUCCEEDED(hr))
{
hr = p_frame_description->get_Width(&width);
}
if (SUCCEEDED(hr))
{
hr = p_frame_description->get_Height(&height);
}
if (width != 512 || height != 424)
{
safe_release(&p_depth_frame);
safe_release(&p_frame_description);
return false;
}
// process depth frame
if (SUCCEEDED(hr))
{
hr = p_depth_frame->get_DepthMinReliableDistance(&depth_min_distance);
}
if (SUCCEEDED(hr))
{
hr = p_depth_frame->get_DepthMaxReliableDistance(&depth_max_distance);
}
if (SUCCEEDED(hr))
{
int size = 512 * 424;
p_depth_buffer = new unsigned short[size];
hr = p_depth_frame->CopyFrameDataToArray(size, p_depth_buffer);
if (SUCCEEDED(hr))
{
cv::Mat depth_map(cv::Size(DEPTH_WIDTH, DEPTH_HEIGHT), CV_16UC1, p_depth_buffer);
double scale = 255.0 / (depth_max_distance - depth_min_distance);
depth_map.convertTo(depth_frame, CV_8UC1, scale);
cv::imshow("depth", depth_map);
}
}
// Clean up depth frame
safe_release(&p_depth_frame_ref);
safe_release(&p_depth_frame);
safe_release(&p_frame_description);
if (p_depth_buffer != NULL) {
delete[] p_depth_buffer;
p_depth_buffer = NULL;
}
if (FAILED(hr))
{
return false;
}
else
{
return true;
}
}

IMFActivate::ActivateObject return error code "CoInitialize has not been called."

I'm writing a simple multimedia application in Visual Studio 2013 and I need to enumerate camera devices connected to my computer and create a media source object to link to one of them. I use Media Foundation SDK and tried to run the guide here: https://msdn.microsoft.com/en-us/library/windows/desktop/dd940326(v=vs.85).aspx :
#include <Mfapi.h>
#include <mfidl.h>
#include <mfobjects.h>
#include <iostream>
#pragma comment(lib, "Mfplat")
#pragma comment(lib, "Mf")
template <class T> void SafeRelease(T **ppT) {
if (*ppT) {
(*ppT)->Release();
*ppT = NULL;
}
}
HRESULT CreateVideoDeviceSource(IMFMediaSource **ppSource) {
*ppSource = NULL;
IMFMediaSource *pSource = NULL;
IMFAttributes *pAttributes = NULL;
IMFActivate **ppDevices = NULL;
// Create an attribute store to specify the enumeration parameters.
HRESULT hr = MFCreateAttributes(&pAttributes, 1);
if (FAILED(hr))
{
goto done;
}
// Source type: video capture devices
hr = pAttributes->SetGUID(
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
);
if (FAILED(hr))
{
goto done;
}
// Enumerate devices.
UINT32 count;
hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count);
if (FAILED(hr))
{
goto done;
}
if (count == 0)
{
hr = E_FAIL;
goto done;
}
// Create the media source object.
hr = ppDevices[0]->ActivateObject(IID_PPV_ARGS(&pSource));
if (FAILED(hr))
{
std::cout << "Failed to create device object" << hr <<std::endl;
goto done;
}
*ppSource = pSource;
(*ppSource)->AddRef();
DWORD chs;
(*ppSource)->GetCharacteristics(&chs);
std::cout << chs << std::endl;
done:
SafeRelease(&pAttributes);
for (DWORD i = 0; i < count; i++)
{
SafeRelease(&ppDevices[i]);
}
CoTaskMemFree(ppDevices);
SafeRelease(&pSource);
return hr;
}
int main(int argc, char* argv[]) {
IMFMediaSource* ppSource;
CreateVideoDeviceSource(&ppSource);
std::cout << "END" << std::endl;
return 0;
}
The problem is that this part of the code :
// Create the media source object.
hr = ppDevices[0]->ActivateObject(IID_PPV_ARGS(&pSource));
if (FAILED(hr))
{
goto done;
}
fails to create a media source object(the HRESULT returned is 0x800401F0 (CO_E_NOTINITIALIZED)--"CoInitialize has not been called.
"). What does the error code mean and What could be the problem causing the failure ? I'm using WIN8.1.
Com Libraries need to be initialized for each thread, through either of
CoInitialize
CoInitializeEx
OleInitialize
depending on which services are to be used in this thread.
Do this at the start of your program, for all threads that use COM, and don't forget to call the respective Uninitialize function

How to fill the SafeArray with double datatype values using SafeArrayPutElement

I get E_INVALIDARG error
STDMETHODIMP CDocumentController::HasPrivEventCode(double dUserId,double dPosCd,double dPPRCd,SAFEARRAY** pEventCode)
{
// TODO: Add your implementation code here
long lElements; // number of elements in the array
long lCount;
HRESULT lResult; // return code for OLE functions
double *pArrayElements; // pointer to the elements of the array
// checking if it is a one-dimensional array
if ( (*pEventCode)->cDims != 1 ) return(E_FAIL);
// checking if it is an array of double
if ( (*pEventCode)->cbElements != 8 ) return(E_FAIL);
// how many elements are there in the array
lElements=(*pEventCode)->rgsabound[0].cElements;
// locking the array before using its elements
lResult=SafeArrayLock(*pEventCode);
if (lResult != S_OK) return(E_FAIL);
// using the array
pArrayElements=(double*) (*pEventCode)->pvData;
CMap<double,double,bool,bool> mapEventCds;
for (lCount=0; lCount<lElements; lCount++)
{
double lVal = pArrayElements[lCount];
mapEventCds.SetAt(lVal, false);
}
CheckPrivViewResultEventCds(dUserId, dPosCd, dPPRCd, mapEventCds);
long iEventCdIdx(0);
double dEventCd(0.0);
bool bPriv(false);
POSITION pos(mapEventCds.GetStartPosition());
INT_PTR nEventCnt(mapEventCds.GetCount());
double* arrEventCdsWithPriv = new double[nEventCnt];
VARIANT vt;
//(*pEventCode)->pvData = NULL;
lResult=SafeArrayUnlock(*pEventCode);
HRESULT hr = SafeArrayDestroyData(*pEventCode);
for(INT_PTR count(0); count < nEventCnt; ++count)
{
mapEventCds.GetNextAssoc(pos, dEventCd, bPriv);
if (bPriv)
{
vt.vt = VT_R8;
vt.dblVal = dEventCd;
hr = SafeArrayPutElement(*pEventCode, &iEventCdIdx, &dEventCd);
iEventCdIdx++;
}
}
// Empty the CMap
mapEventCds.RemoveAll();
// releasing the array
lResult=SafeArrayUnlock(*pEventCode);
return S_OK;
}
*pEventCode is my safearray... dEventCd is the 'double' value...I want to insert the dEventCd values to my *pEventCode safearray one by one when (bPriv) is true... Please help
I don't have experience with the APIs you are using. However, I was able to throw together this little test app which creates a SAFEARRAY, puts the value of 2 into the first index, and then retrieves that value successfully. You'll see in the code below that there is a commented out section which includes a call to SafeArrayDestroyData. When that code is commented out, the app works; however, when you uncomment the code, suddenly the call to SafeArrayPutElement fails with E_INVALIDARG. I believe this is your problem. Don't call this method before putting elements into the SAFEARRAY
#include "stdafx.h"
#include <OaIdl.h>
#include <iostream>
#include <comdef.h>
#include <stdio.h>
int _tmain(int argc, _TCHAR* argv[])
{
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = 1;
SAFEARRAY FAR* psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
if (psa == NULL) {
std::cout << "Could not create safe array";
return 0;
}
auto hr = SafeArrayLock(psa);
_com_error lockErr(hr);
printf(lockErr.ErrorMessage());
std::cout << std::endl;
hr = SafeArrayUnlock(psa);
_com_error unlockErr(hr);
printf(unlockErr.ErrorMessage());
std::cout << std::endl;
//This block is causing the trouble!
/*
hr = SafeArrayDestroyData(psa);
_com_error destroyErr(hr);
printf(destroyErr.ErrorMessage());
std::cout << std::endl;
*/
LONG rgIndex = 0;
double d = 2.0;
hr = SafeArrayPutElement(psa, &rgIndex, &d);
_com_error putErr(hr);
printf(putErr.ErrorMessage());
std::cout << std::endl;
if (hr == S_OK) {
double out = 0;
hr = SafeArrayGetElement(psa, &rgIndex, &out);
_com_error getErr(hr);
printf(putErr.ErrorMessage());
std::cout << std::endl;
std::cout << "the value of the element retrieved was: " << out;
}
std::cin.get();
return 0;
}