Background
I am writing a command line C++ program with Visual Studio 2013 Community Edition. It connects to an Active Directory server via LDAP and retrieves a list of unique values in a couple of attributes (ex: office location, department).
Problem
The program compiles fine, but I encounter a memory access issue when I run it:
Unhandled exception at 0x74EDC6B1 (Wldap32.dll) in LdapSearchResultTest1.exe: 0xC0000005: Access violation reading location 0xCCCCCCCC.
This is first time I'm using C++ with an external library, so I'm not sure how to even approach debugging this (normally I write Java for Android). I've spent the better part of the day looking around SO and trying out ideas based on answers to similar questions, but I still have not been able to figure it out.
The exact issue lies with the last parameter in this function call:
// Do the search
int searchReturnCode = ldap_search_s(
ldapSession,
&searchBase[0],
LDAP_SCOPE_SUBTREE,
filter,
pAttributes,
0,
&pSearchResults); // Error is here
My code
My code is based on an example from the MSDN website, which I have reproduced after my code. Here is an SSCCE that demonstrates the issue:
#include<iostream>
#include<Windows.h>
#include<Winldap.h>
#include<WinBer.h>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
// Function headers
vector<string> get_unique_departments(LDAP*, char*, string);
vector<string> get_unique_office_locations(LDAP*, char*, string);
vector<string> get_unique_values_by_property(LDAP*, char*, string, string);
void print_list(string, vector<string>);
// Main function
int main(int argc, char* argv[]) {
/**
* Take AD connection arguments from Windows command line:
* - Server address
* - Server port
* - Username
* - Password
* - Search base(s) (space separated if there are multiple)
*
* Example call from Windows command line:
* > program.exe ad-test.example.com 389 joe#ad-test.example.com L3tM31n "OU=Development Team,DC=ad-test,DC=example,DC=com" "OU=Management Team,DC=ad-test,DC=example,DC=com"
*/
string serverAddress = argv[1];
int serverPort = atoi(argv[2]);
string username = argv[3];
string password = argv[4];
vector<string> searchBases;
for (int i = 0; i < argc; i++) {
searchBases.push_back(argv[i]);
}
// If debug build, print received parameters
#ifdef _DEBUG
cout << "Server address: " << serverAddress << endl
<< "Server port: " << serverPort << endl
<< "Username: " << username << endl
<< "Password: " << password << endl;
for (size_t i = 5; i < searchBases.size(); i++) {
cout << "Search base: " << searchBases.at(i) << endl;
}
cout << endl;
#endif
// Initiate LDAP connection to Active Directory
int ldapVersion = LDAP_VERSION3;
LDAP* ldapSession = ldap_init(&serverAddress[0], serverPort);
ldap_set_option(ldapSession, LDAP_OPT_PROTOCOL_VERSION, &ldapVersion);
ULONG ldapConnection = ldap_connect(ldapSession, nullptr);
// Bind user
int ldapBindResult = ldap_simple_bind_s(ldapSession, &username[0], &password[0]);
if (ldapBindResult != LDAP_SUCCESS) {
ldap_unbind(ldapSession);
#ifdef _DEBUG
cout << "Unable to connect to LDAP directory" << endl << endl;
#endif
}
else {
#ifdef _DEBUG
cout << "Connected to LDAP!" << endl << endl;
#endif
}
// The LDAP object filter
char* filter = "(&(objectCategory=person)(objectClass=user))";
// Get lists of departments and offices
vector<string> departments, offices;
for (int i = 0; i < searchBases.size(); i++) {
vector<string> tempDepts = get_unique_departments(ldapSession, filter, searchBases.at(i));
vector<string> tempOffices = get_unique_office_locations(ldapSession, filter, searchBases.at(i));
for (int j = 0; j < tempDepts.size(); j++) {
departments.push_back(tempDepts.at(j));
}
for (int j = 0; j < tempOffices.size(); j++) {
offices.push_back(tempOffices.at(j));
}
}
// Print the lists
print_list("Departments", departments);
print_list("Offices", offices);
// Return
return 0;
}
// Retrieve a list of unique departments
vector<string> get_unique_departments(LDAP* session, char* filter, string searchBase) {
return get_unique_values_by_property(session, filter, searchBase, "department");
}
// Retrieve a list of unique office locations
vector<string> get_unique_office_locations(LDAP* session, char* filter, string searchBase) {
return get_unique_values_by_property(session, filter, searchBase, "office");
}
// Get a list of an attribute's unique values
vector<string> get_unique_values_by_property(LDAP* ldapSession, char* filter, string searchBase, string property) {
// Initialize some variables
vector<string> results;
char* pAttributes[1];
pAttributes[0] = &property[0];
LDAPMessage* pSearchResults = NULL;
int numResults = 0;
// Do the search
int searchReturnCode = ldap_search_s(
ldapSession,
&searchBase[0],
LDAP_SCOPE_SUBTREE,
filter,
pAttributes,
0,
&pSearchResults); // Error is here
// Process results
if (searchReturnCode == LDAP_SUCCESS) {
// Initialize some variables
LDAPMessage* pEntry = NULL;
char* pEntryDN = NULL;
char* sMsg;
BerElement* pBer = NULL;
char* pAttribute = NULL;
char** ppValue = NULL;
ULONG iValue = 0;
// Count the results
numResults = ldap_count_entries(ldapSession, pSearchResults);
// Loop over results
for (ULONG i = 0; i < numResults; i++) {
// Get the first/next entry
if (!i) {
pEntry = ldap_first_entry(ldapSession, pSearchResults);
}
else {
pEntry = ldap_next_entry(ldapSession, pEntry);
}
// Fail if unable to get entry
if (pEntry == NULL) {
results.clear();
return results;
}
// Loop over the attributes
pAttribute = ldap_first_attribute(ldapSession, pEntry, &pBer);
while (pAttribute != NULL) {
// Get and handle the values
ppValue = ldap_get_values(ldapSession, pEntry, pAttribute);
if (ppValue != NULL) {
iValue = ldap_count_values(ppValue);
if (find(results.begin(), results.end(), *ppValue) == results.end()) {
results.push_back(*ppValue);
}
// Memory management
ldap_value_free(ppValue);
ppValue = NULL;
ldap_memfree(pAttribute);
// Get the next attribute
pAttribute = ldap_next_attribute(ldapSession, pEntry, pBer);
}
}
// Memory management
if (pBer != NULL) {
ber_free(pBer, 0);
}
pBer = NULL;
}
}
// Free search result memory
if (pSearchResults != NULL) {
ldap_msgfree(pSearchResults);
}
// Return
return results;
}
// Print a vector-based list w/ header
void print_list(string header, vector<string> items) {
if (items.size() > 0) {
cout << header << ":" << endl;
for (int i = 0; i < items.size(); i++) {
cout << items.at(i) << endl;
}
cout << endl;
}
}
MSDN Example : Searching an LDAP Directory
From https://msdn.microsoft.com/en-us/library/aa367016%28v=vs.85%29.aspx
//----------------------------------------------
// Performing an LDAP Synchronous Search.
//
// Be aware that you must set the command prompt screen buffer
// height to 350 and the width to 90.
//-------------------------------------------------------------
#include <windows.h>
#include <winldap.h>
#include <winber.h>
#include <rpc.h>
#include <rpcdce.h>
#include <stdio.h>
//-----------------------------------------------------------
// This subroutine must have validated credentials (name and
// password) passed to it.
//-----------------------------------------------------------
int MyLDAPSearch(PCHAR pUserName, PCHAR pPassword)
{
//---------------------------------------------------------
// Initialize a session. LDAP_PORT is the default port, 389.
//---------------------------------------------------------
PCHAR hostName = "fabrikam.com";
LDAP* pLdapConnection = NULL;
pLdapConnection = ldap_init(hostName, LDAP_PORT);
if (pLdapConnection == NULL)
{
printf("ldap_init failed with 0x%x.\n",LdapGetLastError());
ldap_unbind(pLdapConnection);
return -1;
}
else
printf("ldap_init succeeded \n");
//-------------------------------------------------------
// Set session options.
//-------------------------------------------------------
ULONG version = LDAP_VERSION3;
ULONG numReturns = 10;
ULONG lRtn = 0;
// Set the version to 3.0 (default is 2.0).
lRtn = ldap_set_option(
pLdapConnection, // Session handle
LDAP_OPT_PROTOCOL_VERSION, // Option
(void*) &version); // Option value
if(lRtn == LDAP_SUCCESS)
printf("ldap version set to 3.0 \n");
else
{
printf("SetOption Error:%0lX\n", lRtn);
ldap_unbind(pLdapConnection);
return -1;
}
// Set the limit on the number of entries returned to 10.
lRtn = ldap_set_option(
pLdapConnection, // Session handle
LDAP_OPT_SIZELIMIT, // Option
(void*) &numReturns); // Option value
if(lRtn == LDAP_SUCCESS)
printf("Max return entries set to 10 \n");
else
{
printf("SetOption Error:%0lX\n", lRtn);
ldap_unbind(pLdapConnection);
return -1;
}
//--------------------------------------------------------
// Connect to the server.
//--------------------------------------------------------
lRtn = ldap_connect(pLdapConnection, NULL);
if(lRtn == LDAP_SUCCESS)
printf("ldap_connect succeeded \n");
else
{
printf("ldap_connect failed with 0x%lx.\n",lRtn);
ldap_unbind(pLdapConnection);
return -1;
}
//--------------------------------------------------------
// Bind with credentials.
//--------------------------------------------------------
PCHAR pMyDN = "DC=fabrikam,DC=com";
SEC_WINNT_AUTH_IDENTITY secIdent;
secIdent.User = (unsigned char*)pUserName;
secIdent.UserLength = strlen(pUserName);
secIdent.Password = (unsigned char*)pPassword;
secIdent.PasswordLength = strlen(pPassword);
secIdent.Domain = (unsigned char*)hostName;
secIdent.DomainLength = strlen(hostName);
secIdent.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
lRtn = ldap_bind_s(
pLdapConnection, // Session Handle
pMyDN, // Domain DN
(PCHAR)&secIdent, // Credential structure
LDAP_AUTH_NEGOTIATE); // Auth mode
if(lRtn == LDAP_SUCCESS)
{
printf("ldap_bind_s succeeded \n");
secIdent.Password = NULL; // Remove password pointer
pPassword = NULL; // Remove password pointer
}
else
{
printf("ldap_bind_s failed with 0x%lx.\n",lRtn);
ldap_unbind(pLdapConnection);
return -1;
}
//----------------------------------------------------------
// Perform a synchronous search of fabrikam.com for
// all user objects that have a "person" category.
//----------------------------------------------------------
ULONG errorCode = LDAP_SUCCESS;
LDAPMessage* pSearchResult;
PCHAR pMyFilter = "(&(objectCategory=person)(objectClass=user))";
PCHAR pMyAttributes[6];
pMyAttributes[0] = "cn";
pMyAttributes[1] = "company";
pMyAttributes[2] = "department";
pMyAttributes[3] = "telephoneNumber";
pMyAttributes[4] = "memberOf";
pMyAttributes[5] = NULL;
errorCode = ldap_search_s(
pLdapConnection, // Session handle
pMyDN, // DN to start search
LDAP_SCOPE_SUBTREE, // Scope
pMyFilter, // Filter
pMyAttributes, // Retrieve list of attributes
0, // Get both attributes and values
&pSearchResult); // [out] Search results
if (errorCode != LDAP_SUCCESS)
{
printf("ldap_search_s failed with 0x%0lx \n",errorCode);
ldap_unbind_s(pLdapConnection);
if(pSearchResult != NULL)
ldap_msgfree(pSearchResult);
return -1;
}
else
printf("ldap_search succeeded \n");
//----------------------------------------------------------
// Get the number of entries returned.
//----------------------------------------------------------
ULONG numberOfEntries;
numberOfEntries = ldap_count_entries(
pLdapConnection, // Session handle
pSearchResult); // Search result
if(numberOfEntries == NULL)
{
printf("ldap_count_entries failed with 0x%0lx \n",errorCode);
ldap_unbind_s(pLdapConnection);
if(pSearchResult != NULL)
ldap_msgfree(pSearchResult);
return -1;
}
else
printf("ldap_count_entries succeeded \n");
printf("The number of entries is: %d \n", numberOfEntries);
//----------------------------------------------------------
// Loop through the search entries, get, and output the
// requested list of attributes and values.
//----------------------------------------------------------
LDAPMessage* pEntry = NULL;
PCHAR pEntryDN = NULL;
ULONG iCnt = 0;
char* sMsg;
BerElement* pBer = NULL;
PCHAR pAttribute = NULL;
PCHAR* ppValue = NULL;
ULONG iValue = 0;
for( iCnt=0; iCnt < numberOfEntries; iCnt++ )
{
// Get the first/next entry.
if( !iCnt )
pEntry = ldap_first_entry(pLdapConnection, pSearchResult);
else
pEntry = ldap_next_entry(pLdapConnection, pEntry);
// Output a status message.
sMsg = (!iCnt ? "ldap_first_entry" : "ldap_next_entry");
if( pEntry == NULL )
{
printf("%s failed with 0x%0lx \n", sMsg, LdapGetLastError());
ldap_unbind_s(pLdapConnection);
ldap_msgfree(pSearchResult);
return -1;
}
else
printf("%s succeeded\n",sMsg);
// Output the entry number.
printf("ENTRY NUMBER %i \n", iCnt);
// Get the first attribute name.
pAttribute = ldap_first_attribute(
pLdapConnection, // Session handle
pEntry, // Current entry
&pBer); // [out] Current BerElement
// Output the attribute names for the current object
// and output values.
while(pAttribute != NULL)
{
// Output the attribute name.
printf(" ATTR: %s",pAttribute);
// Get the string values.
ppValue = ldap_get_values(
pLdapConnection, // Session Handle
pEntry, // Current entry
pAttribute); // Current attribute
// Print status if no values are returned (NULL ptr)
if(ppValue == NULL)
{
printf(": [NO ATTRIBUTE VALUE RETURNED]");
}
// Output the attribute values
else
{
iValue = ldap_count_values(ppValue);
if(!iValue)
{
printf(": [BAD VALUE LIST]");
}
else
{
// Output the first attribute value
printf(": %s", *ppValue);
// Output more values if available
ULONG z;
for(z=1; z<iValue; z++)
{
printf(", %s", ppValue[z]);
}
}
}
// Free memory.
if(ppValue != NULL)
ldap_value_free(ppValue);
ppValue = NULL;
ldap_memfree(pAttribute);
// Get next attribute name.
pAttribute = ldap_next_attribute(
pLdapConnection, // Session Handle
pEntry, // Current entry
pBer); // Current BerElement
printf("\n");
}
if( pBer != NULL )
ber_free(pBer,0);
pBer = NULL;
}
//----------------------------------------------------------
// Normal cleanup and exit.
//----------------------------------------------------------
ldap_unbind(pLdapConnection);
ldap_msgfree(pSearchResult);
ldap_value_free(ppValue);
return 0;
}
Reading the documentation for ldap_search_s, I see:
base [in]
Pointer to a null-terminated string that contains the distinguished name of the entry at which to start the search.
However, &searchBase[0] will only get you a pointer to the storage std::string uses - there is no requirement that this be null terminated. You should use searchBase.c_str() instead, as this is guaranteed to give you a null terminated c-string.
The pAttributes array has to be null-terminated.
The code should look like this:
char* pAttributes[2];
pAttributes[0] = &property[0];
pAttributes[1] = NULL;
Related
I am trying to write a simple audio capturing application in c++. and i found it is a very hard job to capture audio using c++ library, i couldn't find no more than a few library and I came up with ImediaObject. I found everything is okay in some other pc, but in my pc it can't record audio. When I call ImediaObject.ProcessOutput, it returns S_FALSE. I don't know what's wrong with my pc. I am using Visual Studio 2019.
Can anyone give me any clue ? what is wrong here ?
For your understanding I am sharing my main code here
#include <windows.h>
#include <dmo.h>
#include <Mmsystem.h>
#include <objbase.h>
#include <mediaobj.h>
#include <uuids.h>
#include <propidl.h>
#include <wmcodecdsp.h>
#include <atlbase.h>
#include <ATLComCli.h>
#include <audioclient.h>
#include <MMDeviceApi.h>
#include <AudioEngineEndPoint.h>
#include <DeviceTopology.h>
#include <propkey.h>
#include <strsafe.h>
#include <conio.h>
#include "AecKsBinder.h"
#include "mediabuf.h"
#define SAFE_ARRAYDELETE(p) {if (p) delete[] (p); (p) = NULL;}
#define SAFE_RELEASE(p) {if (NULL != p) {(p)->Release(); (p) = NULL;}}
#define VBFALSE (VARIANT_BOOL)0
#define VBTRUE (VARIANT_BOOL)-1
#define STREAM_BUFFER_LENGTH 0.1f //streaming buffer is 0.1 second long.
#define CHECK_RET(hr, message) if (FAILED(hr)) { puts(message); goto exit;}
#define CHECKHR(x) hr = x; if (FAILED(hr)) {printf("%d: %08X\n", __LINE__, hr); goto exit;}
#define CHECK_ALLOC(pb, message) if (NULL == pb) { puts(message); goto exit;}
class CStaticMediaBuffer : public CBaseMediaBuffer {
public:
STDMETHODIMP_(ULONG) AddRef() { return 2; }
STDMETHODIMP_(ULONG) Release() { return 1; }
void Init(BYTE* pData, ULONG ulSize, ULONG ulData) {
m_pData = pData;
m_ulSize = ulSize;
m_ulData = ulData;
}
};
void OutputUsage();
int __cdecl _tmain()
//int __cdecl _tmain()
{
HRESULT hr = S_OK;
CoInitialize(NULL);
IMediaObject* pDMO = NULL;
IPropertyStore* pPS = NULL;
CStaticMediaBuffer outputBuffer;
DMO_OUTPUT_DATA_BUFFER OutputBufferStruct = { 0 };
OutputBufferStruct.pBuffer = &outputBuffer;
DMO_MEDIA_TYPE mt = { 0 };
ULONG cbProduced = 0;
DWORD dwStatus;
// Parameters to config DMO
int iSystemMode = MODE_NOT_SET; // AEC-MicArray DMO system mode
int iOutFileIdx = -1; // argument index for otuput file name
int iMicDevIdx = -2; // microphone device index
int iSpkDevIdx = -2; // speaker device index
BOOL bFeatrModeOn = 0; // turn feature mode on/off
BOOL bNoiseSup = 1; // turn noise suppression on/off
BOOL bAGC = 0; // turn digital auto gain control on/off
BOOL bCntrClip = 0; // turn center clippng on/off
// control how long the Demo runs
int iDuration = 60; // seconds
int cTtlToGo = 0;
FILE* pfMicOutPCM; // dump output signal using PCM format
DWORD cOutputBufLen = 0;
BYTE* pbOutputBuffer = NULL;
UINT uCapDevCount = 0;
UINT uRenDevCount = 0;
char pcScanBuf[256] = { 0 };
WAVEFORMATEX wfxOut = { WAVE_FORMAT_PCM, 1, 22050, 44100, 2, 16, 0 };
AUDIO_DEVICE_INFO* pCaptureDeviceInfo = NULL, * pRenderDeviceInfo = NULL;
int i;
iMicDevIdx = 0;
iSpkDevIdx = 0;
iSystemMode = 0;
bFeatrModeOn = 1;
bNoiseSup = 1;
bAGC = 1;
bCntrClip = 1;
HANDLE currThread;
HANDLE currProcess;
BOOL iRet;
currProcess = GetCurrentProcess();
currThread = GetCurrentThread();
iRet = SetPriorityClass(currProcess, HIGH_PRIORITY_CLASS);
if (0 == iRet)
{
// call getLastError.
puts("failed to set process priority\n");
goto exit;
}
// DMO initialization
CHECKHR(CoCreateInstance(CLSID_CWMAudioAEC, NULL, CLSCTX_INPROC_SERVER, IID_IMediaObject, (void**)&pDMO));
CHECKHR(pDMO->QueryInterface(IID_IPropertyStore, (void**)&pPS));
// Select capture device
hr = GetCaptureDeviceNum(uCapDevCount);
CHECK_RET(hr, "GetCaptureDeviceNum failed");
pCaptureDeviceInfo = new AUDIO_DEVICE_INFO[uCapDevCount];
hr = EnumCaptureDevice(uCapDevCount, pCaptureDeviceInfo);
CHECK_RET(hr, "EnumCaptureDevice failed");
printf("\nSystem has totally %d capture devices\n", uCapDevCount);
for (i = 0; i < (int)uCapDevCount; i++)
{
_tprintf(_T("Device %d is %s"), i, pCaptureDeviceInfo[i].szDeviceName);
if (pCaptureDeviceInfo[i].bIsMicArrayDevice)
_tprintf(_T(" -- Mic Array Device \n"));
else
_tprintf(_T("\n"));
}
if (iMicDevIdx < -1 || iMicDevIdx >= (int)uCapDevCount)
{
do {
printf("Select device ");
scanf_s("%255s", pcScanBuf, 255);
iMicDevIdx = atoi(pcScanBuf);
if (iMicDevIdx < -1 || iMicDevIdx >= (int)uCapDevCount)
printf("Invalid Capture Device ID \n");
else
break;
} while (1);
}
if (iMicDevIdx == -1)
_tprintf(_T("\n Default device will be used for capturing \n"));
else
_tprintf(_T("\n %s is selected for capturing\n"), pCaptureDeviceInfo[iMicDevIdx].szDeviceName);
SAFE_ARRAYDELETE(pCaptureDeviceInfo);
// Select render device
if (iSystemMode == SINGLE_CHANNEL_AEC ||
iSystemMode == ADAPTIVE_ARRAY_AND_AEC ||
iSystemMode == OPTIBEAM_ARRAY_AND_AEC)
{
hr = GetRenderDeviceNum(uRenDevCount);
CHECK_RET(hr, "GetRenderDeviceNum failed");
pRenderDeviceInfo = new AUDIO_DEVICE_INFO[uRenDevCount];
hr = EnumRenderDevice(uRenDevCount, pRenderDeviceInfo);
CHECK_RET(hr, "EnumRenderDevice failed");
printf("\nSystem has totally %d render devices\n", uRenDevCount);
for (i = 0; i < (int)uRenDevCount; i++)
{
_tprintf(_T("Device %d is %s \n"), i, pRenderDeviceInfo[i].szDeviceName);
}
if (iSpkDevIdx < -1 || iSpkDevIdx >= (int)uRenDevCount)
{
do {
printf("Select device ");
scanf_s("%255s", pcScanBuf, 255);
iSpkDevIdx = atoi(pcScanBuf);
if (iSpkDevIdx < -1 || iSpkDevIdx >= (int)uRenDevCount)
printf("Invalid Render Device ID \n");
else
break;
} while (1);
}
if (iSpkDevIdx == -1)
_tprintf(_T("\n Default device will be used for rendering \n"));
else
_tprintf(_T("\n %s is selected for rendering \n"), pRenderDeviceInfo[iSpkDevIdx].szDeviceName);
}
else {
iSpkDevIdx = -1;
}
SAFE_ARRAYDELETE(pRenderDeviceInfo);
TCHAR* fileName;
fileName = (TCHAR*)"test.raw";
// --- PREPARE OUTPUT --- //
if (NULL != _tfopen_s(&pfMicOutPCM, fileName, _T("wb")))
{
puts("cannot open file for output.\n");
goto exit;
}
// Set AEC mode and other parameters
// Not all user changeable options are given in this sample code.
// Please refer to readme.txt for more options.
// Set AEC-MicArray DMO system mode.
// This must be set for the DMO to work properly
puts("\nAEC settings:");
PROPVARIANT pvSysMode;
PropVariantInit(&pvSysMode);
pvSysMode.vt = VT_I4;
pvSysMode.lVal = (LONG)(iSystemMode);
CHECKHR(pPS->SetValue(MFPKEY_WMAAECMA_SYSTEM_MODE, pvSysMode));
CHECKHR(pPS->GetValue(MFPKEY_WMAAECMA_SYSTEM_MODE, &pvSysMode));
printf("%20s %5d \n", "System Mode is", pvSysMode.lVal);
PropVariantClear(&pvSysMode);
// Tell DMO which capture and render device to use
// This is optional. If not specified, default devices will be used
if (iMicDevIdx >= 0 || iSpkDevIdx >= 0)
{
PROPVARIANT pvDeviceId;
PropVariantInit(&pvDeviceId);
pvDeviceId.vt = VT_I4;
pvDeviceId.lVal = (unsigned long)(iSpkDevIdx << 16) + (unsigned long)(0x0000ffff & iMicDevIdx);
CHECKHR(pPS->SetValue(MFPKEY_WMAAECMA_DEVICE_INDEXES, pvDeviceId));
CHECKHR(pPS->GetValue(MFPKEY_WMAAECMA_DEVICE_INDEXES, &pvDeviceId));
PropVariantClear(&pvDeviceId);
}
if (bFeatrModeOn)
{
// Turn on feature modes
PROPVARIANT pvFeatrModeOn;
PropVariantInit(&pvFeatrModeOn);
pvFeatrModeOn.vt = VT_BOOL;
pvFeatrModeOn.boolVal = bFeatrModeOn ? VBTRUE : VBFALSE;
CHECKHR(pPS->SetValue(MFPKEY_WMAAECMA_FEATURE_MODE, pvFeatrModeOn));
CHECKHR(pPS->GetValue(MFPKEY_WMAAECMA_FEATURE_MODE, &pvFeatrModeOn));
printf("%20s %5d \n", "Feature Mode is", pvFeatrModeOn.boolVal);
PropVariantClear(&pvFeatrModeOn);
// Turn on/off noise suppression
PROPVARIANT pvNoiseSup;
PropVariantInit(&pvNoiseSup);
pvNoiseSup.vt = VT_I4;
pvNoiseSup.lVal = (LONG)bNoiseSup;
CHECKHR(pPS->SetValue(MFPKEY_WMAAECMA_FEATR_NS, pvNoiseSup));
CHECKHR(pPS->GetValue(MFPKEY_WMAAECMA_FEATR_NS, &pvNoiseSup));
printf("%20s %5d \n", "Noise suppresion is", pvNoiseSup.lVal);
PropVariantClear(&pvNoiseSup);
// Turn on/off AGC
PROPVARIANT pvAGC;
PropVariantInit(&pvAGC);
pvAGC.vt = VT_BOOL;
pvAGC.boolVal = bAGC ? VBTRUE : VBFALSE;
CHECKHR(pPS->SetValue(MFPKEY_WMAAECMA_FEATR_AGC, pvAGC));
CHECKHR(pPS->GetValue(MFPKEY_WMAAECMA_FEATR_AGC, &pvAGC));
printf("%20s %5d \n", "AGC is", pvAGC.boolVal);
PropVariantClear(&pvAGC);
// Turn on/off center clip
PROPVARIANT pvCntrClip;
PropVariantInit(&pvCntrClip);
pvCntrClip.vt = VT_BOOL;
pvCntrClip.boolVal = bCntrClip ? VBTRUE : VBFALSE;
CHECKHR(pPS->SetValue(MFPKEY_WMAAECMA_FEATR_CENTER_CLIP, pvCntrClip));
CHECKHR(pPS->GetValue(MFPKEY_WMAAECMA_FEATR_CENTER_CLIP, &pvCntrClip));
printf("%20s %5d \n", "Center clip is", (BOOL)pvCntrClip.boolVal);
PropVariantClear(&pvCntrClip);
}
// Set DMO output format
hr = MoInitMediaType(&mt, sizeof(WAVEFORMATEX));
CHECK_RET(hr, "MoInitMediaType failed");
mt.majortype = MEDIATYPE_Audio;
mt.subtype = MEDIASUBTYPE_PCM;
mt.lSampleSize = 0;
mt.bFixedSizeSamples = TRUE;
mt.bTemporalCompression = FALSE;
mt.formattype = FORMAT_WaveFormatEx;
memcpy(mt.pbFormat, &wfxOut, sizeof(WAVEFORMATEX));
hr = pDMO->SetOutputType(0, &mt, 0);
CHECK_RET(hr, "SetOutputType failed");
MoFreeMediaType(&mt);
// Allocate streaming resources. This step is optional. If it is not called here, it
// will be called when first time ProcessInput() is called. However, if you want to
// get the actual frame size being used, it should be called explicitly here.
hr = pDMO->AllocateStreamingResources();
CHECK_RET(hr, "AllocateStreamingResources failed");
// Get actually frame size being used in the DMO. (optional, do as you need)
int iFrameSize;
PROPVARIANT pvFrameSize;
PropVariantInit(&pvFrameSize);
CHECKHR(pPS->GetValue(MFPKEY_WMAAECMA_FEATR_FRAME_SIZE, &pvFrameSize));
iFrameSize = pvFrameSize.lVal;
PropVariantClear(&pvFrameSize);
// allocate output buffer
cOutputBufLen = wfxOut.nSamplesPerSec * wfxOut.nBlockAlign;
pbOutputBuffer = new BYTE[cOutputBufLen];
CHECK_ALLOC(pbOutputBuffer, "out of memory.\n");
// number of frames to play
cTtlToGo = iDuration * 100;
// main loop to get mic output from the DMO
puts("\nAEC-MicArray is running ... Press \"s\" to stop");
while (1)
{
Sleep(10); //sleep 10ms
if (cTtlToGo-- <= 0)
break;
do {
outputBuffer.Init((byte*)pbOutputBuffer, cOutputBufLen, 0);
OutputBufferStruct.dwStatus = 0;
hr = pDMO->ProcessOutput(0, 1, &OutputBufferStruct, &dwStatus);
CHECK_RET(hr, "ProcessOutput failed");
if (hr == S_FALSE) {
cbProduced = 0;
}
else {
hr = outputBuffer.GetBufferAndLength(NULL, &cbProduced);
CHECK_RET(hr, "GetBufferAndLength failed");
}
// dump output data into a file with PCM format.
if (fwrite(pbOutputBuffer, 1, cbProduced, pfMicOutPCM) != cbProduced)
{
puts("write error");
goto exit;
}
} while (OutputBufferStruct.dwStatus & DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE);
// check keyboard input to stop
if (_kbhit())
{
int ch = _getch();
if (ch == 's' || ch == 'S')
break;
}
}
exit:
SAFE_ARRAYDELETE(pbOutputBuffer);
SAFE_ARRAYDELETE(pCaptureDeviceInfo);
SAFE_ARRAYDELETE(pRenderDeviceInfo);
SAFE_RELEASE(pDMO);
SAFE_RELEASE(pPS);
CoUninitialize();
return hr;
}
void OutputUsage()
{
printf("MFWMAAEC (Aec-MicArray DMO) Demo. \n");
printf("Copyright (c) 2004-2006, Microsoft Corporation. All rights reserved. \n\n");
printf("Usage: AecSDKDemo.exe -out mic_out.pcm -mod 0 [-feat 1] [-ns 1] [-agc 0] \n");
printf(" [-cntrclip 0] [-micdev 0] [-spkdev 0] [-duration 60]\n");
return;
}
NOTE: My main concern is to record audio and use the native noise and echo canceler. If there is any suggestion regarding this, I would very much appriciate it. Thanks.
I am trying to add a public key into diffie Hellman implementation of Bcrypt.
example suggested to create and export a public key. In my case I already got the public key from the client. I am trying to use that public key to generate shared session key. I get STATUS_INVALID_PARAMETER when i try to use BCryptImportKeyPair.
I created PBCRYPT_DH_KEY_BLOB and added the values manually.
Is there any other way to do this? an example of importing public key into BCrypt from string would be appreciated.
Thanks in Advance. Please check the code below.
KeyLength = 1024;//bits
const int sz = 1024;
char * shared_public_key = "48DE15D8E46B857B387E315D518B7D9EDDA1FCA6661CFC9C066B3A352E8644A30BFBB7F84C93818F67B7037235D11A5B0F31E15BCB344C2A7C13E339ED98939CF3F092E64C0DEA28A150404432E3B7077DE3E4D40E421EA88FFAF4D7AD53851912389674B24C80E5FD05D1C60344535159E7A4CAF9F9DCAF712C2A41EF524632";
char * prime = "CBBD1F895B751A803674B4CF6178DAFF87E3AADD017B96CA0D536215091AC55C0D777ADB6206581E7681C5059BEFF7990E4B3DD074266B608800CF7110BE99B861D189A82A26D569CAA2F314E8E79838AEE8DA96380BDFA55B34CA43866B24C0A822947E669C9AA037A8FA765F637663AB4103A9251C70000A689796CE42A2A3";
BYTE OakleyGroup1P[sz /8];
int fld_sz = sz / 8;
string s_prime(prime, fld_sz*2);
transform(s_prime.begin(), s_prime.end(), s_prime.begin(), ::tolower);
string res = "";
for (int i = 0; i < s_prime.size(); i += 2) {
res += s_prime.substr(i, 2);
res += " ";
}
std::istringstream hex_chars_stream(res);
unsigned int c;
int i = 0;
while (hex_chars_stream >> std::hex >> c)
{
OakleyGroup1P[i++] = c;
}
cout << "size of OakleyGroup1P :" << i << endl;
/*for (unsigned char x : OakleyGroup1P) {
cout << ((x >> 4) & 0x0F) << " " << (x & 0x0F) << endl;
}*/
PBYTE PubBlobA2 = new BYTE[sz/8];
string s_shared(shared_public_key, fld_sz * 2);
transform(s_shared.begin(), s_shared.end(), s_shared.begin(), ::tolower);
string temp = "";
for (int i = 0; i < s_shared.size(); i += 2) {
temp += s_shared.substr(i, 2);
temp += " ";
}
std::istringstream hex_chars_stream2(temp);
i = 0;
while (hex_chars_stream2 >> std::hex >> c)
{
PubBlobA2[i++] = c;
}
cout << "size of PubBlobA2 :" << i << endl;
for (int j = 0; j < i; j++) {
cout << ((*(PubBlobA2 + j) >> 4) & 0x0F) << " " << (*(PubBlobA2 + j) & 0x0F) << endl;
}
//
// Construct the DH parameter blob. this is the only supported
// method for DH in CNG.
//
// Calculate size of param blob and allocate memory
DhParamBlobLength = sizeof(BCRYPT_DH_PARAMETER_HEADER) +
sizeof(OakleyGroup1G) +
sizeof(OakleyGroup1P);
DhParamBlob = (PBYTE)HeapAlloc (
GetProcessHeap (),
0,
DhParamBlobLength);
if( NULL == DhParamBlob )
{
Status = STATUS_NO_MEMORY;
ReportError(Status);
goto cleanup;
}
DhParamHdrPointer = (BCRYPT_DH_PARAMETER_HEADER *)DhParamBlob;
//
// Set header properties on param blob
//
DhParamHdrPointer->cbLength = DhParamBlobLength;
DhParamHdrPointer->cbKeyLength = KeyLength/8;//bytes
DhParamHdrPointer->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC;
//
// Set prime
//
memcpy(DhParamBlob + sizeof(BCRYPT_DH_PARAMETER_HEADER),
OakleyGroup1P,
sizeof(OakleyGroup1P));
//
// Set generator
//
memcpy(DhParamBlob + sizeof(BCRYPT_DH_PARAMETER_HEADER) + sizeof(OakleyGroup1P),
OakleyGroup1G,
sizeof(OakleyGroup1G));
//
// Open alg provider handle
//
Status = BCryptOpenAlgorithmProvider(
&ExchAlgHandleB,
BCRYPT_DH_ALGORITHM,
NULL,
0);
if( !NT_SUCCESS(Status) )
{
ReportError(Status);
goto cleanup;
}
//
// B generates a private key
//
Status = BCryptGenerateKeyPair(
ExchAlgHandleB, // Algorithm handle
&PrivKeyHandleB, // Key handle - will be created
KeyLength, // Length of the key - in bits
0); // Flags
if( !NT_SUCCESS(Status) )
{
ReportError(Status);
goto cleanup;
}
Status = BCryptSetProperty(
PrivKeyHandleB,
BCRYPT_DH_PARAMETERS,
DhParamBlob,
DhParamBlobLength,
0);
if( !NT_SUCCESS(Status) )
{
ReportError(Status);
goto cleanup;
}
Status = BCryptFinalizeKeyPair(
PrivKeyHandleB, // Key handle
0); // Flags
if( !NT_SUCCESS(Status) )
{
ReportError(Status);
goto cleanup;
}
//
// B exports DH public key
//
Status = BCryptExportKey(
PrivKeyHandleB, // Handle of the key to export
NULL, // Handle of the key used to wrap the exported key
BCRYPT_DH_PUBLIC_BLOB, // Blob type (null terminated unicode string)
NULL, // Buffer that recieves the key blob
0, // Buffer length (in bytes)
&PubBlobLengthB, // Number of bytes copied to the buffer
0); // Flags
if( !NT_SUCCESS(Status) )
{
ReportError(Status);
goto cleanup;
}
PubBlobB = (PBYTE)HeapAlloc (
GetProcessHeap (),
0,
PubBlobLengthB);
if( NULL == PubBlobB )
{
Status = STATUS_NO_MEMORY;
ReportError(Status);
goto cleanup;
}
Status = BCryptExportKey(
PrivKeyHandleB, // Handle of the key to export
NULL, // Handle of the key used to wrap the exported key
BCRYPT_DH_PUBLIC_BLOB, // Blob type (null terminated unicode string)
PubBlobB, // Buffer that recieves the key blob
PubBlobLengthB, // Buffer length (in bytes)
&PubBlobLengthB, // Number of bytes copied to the buffer
0); // Flags
if( !NT_SUCCESS(Status) )
{
ReportError(Status);
goto cleanup;
}
//
// Build KDF parameter list
//
//specify hash algorithm, SHA1 if null
//specify secret to append
BufferArray[0].BufferType = KDF_TLS_PRF_SEED;
BufferArray[0].cbBuffer = sizeof(rgbrgbTlsSeed);
BufferArray[0].pvBuffer = (PVOID)rgbrgbTlsSeed;
//specify secret to prepend
BufferArray[1].BufferType = KDF_TLS_PRF_LABEL;
BufferArray[1].cbBuffer = (DWORD)((wcslen(Label) + 1) * sizeof(WCHAR));
BufferArray[1].pvBuffer = (PVOID)Label;
ParameterList.cBuffers = 2;
ParameterList.pBuffers = BufferArray;
ParameterList.ulVersion = BCRYPTBUFFER_VERSION;
//
// B imports A's public key
//
// dh public key blob structure
PBCRYPT_DH_KEY_BLOB p_dh_pub_key_blob = (PBCRYPT_DH_KEY_BLOB)HeapAlloc(
GetProcessHeap(),
0,
sizeof(BCRYPT_DH_KEY_BLOB));
p_dh_pub_key_blob->dwMagic = BCRYPT_DH_PUBLIC_MAGIC;
p_dh_pub_key_blob->cbKey = sz/8;
DWORD df_pub_key_data_length = sizeof(BCRYPT_DH_KEY_BLOB) + sz / 8;
PBYTE p_df_pub_key_data = (PBYTE)HeapAlloc(
GetProcessHeap(),
0,
df_pub_key_data_length);
memcpy(p_df_pub_key_data,
p_dh_pub_key_blob,
sizeof(BCRYPT_DH_KEY_BLOB));
memcpy(p_df_pub_key_data + sizeof(BCRYPT_DH_KEY_BLOB),
PubBlobA2,
sz/8);
Status = BCryptImportKeyPair(
ExchAlgHandleB, // Alg handle
NULL, // Parameter not used
BCRYPT_DH_PUBLIC_BLOB, // Blob type (Null terminated unicode string)
&PubKeyHandleB, // Key handle that will be recieved
p_df_pub_key_data, // Buffer than points to the key blob
df_pub_key_data_length, // Buffer length in bytes
0);
I have a helper function for using prepared statements with mysql. All works well as long as i dont want to retrieve any results.
If i want to retrieve a result (e.g. simple long ID) im getting a warning from visual studio debugger that the stack is corrupted around my ID variable.
Header
bool RunPreparedStatement(std::string query, std::vector paramList, std::string& errbuf, int* affected_rows, bool fetchResultID = false, int32* result_id=0, bool fetchInsertID = false, int32* last_insert_id=0);
bool RunPreparedStatement(std::string sql, std::vector<MYSQL_BIND> paramList, std::string& errStr, int* affected_rows, bool fetchResultID, int32* result_id, bool fetchInsertID, int32* last_insert_id) {
char errbuf[MYSQL_ERRMSG_SIZE];
int numParams = paramList.size();
bool fetchResult = fetchResultID;
if(numParams == 0) {
errStr = "0 parameters supplied";
return false;
}
MYSQL_STMT *stmt = mysql_stmt_init(&mysql);
if (!stmt) {
errStr = "mysql_stmt_init(), out of memory";
return false;
}
if (mysql_stmt_prepare(stmt, sql.c_str(), sql.length())) {
errStr = "mysql_stmt_prepare() failed ";
errStr.append(mysql_stmt_error(stmt));
return false;
}
int param_count= mysql_stmt_param_count(stmt);
if (param_count != numParams) /* validate parameter count */{
errStr = "invalid parameter count returned by MySQL";
return false;
}
if (mysql_stmt_bind_param(stmt, ¶mList[0])) {
errStr = "mysql_stmt_bind_param() failed ";
errStr.append(mysql_stmt_error(stmt));
return false;
}
int32 id = 0;
MYSQL_BIND resultParam1;
BindValue(&resultParam1,MYSQL_TYPE_LONGLONG,&id,0,0,0);
if(fetchResult) {
/* Bind the results buffer */
if (mysql_stmt_bind_result(stmt, &resultParam1) != 0) {
errStr = "mysql_stmt_bind_result() failed ";
errStr.append(mysql_stmt_error(stmt));
return false;
}
}
if (mysql_stmt_execute(stmt)) {
errStr = "mysql_stmt_execute() failed ";
errStr.append(mysql_stmt_error(stmt));
return false;
}
if(fetchResult) {
if (mysql_stmt_store_result(stmt) != 0) {
errStr = "Could not buffer result set ";
errStr.append(mysql_stmt_error(stmt));
return false;
}
if(mysql_stmt_fetch (stmt) == 0) {
(*result_id) = id;
// OK
*affected_rows = 1;
} else {
*affected_rows = 0;
/*errStr = "no results found ";
errStr.append(mysql_stmt_error(stmt));
return false;*/
}
} else {
*affected_rows = mysql_stmt_affected_rows(stmt);
}
if(fetchInsertID) {
*last_insert_id= mysql_stmt_insert_id(stmt);
}
if(stmt != NULL) {
// Deallocate result set
mysql_stmt_free_result(stmt); /* deallocate result set */
if (mysql_stmt_close(stmt)) {
errStr = "closing the statement failed ";
errStr.append(mysql_stmt_error(stmt));
return false;
}
}
return true;
}
I call it like this
std::string errBuf;
int affected_rows = 0;
std::string sql = "SELECT count(*) FROM name WHERE (?) like name";
std::vector<MYSQL_BIND> paramList;
std::vector<MYSQL_BIND> resultParamList;
char data[1024];
safe_strncpy(data,name,sizeof(data), __FILE__, __LINE__);
MYSQL_BIND param1;
BindValue(¶m1,MYSQL_TYPE_STRING,data,strlen(data),0,0);
paramList.push_back(param1);
int32 count = 0;
bool ret = true;
if(RunPreparedStatement(sql,paramList,errBuf,&affected_rows,true,&count)){
...
}
I previously had also a resultParamList instead of simple the ID and had the same error and thought it was related to return a list of values but that wasnt it.
Im receiving the warning as soon as the RunPreparedStatement method is finished.
Trying another sample code i found the issue
int32 id = 0;
MYSQL_BIND resultParam1;
BindValue(&resultParam1,MYSQL_TYPE_LONGLONG,&id,0,0,0);
im telling that the result type is MYSQL_TYPE_LONGLONG but im only giving it a int32 (unsigned int ) instead of unsigned long long.
So either change to MYSQL_TYPE_LONG or increase var size.
I writing program for the Windows registry and trying to query values from it, but even if I running my own program with the permissions of Administrator, I can not read all parameters and got error code 5 - Access Denied for some values. But at the same time standard regedit could show me that value. What did i doing wrong?
I have a class for the registry RegistryClass
RegistryClass.h:
class RegistryClass
{
HKEY hKey;
public:
int GetCountOfKeys();
bool OpenKey(HKEY key, std::string path);
void EnumKeys(char ** result, int * count);
...
}
RegistryClass.cpp
#include "RegistryClass.h"
...
bool RegistryClass::OpenKey(HKEY key, std::string path)
{
if(RegOpenKeyExA(key,path.c_str(),NULL,KEY_ALL_ACCESS,&hKey) == ERROR_SUCCESS)
{
return true;
}
hKey = NULL;
return false;
}
int RegistryClass::GetCountOfKeys()
{
DWORD count = 0;
char keyName [256];
DWORD len = 255;
while(1)
{
if(RegEnumKeyExA(hKey,count,keyName,&len,NULL,NULL,NULL,NULL) != ERROR_SUCCESS)
break;
count++;
len = 255;
}
return count;
}
void RegistryClass::EnumKeys(char ** result, int * count)
{
if(hKey == NULL)
return;
*count = 0;
DWORD dwIndex = 0; // current key
char keyName [255]; // current key name
DWORD lpcchName = 255; // name length
int error;
do
{
error = RegEnumKeyExA(hKey,dwIndex,keyName,&lpcchName,NULL,NULL,NULL,NULL);
if(error == ERROR_SUCCESS)
{
memcpy(result[(*count)],keyName,lpcchName);
(*count)++;
}
dwIndex++;
lpcchName = 255;
}while(error == ERROR_SUCCESS);
}
in main program i trying to retrive keys
void MainWindow::InitializeFirstState()
{
item_HKEY_CLASSES_ROOT = new QTreeWidgetItem();
item_HKEY_CLASSES_ROOT->setText(0,"HKEY_CLASSES_ROOT");
// and other keys
...
tree->addTopLevelItem(item_HKEY_CLASSES_ROOT);
...
AddInternalKeys(item_HKEY_CLASSES_ROOT,true);
...
}
...
void AddInternalKeys(QTreeWidgetItem * item, bool rec)
{
std::string currentPath = GetFullPathKey(item);
// first key name
std::string keyName = GetParentKeyName(item);
RegistryClass * regC = new RegistryClass();
HKEY key;
if(strcmp(keyName.c_str(),"HKEY_CLASSES_ROOT") == 0)
{
key = HKEY_CLASSES_ROOT;
}
else if(strcmp(keyName.c_str(),"HKEY_CURRENT_USER") == 0)
{
key = HKEY_CURRENT_USER;
}
else if(strcmp(keyName.c_str(),"HKEY_LOCAL_MACHINE") == 0)
{
key = HKEY_LOCAL_MACHINE;
}
else if(strcmp(keyName.c_str(),"HKEY_USERS") == 0)
{
key = HKEY_USERS;
}
else // HKEY_CURRENT_CONFIG
{
key = HKEY_CURRENT_CONFIG;
}
if(regC->OpenKey(key,currentPath) == true)
{
internalLog->print("key opened succesfully\n");
}
else internalLog->print("key was not opened\n");
int count = regC->GetCountOfKeys();
char ** keys = (char **) malloc(sizeof(char *) * count);
for(int i=0;i<count;i++)
{
keys[i] = (char *) malloc(sizeof(char) * 256);
memset(keys[i],0,sizeof(char) * 256);
}
regC->EnumKeys(keys,&count);
regC->CloseKey();
delete regC;
QTreeWidgetItem * newItem;
count--;
while(count >= 0)
{
newItem = new QTreeWidgetItem();
newItem->setText(0,keys[count]);
item->addChild(newItem);
std::string str = keys[count];
AddKeyNames(newItem,str);
free(keys[count]);
if(rec == true)
AddInternalKeys(newItem,false);
count--;
}
free(keys);
}
You are asking for too much access. You are asking for KEY_ALL_ACCESS when all you actually need is KEY_READ. You do not have all-access permission, but you do have read permission.
I'm working with MAPI library in C++ to send emails. Now I need that the emails I send have a reply-to set to more than one email and I just can do it to one email.
I have been reading that to be able to do this I need to work with the objects FLATENTRYLIST (link) and FLATENTRY (link).
My doubt is how can I store more than one FLATENTRY object in the FLATENTRYLIST. My experience in C++ is not very high so if anyone can help me I will apreciate.
Thanks in advance
Paulo
The FLATENTRYLIST has cEntries member that determines the number of the entries in the list.
You just need to store the entries in abEntries array.
Here is the solution I developed - http://www.codeproject.com/KB/IP/CMapiEx.aspx?msg=3959770#xx3959770xx
Thanks Dmitry for your help.
When I was copying the EntryID to the FlatEntry I as copying the wrong bytes number. Here is the final code that works like a charm.
BOOL CMAPIMessage::SetReplyTo(LPADRLIST lpAddrList)
{
HRESULT hRes = S_OK;
SPropValue pspvReply[1];
LPFLATENTRYLIST lpEntryList = NULL;
BOOL bResult = false;
CString m_strReplyToNames;
int cb = 0;
int displayNameTagID = -1;
int emailTagID = -1;
int entryIDTagID = -1;
int cbAllBytes = 0;
//Get all the EntryID's bytes to initalize the FLATENTRYLIST
for(unsigned j=0; j<lpAddrList->cEntries; j++)
{
for (unsigned i = 0; i < lpAddrList->aEntries[j].cValues; i++)
{
if (lpAddrList->aEntries[j].rgPropVals[i].ulPropTag == PR_ENTRYID)
{
entryIDTagID = i;
}
}
if (entryIDTagID >= 0)
{
int feBytes = CbNewFLATENTRY(lpAddrList->aEntries[j].rgPropVals[entryIDTagID].Value.bin.cb);
cbAllBytes += feBytes;
cbAllBytes += ((feBytes + 4 & ~3) - feBytes);
}
}
//Allocate a new FLATENTRYLIST with all flatentries bytes
cb = CbNewFLATENTRYLIST(cbAllBytes);
hRes = MAPIAllocateBuffer(cb, (LPVOID *)&lpEntryList);
if (FAILED(hRes))
{
bResult = false;
goto Cleanup;
}
ZeroMemory((VOID *)lpEntryList, cb);
// Copy the bits of the FLATENTRY into the FLATENTRYLIST.
lpEntryList->cEntries = lpAddrList->cEntries;
int countBytesAdded = 0;
for(unsigned j=0; j<lpAddrList->cEntries; j++)
{
for (unsigned i = 0; i < lpAddrList->aEntries[j].cValues; i++)
{
if (lpAddrList->aEntries[j].rgPropVals[i].ulPropTag == PR_TRANSMITABLE_DISPLAY_NAME)
{
displayNameTagID = i;
}
else if (lpAddrList->aEntries[j].rgPropVals[i].ulPropTag == PR_EMAIL_ADDRESS)
{
emailTagID = i;
}
else if (lpAddrList->aEntries[j].rgPropVals[i].ulPropTag == PR_ENTRYID)
{
entryIDTagID = i;
}
}
if ((emailTagID>=0) && (entryIDTagID>=0))
{
CString m_strReplyToName;
CString m_strReplyToEmail;
m_strReplyToEmail=lpAddrList->aEntries[j].rgPropVals[emailTagID].Value.lpszA;
if(displayNameTagID>=0)
m_strReplyToName=lpAddrList->aEntries[j].rgPropVals[displayNameTagID].Value.lpszA;
else
m_strReplyToName = m_strReplyToEmail;
m_strReplyToNames += (CString)m_strReplyToName + ";";
// Allocate a new FLATENTRY structure for the PR_REPLY_RECIPIENT_ENTRIES property
LPFLATENTRY lpReplyEntry = NULL;
cb = CbNewFLATENTRY(lpAddrList->aEntries[j].rgPropVals[entryIDTagID].Value.bin.cb);
hRes = MAPIAllocateBuffer(cb, (LPVOID *)&lpReplyEntry);
if (FAILED(hRes))
{
bResult = false;
goto Cleanup;
}
ZeroMemory((VOID *)lpReplyEntry, cb);
// Copy the bits of the entry id into the FLATENTRY structure
CopyMemory(lpReplyEntry->abEntry,
lpAddrList->aEntries[j].rgPropVals[entryIDTagID].Value.bin.lpb,
lpAddrList->aEntries[j].rgPropVals[entryIDTagID].Value.bin.cb);
lpReplyEntry->cb = lpAddrList->aEntries[j].rgPropVals[entryIDTagID].Value.bin.cb;
int missingBytes = 0;
int feBytes = CbFLATENTRY(lpReplyEntry);
missingBytes = ((feBytes + 4 & ~3) - feBytes);
//Copy each FLATENTRY to the abEntries, next to the previous added bytes
CopyMemory(lpEntryList->abEntries + countBytesAdded, lpReplyEntry, feBytes);
countBytesAdded += feBytes + missingBytes;
//Clean Memory
if (lpReplyEntry) MAPIFreeBuffer(lpReplyEntry);
}
displayNameTagID = -1;
emailTagID = -1;
entryIDTagID = -1;
}
lpEntryList->cbEntries = countBytesAdded;
pspvReply[0].ulPropTag = PR_REPLY_RECIPIENT_ENTRIES;
// Allocate memory in the lpb to hold the FLATENTRYLIST
hRes = MAPIAllocateBuffer(CbFLATENTRYLIST(lpEntryList), (LPVOID *)&pspvReply[0].Value.bin.lpb);
if (FAILED(hRes))
{
bResult = false;
goto Cleanup;
}
// Copy the memory into the SPropValue
CopyMemory(pspvReply[0].Value.bin.lpb,lpEntryList,CbFLATENTRYLIST(lpEntryList));
pspvReply[0].Value.bin.cb = CbFLATENTRYLIST(lpEntryList);
//Set the PR_REPLY_RECIPIENT_NAMES property with all names
SetPropertyString(PR_REPLY_RECIPIENT_NAMES, m_strReplyToNames);
// Set the property that contains the FLATENTRYLIST with the reply-to adresses to the message properties
hRes = Message()->SetProps(1,pspvReply,NULL);
if (FAILED(hRes))
{
bResult = false;
goto Cleanup;
}
bResult = true;
Cleanup:
if (lpEntryList) MAPIFreeBuffer(lpEntryList);
return bResult;
}