After resizing Custom Task Pane "BeforeFolderSwitch" Event handler stopps being called

E

escamoteur

Hi,

a strange behaviour. I Developed a Custom Task Pane and want to be it visible when the user moves to a certain folder.

This works fine:

private void InitGlobalEvents()
{

Application.ActiveExplorer().BeforeFolderSwitch += new
Microsoft.Office.Interop.Outlook.ExplorerEvents_10_BeforeFolderSwitchEventHandler(Explorer_BeforeFolderSwitch);
}


Here is the handler:


void Explorer_BeforeFolderSwitch(object NewFolder, ref bool Cancel)
{
Cancel = false;
Outlook.Folder newFolder = (Outlook.Folder)NewFolder;
if (newFolder.EntryID == Config.boFolder.EntryID)
{
BO_SummeryPane.Visible = true;
}
else
{
BO_SummeryPane.Visible = false;
}

}

BUT after I resize the Custom Task Pane once, my Eventhandler no longer gets called.

Any idea? (Outlook 2007, C#, COM-AddIn)

Best
Tom
 
K

Ken Slovak - [MVP - Outlook]

If ActiveExplorer().CurrentFolder is changed, or the garbage collector runs
you wouldn't get that event again. I'd eliminate those possibilities first
before thinking it's due to the CTP (which is still possible).

Declare an Explorer object at a class scope so it doesn't go out of scope or
get garbage collected. Add the event to that object. Then see if you still
have a problem.
 
E

escamoteur

Hi Ken,

you solved the problem. Although I'm curious why Outlook would delete the main Explorer Object that I referenced before.

And it happened defenetly always after resizing the the CTP, perhaps this triggered the new Explorer object.
Best
Tom
 
K

Ken Slovak - [MVP - Outlook]

You had no explicit Explorer object that would retain scope, your
intrinsically declared Explorer object that was assigned the event was going
out of scope as soon as that method ended, it was only a matter of time
before the GC ran and destroyed your event handler references.
 
E

escamoteur

Is this because the ExplorerObjects are in reallty only COM-Proxies and not the real Explorer?
Tom
 
K

Ken Slovak - [MVP - Outlook]

No, it would be the case with COM or managed objects, especially when you
use compound dot operators.

For example, take this simple expression inside a procedure:

Outlook.Explorer _exp = _olApp.Explorers[1];

That creates behind the scenes an an Explorers collection as well as the
explicit Explorer object. You can't explicitly release that Explorers
collection, it will go out of scope when that procedure goes out of scope.
It may linger however until the garbage collector finally runs. You have no
control over it. The same would apply to any managed objects declared the
same way, however COM objects are more prone to have problems and cause
memory leaks.

If you were to explicitly declare an Explorers collection and an Explorer
object at class level the objects would retain scope as long as the class
has scope. You can then be confident they will be alive, as will any event
handlers, and you can release the objects when you choose to release them.

This also becomes important in loops where if you let the compiler create
internal variables like that they don't get released within the loop and you
can easily exceed the RPC channel limits when working with Exchange objects.
Then you get memory errors from MAPI.
 
E

escamoteur

So all the Objects that I access from managed code are not the REAL Outlook Objects but they get created as stubs/proxies to
communicate with the Outlook internal objects?

I always thouht that _olApp.Explorers[1] would always return the same object as long as this explorerwindow is open.

Hmm Good to know. So better not use method().object.method() expressions at all

Best
Tom

Ken Slovak - said:
No, it would be the case with COM or managed objects, especially when you use compound dot operators.

For example, take this simple expression inside a procedure:

Outlook.Explorer _exp = _olApp.Explorers[1];

That creates behind the scenes an an Explorers collection as well as the explicit Explorer object. You can't explicitly release
that Explorers collection, it will go out of scope when that procedure goes out of scope. It may linger however until the garbage
collector finally runs. You have no control over it. The same would apply to any managed objects declared the same way, however
COM objects are more prone to have problems and cause memory leaks.

If you were to explicitly declare an Explorers collection and an Explorer object at class level the objects would retain scope as
long as the class has scope. You can then be confident they will be alive, as will any event handlers, and you can release the
objects when you choose to release them.

This also becomes important in loops where if you let the compiler create internal variables like that they don't get released
within the loop and you can easily exceed the RPC channel limits when working with Exchange objects. Then you get memory errors
from MAPI.




escamoteur said:
Is this because the ExplorerObjects are in reallty only COM-Proxies and not the real Explorer? Tom
 
K

Ken Slovak - [MVP - Outlook]

All COM objects are accessed either from a PIA or by reflection
(late-binding). That has nothing to do with where you declare your objects
and what scope you give them or how dot operators work.

The rules of scope would apply equally to purely managed objects. If you set
up a managed class that fires events and instantiate it with a local
variable inside a procedure, that object goes out of scope when the
procedure ends and the event stops firing then. That's exactly the same as
with COM objects.

The problem of multiple dot operators is both a memory problem and a problem
of providing explicit objects you can directly reference (for releasing or
for other reasons). In the case of Exchange objects the internal, implicitly
created objects work. It's just that you can't explicitly reference them to
release them, so they just keep increasing until the RPC channel limit is
exceeded and your code fails.

_olApp.Explorers[1] will always return the same Explorer object as long as
it's not closed, but that has nothing to do with creation of an implicit
Explorers collection you have no control over.
 
E

escamoteur

_olApp.Explorers[1] will always return the same Explorer object as long as
it's not closed, but that has nothing to do with creation of an implicit
Explorers collection you have no control over.

Now I'm a bit confused. If the explorer object is not deleted as long as the Explorer is not closed, why is

Application.ActiveExplorer()

destroyed by the garbage collector if the explorer window is still open?

Best
Tom




escamoteur said:
So all the Objects that I access from managed code are not the REAL
Outlook Objects but they get created as stubs/proxies to communicate with
the Outlook internal objects?

I always thouht that _olApp.Explorers[1] would always return the same
object as long as this explorerwindow is open.

Hmm Good to know. So better not use method().object.method() expressions
at all

Best
Tom
 
K

Ken Slovak - [MVP - Outlook]

That is not an object variable, it is a reference to a specific object.
Completely different things.

If you add your event handler to an object variable it has scope and lives
as long as that object has scope. After that it gets garbage collected.

Application.ActiveExplorer() will always exist as long as there is at least
one Explorer and one is active. However that does not mean that you can just
attach event handlers and expect them to survive unless you explicitly
instantiate an Explorer object variable to that ActiveExplorer() object.

There must be hundreds of posts mentioning loss of event handlers and why
they are going out of scope if not explicitly assigned to objects or if the
objects go out of scope. All I can suggest is taking a look at the scoping
rules for c#.




escamoteur said:
_olApp.Explorers[1] will always return the same Explorer object as long
as it's not closed, but that has nothing to do with creation of an
implicit Explorers collection you have no control over.

Now I'm a bit confused. If the explorer object is not deleted as long as
the Explorer is not closed, why is
Application.ActiveExplorer()

destroyed by the garbage collector if the explorer window is still open?

Best
Tom
 
E

escamoteur

Thanks Ken I understood now. I'm coming from c++, so I'm still not used to the thing tht someone else may free my ressources.

Best
Tom

Ken Slovak - said:
That is not an object variable, it is a reference to a specific object.
Completely different things.

If you add your event handler to an object variable it has scope and lives
as long as that object has scope. After that it gets garbage collected.

Application.ActiveExplorer() will always exist as long as there is at least
one Explorer and one is active. However that does not mean that you can just
attach event handlers and expect them to survive unless you explicitly
instantiate an Explorer object variable to that ActiveExplorer() object.

There must be hundreds of posts mentioning loss of event handlers and why
they are going out of scope if not explicitly assigned to objects or if the
objects go out of scope. All I can suggest is taking a look at the scoping
rules for c#.




escamoteur said:
_olApp.Explorers[1] will always return the same Explorer object as long
as it's not closed, but that has nothing to do with creation of an
implicit Explorers collection you have no control over.

Now I'm a bit confused. If the explorer object is not deleted as long as
the Explorer is not closed, why is
Application.ActiveExplorer()

destroyed by the garbage collector if the explorer window is still open?

Best
Tom
 
K

Ken Slovak - [MVP - Outlook]

Understanding the operation and limitations of the garbage collector,
especially for COM objects, is difficult to figure out at first.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top