Currently the MFCMAPI uses a single thread to serialize all of the MAPI calls. Mapi provider initializes and stores the folder name, etc as a member variable and then read the mailboxs.
This may result in the slow processing of the exchange messages and attachments. For example, it costly when query for attachment files and wait for it to return. So it would be better if can send a request to read the messages and at same time can do another process (initialize another message).
So, is it possible to query and read messages while initialize for the next next message by IMonikers and IBindStatusCallback::OnDataAvailable.
Or is there any other way to do that?
I have tried to use IMoniker and IStream to read data from exchange server asynchronously, I am trying to use BindToStorage to make an asynchronous bind and read date from OnDataAvailable. The binding code is shown as below.
hRes = CoInitialize(NULL);
CComPtr<IBindCtx> pbc;
CComPtr<IMoniker> pmk;
CComPtr <IStream> lpStream1;
ULONG chEaten = 0;
hRes = CreateBindCtx(0, &pbc);
OLECHAR string[] =
L"Session:3!clsid:10000013-0000-0000-0000-000000000001";
if (FAILED(hRes = MkParseDisplayName(pbc, string, &chEaten, &pmk)))
{
return 0;
}
hRes = pmk->BindToStorage(pbc, NULL, IID_IStream,reinterpret_cast<void **>(&lpStream1));
However when call BindToStorage, it returns Class not Registered.
Does anyone know which part is wrong?
And Is that possible to read data from exchange server asynchronously by this method?
Thanks
Admittedly it's been a while since I closely looked at the MFCMAPI source code, but I don't think it does anything like this.
If you want to retrieve the data asynchronously, you need to start a new thread, initialize MAPI, and do whatever lengthy operation you need to do on that thread.
What kind of data are you trying to read?
MFCMAPI already uses a worker thread to handle QueryRows calls while loading a folder. Beyond that, I wasn't really targeting speed over code clarity/simplicity so I didn't bother with threading.
I'm ignoring your questions about IMoniker and BindToStorage because, for the most part, MAPI is not COM, so I don't see what they have to do with spinning up threads to run MAPI code. If you want to read a stream from a worker thread, just make sure you initialize MAPI on that thread.
Are you trying to redo part of MFCMAPI itself or are you writing code for your own application, using MFCMAPI as a model? If within MFCMAPI, what specific scenario are you targeting?
Related
I am not really seeking code examples, but I'm hoping someone can review my program design and provide feedback. I am trying to figure out how do I ensure I have one instance of my "workflow" running at a time.
I am working in C++.
This is my workflow:
I read rows off of a Postgres database.
If the table has any records, I want to do these instructions:
Read the records and transform them to JSON
Send the JSON document to a remote Web service
Parse the response from the service. The service tells me which records were saved or not saved, based on their primary key.
I delete the successfully saved records
I log the unsuccessful records (there's another process that consumes the logs and so my work is done).
I want to perform all of this threads using a separate thread (or "task", whatever higher-level abstraction is available in C++), and I want to make sure that if my function for [1] gets called multiple times, the additional calls basically get "dropped" if step 1 is already in flight.
In C++, I believe I can use a flag and a mutex. I use a something like std::lock_guard<std::mutex> at the top of my method. Then the next line checks for a flag.
// MyWorkflow.cpp
std::mutex myMutex;
int inFlight = 0;
void process() {
std::lock_guard<std::mutex> guard(myMutex);
if (inflight) {
return;
}
inflight = 1;
std::vector<Widget> widgets = readFromMyTable();
std::string json = getJson(&widgets);
... // Send the json to the remote service and handle the response
}
Okay, let me explain my confusion. I want to use Curl to perform the HTTP request. But Curl works asynchronously. And so if I make the asynchronous HTTP call via Curl, my update function will just return and myMutex will be released, right?
I think in my asynchronous response handler, I need to call a second function that's in MyWorkflow.cpp
void markCompletion() {
std::lock_guard<std::mutex> guard(myMutex);
inFlight = 0; // Reset the inflight flag here
}
Is this the right approach? I am worried that if an exception is thrown anywhere before I call markCompletion(), I will block all future callers. I think I need to ensure I have proper exception handling and always call markCompletion().
I am terribly sorry for asking such a noob question, but I really want to learn to do this the right way.
In Xcode set up a stack of curl_easy_setopt-functions for uploading a file to a server/API, and (after a lot of trial and error) it all works like a charm. After going through several other Q&As i also managed to set up an easy CURLOPT_PROGRESSFUNCTION that looks like this:
static int my_progress_func(void *p,
double t,
double d,
double ultotal,
double ulnow)
{
printf("(%g %%)\n", ulnow*100.0/ultotal);
// globalProgressNumber = ulnow*100.0/ultotal;
return 0;
}
As the upload progresses "0%.. 16%.. 58%.. 100%" is output to the console; splendid.
What i'm not able to do is to actually USE this data (globalProgressNumber) eg. for my NSProgressIndicator; CURL kind of hijacks my App and doesn't allow any other input/output until the progress is complete.
I tried updating IBOutlets from my_progress_func (eg. [_myLabel setStringValue:globalProgressNumber];) but the static int function doesn't allow that.
Neither is [self] allowed, so posting to NSNotificationCenter isn't possible:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"Progressing"
object:self];
My curl function runs from my main class/ window (NSPanel).
Any good advice on how to achieve a realtime/ updating element on my .xib?
CURL [...] doesn't allow any other input/output until the progress is complete.
Are you calling curl_easy_perform from the main thread? If yes, you should not do that since this function is synchronous, i.e it blocks until the transfer finishes.
In other words long running tasks (e.g with network I/O) must run on a separate thread, while UI code (e.g. updating the text of a label) must run on the main thread.
how to achieve a realtime/updating element
You should definitely take care to perform the curl transfer in a separate thread.
This could be easily achieved by wrapping this into an NSOperation with a custom protocol to notify a delegate of the progress (e.g your view controller):
push your operation into an NSOperationQueue,
the operation queue will take care to detach the transfer and run it into an another thread,
on the operation side, you should still use the progress function and set the operation object as the opaque object via the CURLOPT_PROGRESSDATA curl option. By doing so, each time the progress function is called you can retrieve the operation object by casting the void *clientp opaque pointer. Then notify the delegate of the current progress in the main thread (e.g with performSelectorOnMainThread) to make sure you can perform UI updates such as refreshing your NSProgressIndicator.
As an alternative to an NSOperation you can also use Grand Central Dispatch (GCD) and blocks. If possible, I greatly recommend you to work with BBHTTP which is a libcurl client for iOS 5+ and OSX 10.7+ (BBHTTP uses GCD and blocks).
FYI: here's an example from BBHTTP that illustrates how to easily perform a file upload with an upload progress block - this is for iOS but should be directly reusable for OS X.
I've been having some issues getting my method hooks to work. I can get the hook to work if "I" call the method that's being hooked. But when it occurs naturally during the processes operation, it doesn't get hooked. My problem is probably stemming from the fact that I'm actually setting these hooks in my own thread that I've spawned. And apparently the LhSetInclusiveACL() method needs to know the thread that you want to hook. Well, here are my issues...
I don't really care which threads apply the hook, i want them all to be hooked. For example, lets say I want the CreateICW() method from the "gdi32.dll" library hooked for the entire process "iexplorer.exe". Not just from thread ID number 48291 or whatever. Knowing which threads are going to be calling the routines you are interested in hooking requires intimate knowledge of internal workings of the process you are hooking. I'm speculating that is generally not feasible and certainly not feasible for me. Thus its kind of impossible for me to know a priori which thread IDs need to be hooked.
The following code was taken from the "UnmanageHook" example:
extern "C" int main(int argc, wchar_t* argv[])
{
//...
//...
//...
/*
The following shows how to install and remove local hooks...
*/
FORCE(LhInstallHook(
GetProcAddress(hUser32, "MessageBeep"),
MessageBeepHook,
(PVOID)0x12345678,
hHook));
// won't invoke the hook handler because hooks are inactive after installation
MessageBeep(123);
// activate the hook for the current thread
// This is where I believe my problem is. ACLEntries is
// supposed to have a list of thread IDs that should pay
// attention to the MessageBeep() hook. Entries that are
// "0" get translated to be the "current" threadID. I want
// ALL threads and I don't want to have to try to figure out
// which threads will be spawned in the future for the given
// process. The second parameter is InThreadCount. I'm
// kind of shocked that you can't just pass in 0 or -1 or
// something for this parameter and just have it hook all
// threads in that given process.
FORCE(LhSetInclusiveACL(ACLEntries, 1, hHook));
// will be redirected into the handler...
MessageBeep(123);
//...
//...
//...
}
I've added some comments to the LhSetInclusiveACL() method call explaining the situation. Also LhSetExclusiveACL() and the "global" versions for these methods don't seem to help either.
For reference here is the documentation for LhSetExclusiveACL:
/***********************************************************************
Sets an exclusive hook local ACL based on the given thread ID list.
Global and local ACLs are always intersected. For example if the
global ACL allows a set “G” of threads to be intercepted, and the
local ACL allows a set “L” of threads to be intercepted, then the
set “G L” will be intercepted. The “exclusive” and “inclusive”
ACL types don’t have any impact on the computation of the final
set. Those are just helpers for you to construct a set of threads.
EASYHOOK_NT_EXPORT LhSetExclusiveACL(
ULONG* InThreadIdList,
ULONG InThreadCount,
TRACED_HOOK_HANDLE InHandle);
Parameters:
InThreadIdList
An array of thread IDs. If you specific zero for an
entry in this array, it will be automatically replaced
with the calling thread ID.
InThreadCount
The count of entries listed in the thread ID list. This
value must not exceed MAX_ACE_COUNT!
InHandle
The hook handle whose local ACL is going to be set.
Return values:
STATUS_INVALID_PARAMETER_2
The limit of MAX_ACE_COUNT ACL is violated by the given buffer.
***********************************************************************/
Am I using this wrong? I imagine that this is how the majority of implementations would use this library, so why is this not working for me?
You want to use LhSetExclusiveACL instead. This means that any calls across any threads get hooked, except for ones you specify in the ACL.
i'm studying this source base. Basically this is an Anim server client for Symbian 3rd edition for the purpose of grabbing input events without consuming them in a reliable way.
If you spot this line of the server, here it is basically setting the RProperty value (apparently to an increasing counter); it seems no actual processing of the input is done.
inside this client line, the client is supposed to be receiving the notification data, but it only calls Attach.
my understanding is that Attach is only required to be called once, but is not clear in the client what event is triggered every time the server sets the RProperty
How (and where) is the client supposed to access the RProperty value?
After Attaching the client will somewhere Subscribe to the property where it passes a TRequestStatus reference. The server will signal the request status property via the kernel when the asynchronous event has happened (in your case the property was changed). If your example source code is implemented in the right way, you will find an active object (AO; CActive derived class) hanging around and the iStatus of this AO will be passed to the RProperty API. In this case the RunL function of the AO will be called when the property has been changed.
It is essential in Symbian to understand the active object framework and quite few people do it actually. Unfortunately I did not find a really good description online (they are explained quite well in Symbian OS Internals book) but this page at least gives you a quick example.
Example
In the ConstructL of your CMyActive subclass of CActive:
CKeyEventsClient* iClient;
RProperty iProperty;
// ...
void CMyActive::ConstructL()
{
RProcess myProcess;
TSecureId propertyCategory = myProcess.SecureId();
// avoid interference with other properties by defining the category
// as a secure ID of your process (perhaps it's the only allowed value)
TUint propertyKey = 1; // whatever you want
iClient = CKeyEventsClient::NewL(propertyCategory, propertyKey, ...);
iClient->OpenNotificationPropertyL(&iProperty);
// ...
CActiveScheduler::Add(this);
iProperty.Subscribe(iStatus);
SetActive();
}
Your RunL will be called when the property has been changed:
void CMyActive::RunL()
{
if (iStatus.Int() != KErrCancel) User::LeaveIfError(iStatus.Int());
// forward the error to RunError
// "To ensure that the subscriber does not miss updates, it should
// re-issue a subscription request before retrieving the current value
// and acting on it." (from docs)
iProperty.Subscribe(iStatus);
TInt value; // this type is passed to RProperty::Define() in the client
TInt err = iProperty.Get(value);
if (err != KErrNotFound) User::LeaveIfError(err);
SetActive();
}
I am writing an application in Qt to be deployed on Symbian S60 platform. Unfortunately, it needs to have Bluetooth functionality - nothing really advanced, just simple RFCOMM client socket and device discovery. To be exact, the application is expected to work on two platforms - Windows PC and aforementioned S60.
Of course, since Qt lacks Bluetooth support, it has to be coded in native API - Winsock2 on Windows and Symbian C++ on S60 - I'm coding a simple abstraction layer. And I have some problems with the discovery part on Symbian.
The discovery call in the abstraction layer should work synchronously - it blocks until the end of the discovery and returns all the devices as a QList. I don't have the exact code right now, but I had something like that:
RHostResolver resolver;
TInquirySockAddr addr;
// OMITTED: resolver and addr initialization
TRequestStatus err;
TNameEntry entry;
resolver.GetByAddress(addr, entry, err);
while (true) {
User::WaitForRequest(err);
if (err == KErrHostResNoMoreResults) {
break;
} else if (err != KErrNone) {
// OMITTED: error handling routine, not very important right now
}
// OMITTED: entry processing, adding to result QList
resolver.Next(entry, err);
}
resolver.Close();
Yes, I know that User::WaitForRequest is evil, that coding Symbian-like, I should use active objects, and so on. But it's just not what I need. I need a simple, synchronous way of doing device discovery.
And the code above does work. There's one quirk, however - I'd like to have a timeout during the discovery. That is, I want the discovery to take no more than, say, 15 seconds - parametrized in a function call. I tried to do something like this:
RTimer timer;
TRequestStatus timerStatus;
timer.CreateLocal();
RHostResolver resolver;
TInquirySockAddr addr;
// OMITTED: resolver and addr initialization
TRequestStatus err;
TNameEntry entry;
timer.After(timerStatus, timeout*1000000);
resolver.GetByAddress(addr, entry, err);
while (true) {
User::WaitForRequest(err, timerStatus);
if (timerStatus != KRequestPending) { // timeout
resolver.Cancel();
User::WaitForRequest(err);
break;
}
if (err == KErrHostResNoMoreResults) {
timer.Cancel();
User::WaitForRequest(timerStatus);
break;
} else if (err != KErrNone) {
// OMITTED: error handling routine, not very important right now
}
// OMITTED: entry processing, adding to result QList
resolver.Next(entry, err);
}
timer.Close();
resolver.Close();
And this code kinda works. Even more, the way it works is functionally correct - the timeout works, the devices discovered so far are returned, and if the discovery ends earlier, then it exits without waiting for the timer. The problem is - it leaves a stray thread in the program. That means, when I exit my app, its process is still loaded in background, doing nothing. And I'm not the type of programmer who would be satisfied with a "fix" like making the "exit" button kill the process instead of exiting gracefully. Leaving a stray thread seems a too serious resource leak.
Is there any way to solve this? I don't mind rewriting everything from scratch, even using totally different APIs (as long as we're talking about native Symbian APIs), I just want it to work. I've read a bit about active objects, but it doesn't seem like what I need, since I just need this to work synchronously... In the case of bigger changes, I would appreciate more detailed explanations, since I'm new to Symbian C++, and I don't really need to master it - this little Bluetooth module is probably everything I'll need to write in it in foreseeable future.
Thanks in advance for any help! :)
The code you have looks ok to me. You've missed the usual pitfall of not consuming all the requests that you've issued. Assuming that you also cancel the timer and do a User::WaitForRequest(timerStatus) inside you're error handing condition, it should work.
I'm guessing that what you're worrying about is that there's no way for your main thread to request that this thread exit. You can do this roughly as follows:
Pass a pointer to a TRequestStatus into the thread when it is created by your main thread. Call this exitStatus.
When you do the User::WaitForRequest, also wait on exitStatus.
The main thread will do a bluetoothThread.RequestComplete(exitStatus, KErrCancel) when it wants the subthread to exit, where bluetoothThread is the RThread object that the main thread created.
in the subthread, when exitStatus is signalled, exit the loop to terminate the thread. You need to make sure you cancel and consume the timer and bluetooth requests.
the main thread should do a bluetoothThread.Logon and wait for the signal to wait for the bluetooth thread to exit.
There will likely be some more subtleties to deal correctly with all the error cases and so on.
I hope I'm not barking up the wrong tree altogether here...
The question is already answered, but... If you'd use active objects, I'd propose you to use nested active scheduler (class CActiveSchedulerWait). You could then pass it to your active objects (CPeriodic for timer and some other CActive for Bluetooth), and one of them would stop this nested scheduler in its RunL() method. More than this, with this approach your call becomes synchronous for the caller, and your thread will be gracefully closed after performing the call.
If you're interested in the solution, search for examples of CActiveSchedulerWait, or just ask me and I'll give your some code sample.