I'm using Windows Web Services to access a WCF service and it creates a an array of pointers of the results.
I had a similar issue where I was also reading garbage data and I though it might be caused by sendign this data to another function that was causing the pointers to get invalidated but now I'm storing it in a vector reference to try to avoid such issues but the problem persists. I'm not sure what do do anymore.
I also tried using ListaDeMaterialesBE** lstmat = new ListaDeMaterialesBE*; but that did not work at all.
Here is the code:
void svc_listMaterials(const size_t& idProject, std::vector<ListaDeMaterialesBE>& result) {
HRESULT hr = ERROR_SUCCESS;
WS_ERROR* error = NULL;
WS_HEAP* heap = NULL;
WS_SERVICE_PROXY* proxy = NULL;
WS_ENDPOINT_ADDRESS address = {};
const WS_STRING url = WS_STRING_VALUE(L"http://localhost/SIMSE_Service.ServicioEstadistico.svc");
address.url = url;
WS_HTTP_BINDING_TEMPLATE templateValue = {};
ULONG maxMessageSize = 2147483647;
WS_CHANNEL_PROPERTY channelProperty [ 1 ];
channelProperty [ 0 ].id = WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE;
channelProperty [ 0 ].value = &maxMessageSize;
channelProperty [ 0 ].valueSize = sizeof(maxMessageSize);
WS_CHANNEL_PROPERTIES channelProperties;
channelProperties.properties = channelProperty;
channelProperties.propertyCount = 1;
templateValue.channelProperties = channelProperties;
hr = WsCreateError(NULL, 0, &error);
if (FAILED(hr)) {
}
hr = WsCreateHeap(2048, 512, NULL, 0, &heap, error);
WS_HTTP_BINDING_TEMPLATE templ = {};
hr = BasicHttpBinding_IServicioEstadistico_CreateServiceProxy(&templateValue, NULL, 0, &proxy, error);
hr = WsOpenServiceProxy(proxy, &address, NULL, error);
// The issue starts here
ListaDeMaterialesBE** lstmat;
unsigned int rcount;
hr = BasicHttpBinding_IServicioEstadistico_ListarMaterialesPorProyecto(proxy,
idProject,
&rcount,
&lstmat,
heap,
NULL,
NULL,
NULL,
error);
// Here is where we seem to be reading garbage data
if (rcount > 1 && rcount < 10000) {
for (size_t i = 1; i <= rcount; ++i) {
ListaDeMaterialesBE t = **lstmat;
result.push_back(t);
lstmat++;
}
}
if (proxy) {
WsCloseServiceProxy(proxy, NULL, NULL);
WsFreeServiceProxy(proxy);
}
if (heap) {
WsFreeHeap(heap);
}
if (error) {
WsFreeError(error);
}
if (FAILED(hr)) {
std::cout << "errored \n";
}
}
I think the reason for the error is your wrong use of the returned secondary pointer.
I created a simple example to simulate the problem:
#define COUNT 10
void f(int** pp)
{
*pp = new int[COUNT];
for (int i = 0; i < COUNT; i++)
{
(*pp)[i] = i;
}
}
int main(int argc, const char* argv[])
{
int** pp = new int*;
f(pp);
for (int i = 0; i < COUNT; i++)
{
cout << **pp;
pp++;
}
return 0;
}
The function f obtains a secondary pointer, this secondary pointer saves the first address of an array, and then writes it.
Then use your method to traverse the array, it will cause an access exception:
The reason for the error is that when you use the secondary pointer to perform an auto-increment operation, the distance it moves each time is not the distance of an element you think.
So you should get the first address of the array it saves through the secondary pointer, and then traverse:
int** pp = new int*;
f(pp);
auto p = *pp;
for (int i = 0; i < COUNT; i++)
{
cout << *p;
p++;
}
Then we can read the correct data:
Related
When i run program start it will show an Error as in the picture.
enter image description here
and When i clikced continue it will show an Error as in the picture
enter image description here
This is the code structure I wrote.
int nSites = 0;
int nTasks = 0;
int nThreads = 0;
CCriticalSection cs;
BOOL bUpdateList=false;
UINT VisitSite(LPVOID pParam){
int nTask = 0;
CInternetSession session;
session.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT,5000);
CHttpConnection *pConnection = NULL;
CHttpFile *pFile1 = NULL;
char *buffer = new char[10240];
UINT nBytesRead = 0;
while(nTasks>0){
nTask = -1;
cs.Lock();
for(int t=0;t<nSites;t++){
if(!bAssigned[t]){
bAssigned[t]=true;
nTask=t;
t=nSites;
}
}
cs.Unlock();
if(nTask == -1){
cs.Lock();
nThreads--;
cs.Unlock();
return 0;
}
try
{
pConnection = session.GetHttpConnection(sAddress[nTask], 80, (_T("")), (_T("")));
pFile1 = pConnection->OpenRequest((_T("GET")), (_T("/")));
pFile1->SendRequest();
nBytesRead = pFile1->Read(buffer, 10240);
buffer[nBytesRead] = (_T('\0'));
//ถ้าหากว่า สามารถติดต่อได้ ที่ port 80จริง ให้พิมพ์ข้อความว่า IP Address น้ีเป็น Web server
if (pConnection != NULL)
{
cs.Lock();
bUpdateList=true;
bIsWebServer[nTask]=true;
cs.Unlock();
}
cs.Lock();
bFinished[nTask]=true;
nTasks--;
nThreads--;
cs.Unlock();
if(pFile1) delete pFile1;
if(pConnection) delete pConnection;
delete [] buffer;
if (buffer != NULL) {
HeapFree(GetProcessHeap(), 0, buffer);
}
if (pFile1 != NULL) {
HeapFree(GetProcessHeap(), 0, pFile1);
}
if (pConnection != NULL) {
HeapFree(GetProcessHeap(), 0, pConnection);
}
//return 0;
}
catch (CInternetException* ie )
{
ie->Delete();
cs.Lock();
nTasks--;
bUpdateList=true;
bFinished[nTask]=true;
bIsWebServer[nTask]=false;
nThreads--;
cs.Unlock();
}
}
cs.Lock();
nThreads--;
cs.Unlock();
session.Close();
return 0;
}
Cause i think it comes from *ie but Not sure if I wrote the structure correctly, please check.
Look at this
char *buffer = new char[10240];
...
delete [] buffer;
if (buffer != NULL) {
HeapFree(GetProcessHeap(), 0, buffer);
}
You don't need to use delete[] and HeapFree. Because you used new[] to allocate buffer you should use delete[] to free it. Remove the call to HeapFree.
You have the same problem with pFile1 and pConnection, use delete don't use HeapFree.
Another change
if(pFile1) delete pFile1;
if(pConnection) delete pConnection;
can be simplified to
delete pFile1;
delete pConnection;
It's not an error to delete a NULL pointer. Deleteing a NULL pointer has no effect, so you don't need to test if a pointer is NULL before deleting it.
However like Alan Birtles said you really should test if pConnection is NULL before you try to use it.
I'm trying to create and read a SAFEARRAY(MyUDT)* where MyUDT contains a SAFEARRAY, but when I try to read it I got an "Access violation" exception.
I defined the following struct and enum:
typedef [uuid(...)]
enum CollisionDetectorMoveType
{
CollisionDetectorMoveType_Unknown = -1,
CollisionDetectorMoveType_Move = 0,
CollisionDetectorMoveType_Measure
} CollisionDetectorMoveType;
typedef [uuid(...)]
struct CollisionDetectorXYZ
{
double X;
double Y;
double Z;
} CollisionDetectorXYZ;
typedef [uuid(...)]
struct CollisionDetectorMultiPosition
{
SAFEARRAY(CollisionDetectorXYZ) pos;
CollisionDetectorMoveType type;
} CollisionDetectorMultiPosition;
bool createTestCollisionDetectorMultiPositionSafeArray(SAFEARRAY** psa)
{
IRecordInfoPtr recordset_info = nullptr;
HRESULT hr = GetRecordInfoFromGuids(LIBID_CollisionDetectorLib, 1, 0, 0, UUID_CollisionDetectorMultiPosition, &recordset_info);
if (FAILED(hr))
{
return false;
}
SAFEARRAYBOUND safearray_bound;
memset(&safearray_bound, 0, sizeof(safearray_bound));
safearray_bound.cElements = 10;
safearray_bound.lLbound = 0;
*psa = ::SafeArrayCreateEx(VT_RECORD, 1, &safearray_bound, (PVOID)recordset_info);
for (size_t i = 0; i < 10; ++i)
{
CollisionDetectorMultiPosition multiPosition;
multiPosition.type = i % 2 == 0 ? CollisionDetectorMoveType_Move : CollisionDetectorMoveType_Measure;
if (!createTestCollisionDetectorXYZSafeArray(&multiPosition.pos))
{
return false;
}
LONG current_position = i;
::SafeArrayPutElement(*psa, ¤t_position, &multiPosition);
}
::SafeArrayUnaccessData(*psa);
return true;
}
}
bool createTestCollisionDetectorXYZSafeArray(SAFEARRAY** psa)
{
IRecordInfoPtr recordset_info = nullptr;
HRESULT hr = GetRecordInfoFromGuids(LIBID_CollisionDetectorLib, 1, 0, 0, UUID_CollisionDetectorXYZ, &recordset_info);
if (FAILED(hr))
{
return false;
}
SAFEARRAYBOUND safearray_bound;
memset(&safearray_bound, 0, sizeof(safearray_bound));
safearray_bound.cElements = 10;
safearray_bound.lLbound = 0;
*psa = ::SafeArrayCreateEx(VT_RECORD, 1, &safearray_bound, (PVOID)recordset_info);
for (size_t i = 0; i < 10; ++i)
{
CollisionDetectorXYZ current_point;
current_point.X = i;
current_point.Y = i;
current_point.Z = i;
LONG current_position = i;
::SafeArrayPutElement(*psa, ¤t_position, ¤t_point);
}
::SafeArrayUnaccessData(*psa);
return true;
}
Then I try to create and read the SAFEARRAY:
SAFEARRAY* psa2 = NULL;
if (!createTestCollisionDetectorMultiPositionSafeArray(&psa2))
{
*retVal = SYSERR;
return S_OK;
}
CollisionDetectorMultiPosition* current_pointer_to_element;
auto access_result = ::SafeArrayAccessData(psa2, (void **)¤t_pointer_to_element);
if (FAILED(access_result))
{
return S_OK;
}
LONG upper_bound, lower_bound;
::SafeArrayGetLBound(psa2, 1, &lower_bound);
::SafeArrayGetUBound(psa2, 1, &upper_bound);
std::vector<CollisionDetectorMultiPosition> multiPositionVector;
LONG size = upper_bound - lower_bound + 1;
for (LONG i = 0; i < size; i++)
{
CollisionDetectorMultiPosition this_value;
::SafeArrayGetElement(psa2, &i, (void *)&this_value);
multiPositionVector.push_back(this_value);
}
However when I call ::SafeArrayGetElement(psa2, &i, (void *)&this_value); I got the exception.
What I'm doing wrong?
If I simply call
CollisionDetectorMultiPosition multiPosition;
multiPosition.type = CollisionDetectorMoveType_Move;
if (!createTestCollisionDetectorXYZSafeArray(&multiPosition.pos))
{
*retVal = SYSERR;
return S_OK;
}
I can read the multiPosition.pos SAFEARRAY without any problem.
Thanks for your help.
Solved
I found a solution, I report the code for all the users which could have the same problem. Basically the trick is to create a SAFEARRAY of VARIANT, and fill the VARIANT struct with the CollisionDetectorMultiPosition.
CComVariant variant;
variant.vt = VT_RECORD;
variant.pvRecord = &multiPosition;
variant.pRecInfo = recordset_info;
Creation of SAFEARRAY
bool createTestCollisionDetectorMultiPositionSafeArray(SAFEARRAY** psa)
{
IRecordInfoPtr recordset_info;
HRESULT hr = GetRecordInfoFromGuids(LIBID_CollisionDetectorLib, 1, 0, 0, UUID_CollisionDetectorMultiPosition, &recordset_info);
if (FAILED(hr))
{
return false;
}
SAFEARRAYBOUND safearray_bound;
memset(&safearray_bound, 0, sizeof(safearray_bound));
safearray_bound.cElements = 10;
safearray_bound.lLbound = 0;
*psa = SafeArrayCreate(VT_VARIANT, 1, &safearray_bound);
for (size_t i = 0; i < 10; ++i)
{
CollisionDetectorMultiPosition multiPosition;
multiPosition.type = i % 2 == 0 ? CollisionDetectorMoveType_Move : CollisionDetectorMoveType_Measure;
if (!createTestCollisionDetectorXYZSafeArray(&multiPosition.pos))
{
return false;
}
CComVariant variant;
variant.vt = VT_RECORD;
variant.pvRecord = &multiPosition;
variant.pRecInfo = recordset_info;
LONG current_position = i;
::SafeArrayPutElement(*psa, ¤t_position, &variant);
variant.vt = VT_EMPTY;
}
::SafeArrayUnaccessData(*psa);
return true;
}
Reading the SAFEARRAY
SAFEARRAY* psa2 = NULL;
if (!createTestCollisionDetectorMultiPositionSafeArray(&psa2))
{
*retVal = AC3SYSERR;
return S_OK;
}
LONG upper_bound, lower_bound;
::SafeArrayGetLBound(psa2, 1, &lower_bound);
::SafeArrayGetUBound(psa2, 1, &upper_bound);
std::vector<std::pair<CollisionDetectorMoveType, std::vector<CollisionDetectorXYZ>>> multiPositionVector;
LONG size = upper_bound - lower_bound + 1;
for (LONG i = 0; i < size; i++)
{
VARIANT this_value;
VariantInit(&this_value);
VariantClear(&this_value);
::SafeArrayGetElement(psa2, &i, (void *)&this_value);
CollisionDetectorMultiPosition* this_value2 = (CollisionDetectorMultiPosition *)this_value.pvRecord;
CollisionDetectorXYZ* current_pointer_to_element;
auto access_result = ::SafeArrayAccessData(this_value2->pos, (void **)¤t_pointer_to_element);
if (FAILED(access_result))
{
return S_OK;
}
LONG upper_bound, lower_bound;
::SafeArrayGetLBound(this_value2->pos, 1, &lower_bound);
::SafeArrayGetUBound(this_value2->pos, 1, &upper_bound);
std::vector<CollisionDetectorXYZ> moves;
LONG size = upper_bound - lower_bound + 1;
for (LONG i = 0; i < size; i++)
{
CollisionDetectorXYZ this_value;
::SafeArrayGetElement(this_value2->pos, &i, (void *)&this_value);
moves.push_back(this_value);
}
multiPositionVector.push_back(std::make_pair(this_value2->type, moves));
::SafeArrayUnaccessData(this_value2->pos);
}
Actually I had similar problem and this thread helped me a lot, but there are some details specific to MFC ActiveX that took me a couple of days to demystify and I want to share them with the community.
My objective was to add a method in an MFC/ATL ActiveX that would return an Array of UDT to COM enabled programming languages.
My first problem was exposing the UUID of the UDT to the C++ code; for some reason despite giving a GUID to the UDT it was not being generated nor becoming available to C++. I found that I had to add cpp_quote in IDL to force it.
[
uuid(GUID_LIBRARY),
version(VERSION)
...
]
library WebKitXCEF3Lib
{
importlib(STDOLE_TLB);
typedef [public, uuid(<your guid here>)] struct Cookie
{
BSTR Name;
BSTR Domain;
BSTR Path;
BSTR Value;
VARIANT_BOOL HttpOnly;
VARIANT_BOOL Secure;
VARIANT_BOOL Expires;
VARIANT ExpiryDateUTC;
} Cookie;
cpp_quote("struct __declspec(uuid(\"{<your guid here>}\")) Cookie;")
...
}
Next, the return type of the method returning the UDT Array has to be VARIANT:
[id(100)] VARIANT GetCookies(BSTR Domain);
The DISPATCH MAP should define the return type as VT_VARIANT too:
BEGIN_DISPATCH_MAP(CMyCtrl, COleControl)
DISP_FUNCTION_ID(CMyCtrl, "GetCookies", dispidGetCookies, GetCookies, VT_VARIANT, VTS_BSTR)
END_DISPATCH_MAP()
And finally the C++ code must create a SAFEARRAY using SafeArrayCreateEx and provide the IRecordInfo of the UDT, which finally wraps to this:
VARIANT CMyCtrl::GetCookies(LPCTSTR Domain)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
SAFEARRAY* psaCookies = nullptr;
if(AmbientUserMode() && !Unloading || BROWSER_READY)
{
LONG L = Cookies.size();
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = L;
IRecordInfoPtr pRecInfo = nullptr; // DO NOT RELEASE !!!
if(SUCCEEDED(GetRecordInfoFromGuids(LIBID_MyLib, VERSION_MAJOR, VERSION_MINOR, 0, __uuidof(Cookie), &pRecInfo)))
{
psaCookies = ::SafeArrayCreateEx(VT_RECORD, 1, rgsabound, pRecInfo);
if(psaCookies)
{
Cookie* pCookies = NULL;
if(SUCCEEDED(SafeArrayAccessData(psaCookies, reinterpret_cast<PVOID*>(&pCookies))))
{
for(LONG i = 0; i < L; i++)
{
pCookies[i].Name = WSTR_to_BSTR(Cookies[i].Name);
pCookies[i].Domain = WSTR_to_BSTR(Cookies[i].Domain);
pCookies[i].Path = WSTR_to_BSTR(Cookies[i].Path);
pCookies[i].Value = WSTR_to_BSTR(Cookies[i].Value);
pCookies[i].HttpOnly = Cookies[i].HttpOnly;
pCookies[i].Secure = Cookies[i].Secure;
pCookies[i].Expires = Cookies[i].Expires;
VariantCopy(&(pCookies[i].ExpiryDateUTC), &(Cookies[i].ExpiryDateUTC));
}
SafeArrayUnaccessData(psaCookies);
}
}
}
}
VARIANT result;
VariantInit(&result);
if(psaCookies)
{
result.vt = VT_ARRAY | VT_RECORD;
result.parray = psaCookies;
}
return result;
}
Be careful NOT to release the IRecordInfo and the returning VARIANT must be of type VT_ARRAY | VT_RECORD.
The VB6 code looks like this:
Private Sub wxDesigner_OnPageComplete(ByVal URL As String)
Dim Cookies As Variant
Cookies = wxDesigner.GetCookies("foo.com")
End Sub
And in Watches the VARIANT looks like this:
Currently I'm using this function which I've cobbled together from reading several loosely related questions all over the internet. The problem I'm having is that the first time I ran it it returned an error, but unfortunately I haven't been able to reproduce it. Now when I run it it simply returns 0 every time.
DWORD GetAddressOfString(char *input)
{
unsigned char *p = NULL;
MEMORY_BASIC_INFORMATION info;
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, _processID);
for (p = NULL; VirtualQueryEx(process, p, &info, sizeof(info)) == sizeof(info); p += info.RegionSize)
{
if (info.State == MEM_COMMIT && (info.Type == MEM_MAPPED || info.Type == MEM_PRIVATE))
{
char *buffer = new char[info.RegionSize];
SIZE_T bytesRead;
ReadProcessMemory(process, p, &buffer, info.RegionSize, &bytesRead);
for (int i = 0; i <= (info.RegionSize - sizeof(input)); i++)
{
if (memcmp(input, &buffer[i], sizeof(input)) == 0)
{
return i;
}
}
}
}
}
Here's a quick and dirty version that searches for data in itself. If you open up Notepad++, type "SomeDataToFind", replace the pid with the correct value, and run it, it should find the data as well. It might give you something to start with and embellish to suit your needs.
Your code was searching for the wrong length, returning the wrong offset, leaking memory like a sieve, and not always returning a value which is undefined behavior.
#include <Windows.h>
#include <iostream>
#include <string>
#include <vector>
char* GetAddressOfData(DWORD pid, const char *data, size_t len)
{
HANDLE process = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pid);
if(process)
{
SYSTEM_INFO si;
GetSystemInfo(&si);
MEMORY_BASIC_INFORMATION info;
std::vector<char> chunk;
char* p = 0;
while(p < si.lpMaximumApplicationAddress)
{
if(VirtualQueryEx(process, p, &info, sizeof(info)) == sizeof(info))
{
p = (char*)info.BaseAddress;
chunk.resize(info.RegionSize);
SIZE_T bytesRead;
if(ReadProcessMemory(process, p, &chunk[0], info.RegionSize, &bytesRead))
{
for(size_t i = 0; i < (bytesRead - len); ++i)
{
if(memcmp(data, &chunk[i], len) == 0)
{
return (char*)p + i;
}
}
}
p += info.RegionSize;
}
}
}
return 0;
}
int main()
{
const char someData[] = "SomeDataToFind";
std::cout << "Local data address: " << (void*)someData << "\n";
//Pass whatever process id you like here instead.
DWORD pid = GetCurrentProcessId();
char* ret = GetAddressOfData(pid, someData, sizeof(someData));
if(ret)
{
std::cout << "Found: " << (void*)ret << "\n";
}
else
{
std::cout << "Not found\n";
}
return 0;
}
I am trying to debug sporadic access violations that occur inside a boost::interprocess message queue. (access violation reading an address in the shared memory region).
Environment: boost 1.54, VC++2010. Occurs in both Debug & Release builds.
It always occurs on or about line 854 (in case of reception) in message_queue.hpp:
Comments were added by me
recvd_size = top_msg.len; // top_msg points to invalid location
Or line 756 (in case of sending)
BOOST_ASSERT(free_msg_hdr.priority == 0); // free_msg_hdr points to invalid location
It appears as though this is related to the message queue creation. If a message queue is created "properly" (i.e. without the possible race condition), the error never occurs.
Otherwise it might occur on timed_receive() or timed_send() on the queue at seemingly random times.
I came up with a short example that represents the problem:
Unfortunately I cannot run it on Coliru, since it requires two processes.
One has to be started without any parameters, the second with any single parameter.
After a number of runs, one of the processes will crash in message_queue.
#include <iostream>
#include <boost/interprocess/ipc/message_queue.hpp>
#include <boost/thread.hpp>
#include <boost/assert.hpp>
#include <boost/date_time.hpp>
using namespace boost::interprocess;
using namespace boost::posix_time;
using boost::posix_time::microsec_clock; // microsec_clock is ambiguous between boost::posix_time and boost::interprocess. What are the odds?
int main(int argc, wchar_t** argv)
{
while(true)
{
int proc = 0;
message_queue* queues[2] = {NULL, NULL};
std::string names[] = {"msgq0", "msgq1"};
if(1 == argc)
{
proc = 0;
message_queue::remove(names[0].c_str());
if(NULL != queues[0]) { delete queues[0]; queues[0] = NULL; }
queues[0] = new message_queue(open_or_create, names[0].c_str(), 128, 10240);
bool bRet = false;
do
{
try
{
if(NULL != queues[1]) { delete queues[1]; queues[1] = NULL; }
queues[1]=new message_queue(open_only, names[1].c_str());
bRet = true;
}
catch(const interprocess_exception&)
{
//boost::this_thread::sleep(boost::posix_time::milliseconds(2));
delete queues[1];
queues[1] = NULL;
continue;
}
}while(!bRet);
}
else
{
proc = 1;
message_queue::remove(names[1].c_str());
if(NULL != queues[1]) { delete queues[1]; queues[1] = NULL; }
queues[1] = new message_queue(open_or_create, names[1].c_str(), 128, 10240);
bool bRet = false;
do
{
try
{
if(NULL != queues[0]) { delete queues[0]; queues[0] = NULL; }
queues[0]=new message_queue(open_only, names[0].c_str());
bRet = true;
}
catch(const interprocess_exception&)
{
//boost::this_thread::sleep(boost::posix_time::milliseconds(2));
delete queues[0];
queues[0] = NULL;
continue;
}
}while(!bRet);
}
long long nCnt = 0;
for(int i = 0; i < 1; ++i)
{
if(proc)
{
std::string sOut;
sOut = "Proc1 says: Hello ProcA " + std::to_string(nCnt) + " ";
sOut.resize(10230, ':');
for(int n = 0; n < 3; ++n)
{
queues[1]->timed_send(sOut.data(), sOut.size(), 0, ptime(boost::posix_time::microsec_clock::universal_time()) + milliseconds(1));
}
bool bMessage = false;
for(int n = 0; n < 3; ++n)
{
size_t nRec; unsigned int nPrio;
std::string sIn; sIn.resize(10240);
bMessage = queues[0]->timed_receive(&sIn[0], 10240, nRec, nPrio, ptime(boost::posix_time::microsec_clock::universal_time()) + milliseconds(1));
if(bMessage)
{
sIn.resize(nRec);
//std::cout << sIn << " ";
}
}
if(bMessage)
{
//std::cout << std::endl;
}
}
else
{
std::string sOut;
sOut = "Proc0 says: Hello Procccccccdadae4325a " + std::to_string(nCnt);
sOut.resize(10240, '.');
for(int n = 0; n < 3; ++n)
{
queues[0]->timed_send(sOut.data(), sOut.size(), 0, ptime(boost::posix_time::microsec_clock::universal_time()) + milliseconds(1));
}
bool bMessage = false;
for(int n = 0; n < 3; ++n)
{
size_t nRec; unsigned int nPrio;
std::string sIn; sIn.resize(10240);
bMessage = queues[1]->timed_receive(&sIn[0], 10240, nRec, nPrio, ptime(boost::posix_time::microsec_clock::universal_time()) + milliseconds(1));
if(bMessage)
{
sIn.resize(nRec);
//std::cout << sIn << " ";
}
}
if(bMessage)
{
//std::cout << std::endl;
}
}
nCnt++;
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
}
}
return 0;
}
I am still thinking I might be doing something wrong, since I cannot find anything about this problem anywhere else, and the boost libraries are normally very good.
Is there anything I might be doing wrong with the usage of the message_queue in this example?
I don't think that both processes using open_or_create is a supported idiom. Are you aware of this thread on the mailing list? I can't find more discussions so it looks to me like lifetime management wasn't eventually considered necessary to add.
Thus you'll need to synchronise the creation manually with boost::interprocess or possibly by having one of the processes retrying to open_only the queue until the other process creates it.
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;
}