MailItem.save() Method

A

Austin Stephens

I am new to the groups. However I did read for two days (Sue does seem to
answer 90 percent of the questions) ïŠ.
I realize this is a VBA group but I am sure my C# code does not enter into
my question.
I create a new MailItem and just want to save it into a Folder other than
the olFolderDrafts.

Here is my starting code:

ApplicationClass o = new ApplicationClass();
NameSpace outlookNS = o.GetNamespace("MAPI");
MAPIFolder folder =
outlookNS.GetDefaultFolder(OlDefaultFolders.olFolderInbox);
Outlook.MailItem newItem = o.CreateItem(OlItemType.olMailItem) as MailItem;
…
newItem.Save();

I would like: |newItem.SaveAs(“???â€, myFolder);| to work but,
SaveAs wants a string Path, plus the Object Type: OlDefaultFolders.


Thanks...
Austin
 
D

Dmitry Streblechenko

Or use MAPIFolder.Items.Add instead of Application.CreaterItem to begin
with.
Also don't forget that Move is a fucntion that returns the newly created
item in the target folder; it is not a sub.

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool
 
A

Austin Stephens

Michael,

Thank you! It’s now:
newItem.Save();
MAPIFolder targetFolder = outlookNS.PickFolder();
newItem.Move(targetFolder);
Dmitry,
It is an honor, sir!
For now I’ll let the user pick the folder. However, after beta I think I’ll
implement your suggestion and pick the folder myself.

As to the “it is not a sub†reference; I’m in C# so it will be a try/catch
and I’ll ignore the return.

Thanks...
Austin
 
M

Michael Bauer

Hi Austin,
As to the “it is not a sub†reference; I’m in C# so it will be a try/catch
and I’ll ignore the return.

that´s ok if you don´t need to handle the item after it is moved.
 
D

Dmitry Streblechenko

Unless of course you don't want to depend on the GC to release all COM
objects. I am not sure that an implicit COM object will be immediately
released. If you however store the returned object in a variable, you will
be able to call Marshal.ReleaseCOMObject.

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool
 
J

Jim Vierra

I have found that you have to be careful on the release. If the object is
still processing a request it seems to get hung if release via
ReleaseComObject. The explicit calls shouldn't need releasing as the GC
will get them as soon as the reference count drops to zero but I don't
believe late bound objects are manages by the GC. Only the reference you
hold is under management. You shouldn't have to do the release under NET
1.1. Wouldn't you agree that the COM subsystem should handle all of that.

In my testing I found that an explicit call to the "release" would often
crash the object if it was Word, Outlook or Excel. I believe that there are
discussions in the KB about this but can't remember how to find them.
 
D

Dmitry Streblechenko

No on all counts:
1. all languages have the ability to release COM objects immediately (e.g.
by setting a variable to Nothing in VB). If one of the objects hangs,
something's wrong with the object. I cannot recall any bugs in Office
related to COM objects hanging when released. Do you have any examples?
2. Explicit release calls are very much needed, especially if you are
running against an Exchange server and you are limited to 255 RPC
channels/process. Just try interating through a folder with a large number
of items... COM is not a native .Net API, and manual tweaking (such as using
ReleaseCOMObjects) is often needed.
3. Both early and late bound objects are managed by the GC in .Net. There is
absolutely no difference between the two kinds when it comes to their
lifetime management.
4. GC will release the COM objects whenever it feels like it, which may be
minutes later. And COM subsystem does not handle "all of that", GC and the
object itself do.
5. What KB articles do you refer to? Any sample code?

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool
 
J

Jim Vierra

Dimity - OK
Why then does a release - not an assignment to "Nothing" - cause the object
to hang in memory if there is a pending request.?
If I do this
'some language
dim o as object
set o = createobject("some.object") ' such as Word.Application

I have a "what" relationship to the actual object?
Is "o" the object - no.
Can I destroy "o" - yes - it's mine.
Why then do some objects - particularly Office object accessed via Interop -
refuse to shut down when released in this way if an operation is pending? If
no operation pending then they shut down correctly.

Same scenario not using NET (such as scripting) the issue seems to not
happen.
 
D

Dmitry Streblechenko

See below

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool

Jim Vierra said:
Dimity - OK
Why then does a release - not an assignment to "Nothing" - cause the
object to hang in memory if there is a pending request.?

In VB6, setting an object to Nothing results in an immediate call to
IUnknown::Release. In .Net it simply adds the object to an internal GC list.
When GC feels it is time to release it (whenever that might be), it will
call IUnknown::Release. It is then up to the COM object's implementation
what it wants to do (GC has no say in this matter) - if the reference count
drops to 0, the COM object can kill itself. Or it can do something entirely
different.
If I do this
'some language
dim o as object
set o = createobject("some.object") ' such as Word.Application

I have a "what" relationship to the actual object?

It is a pointer to IDispatch. Or, to be fully precise, a pointer to an
inproc IDispatch proxy (furnished by the COM runtime) that talks to the
object's implementation in the word.exe process space.
Is "o" the object - no.

Yes, it is.
Can I destroy "o" - yes - it's mine.

It depends. If by "destroy" you mean release *your* reference to that
object - sure. If Word knows that there are outstanding references (some
other app can be referencing it), it will simply decrement its internal
reference counter (see above).
Why then do some objects - particularly Office object accessed via
Interop - refuse to shut down when released in this way if an operation is
pending? If no operation pending then they shut down correctly.

Because somee of them think that a user might still be working with the
object: imagine that your code creates an instance of Word.Application, a
user then starts a new document, then your app releases the COM object. Most
users will be extremely upset if Word were to disappear simply because your
app decided that it no longer needed a pointer.
You can argue what the exact behavior should be, but the important point is
that the COM object itself decides what to do based on whatever it thinks it
appropriate, .Net or GC has no say.
 
J

Jim Vierra

Exactly what I was getting at.

Now consider what happens when "I" have an outstanding call to an "o" and I
destroy it.

If I reference that object or if I trap on the call the COM thinks I am
still busy and COM does not release the object.

This happens frequently with Word and Outlook when called through Interop.
I don't know if it's supposed to do that or if it's a bug/mismatch in the
Interop when called from C#.

I haven't played with it as much as I should so I can't really give a good
set of examples. I decided to stay away from latebound access due to the
effect on Outlook 2003 and Word 2003.
I agree. GC should have no affect on COM objects only on the reference to
the proxy. The COM object should clean up any outstanding calls where the
caller has gone away.

If I set up a callback to Outlook - say "Item_Send" and erase the
application object at the end of the callback Outlook will never shutdown.
Shouldn't be able to do that wouldn't you agree?
 
D

Dmitry Streblechenko

Below

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool

Jim Vierra said:
Exactly what I was getting at.

Now consider what happens when "I" have an outstanding call to an "o" and
I destroy it.

I don't really understand what you mean by "I have an outstanding call to an
"o" and I destroy it.". To be able to call a method on a COM object, you
need to keep a reference to it, which means it is still referenced.
Unlike regular classes (.Net, C++, Delphi, etc), you do not destroy COM
objects. There is simply no way to do that. One of the basic COM principles
is that the COM object itself is responsible for its own destruction. Again,
COM object is not a class. Even if it looks like one (v-table, etc). You can
dereference the object, but you cannot destroy it.
If I reference that object or if I trap on the call the COM thinks I am
still busy and COM does not release the object.

I am not sure what you mean.. COM has absolutely no notion of "busy". You
call AddRef, the object increments its internal reference counter. You call
Release, it decrements it. If it drops down to 0, the object is supposed to
destroy itself. Or do whatever it pleases. There is no such thing as "busy",
especially when it comes to the code that consumes the COM object.
This happens frequently with Word and Outlook when called through Interop.
I don't know if it's supposed to do that or if it's a bug/mismatch in the
Interop when called from C#.

Again, it has nothing to do with .Net or COM. It is Office trying to be
smart and figure out whether it should kill itself or keep itself alive even
if you completely dereference it.
That logic is different in different versions of the Office or maybe
Windows, but it absolutely does not depend on who the caller is. COM objects
neither know nor care.

If I set up a callback to Outlook - say "Item_Send" and erase the
application object at the end of the callback Outlook will never shutdown.
Shouldn't be able to do that wouldn't you agree?

This is a sideeffect of how COM events are supported in .Net. Your event
handler is an object that keeps an internal reference to the COM object in
question. So even if you release your explicit variable, the object is still
referenced by the event handler. Strictly speaking GC should be able to
detect circular references (it does that for the .Net objects), but
apparently it does not work quite well with the COM objects.
 
M

Michael Bauer

Thanks, Dmitry. I forgot that we´re talking about c# and I should have
been quiet, because I don´t know anything about c# :)
 
J

Jim Vierra

So we shouldn't use C# with Outlook? I was beginning to think the same
thing.

If you don't try to do late bound calls the C# access works well. The MS
examples don't work well as each of them has a missing piece of information
it seems. Took me 3 days to find the correct way to call
"MailIItem.Send()".

I also suspect that the misbehavior might be due to running under the
debugger in C#. Is this a good guess?

--
Jim Vierra
Dmitry Streblechenko said:
Neither do I :)
I just know not to use it in anything Outlook related...

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool
 
D

Dmitry Streblechenko

You can never be sure what went wrong...
IMHO using C# doesn't buy you anything when doing any Outlook development,
actually it limits you more than VB6 does and introduces a new layer of code
that can be a potential source of problems - interop and GC are the two most
infamous ones.
It sure makes you feel proud to be using the latest and greatest, but that's
about it. I'd rather be making money and keep my customers happy than spend
nights tracking bugs in a new shiny IDE...

Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool

Jim Vierra said:
So we shouldn't use C# with Outlook? I was beginning to think the same
thing.

If you don't try to do late bound calls the C# access works well. The MS
examples don't work well as each of them has a missing piece of
information it seems. Took me 3 days to find the correct way to call
"MailIItem.Send()".

I also suspect that the misbehavior might be due to running under the
debugger in C#. Is this a good guess?
 
A

Austin Stephens

Jim Vierra, "Dmitry Streblechenko,

“So we shouldn't use C# with Outlook? I was beginning to think the same
thingâ€

Guys you’re starting to scare me. My C# is resulting in .NET CLR. So will
VB. I will agree nobody should be programming in C++ so I’ll leave that
alone. I programmed from ‘84 to ‘94 in C. ’04; I just picked up C# as a
Christmas present, so I “missed†the C++ horror. My experience with C has
taught me just how much C# was needed: we used to have to code all the
managed stuff that C# now provides.

Dislike it if you wish, but please continue to provide answers. You are a
bigger help than you know!

Jim, it’s taken me weeks to write something with C# and Outlook, but if you
ever programmed in C with 90% pointers you know there is a HUGE learning
curve.

Thanks...
Austin


Jim Vierra said:
So we shouldn't use C# with Outlook? I was beginning to think the same
thing.

If you don't try to do late bound calls the C# access works well. The MS
examples don't work well as each of them has a missing piece of information
it seems. Took me 3 days to find the correct way to call
"MailIItem.Send()".

I also suspect that the misbehavior might be due to running under the
debugger in C#. Is this a good guess?
 
D

Dmitry Streblechenko

Using straight unmanaged C or C++ is another extreme example. VB6 is
perfectly adequate for writing COM addins for Outlook. Using
IDispatch-friendly COM libraries was exactly what VB6 was designed to do,
and it does that very nicely. .Net was designed for a totally different
purpose, and COM interop is an afterthought.

Nobody (well, most people) would not rush to use their brand new chainsaw as
a shovel, but that happens everyday when people select a language for their
next project... Language is not a religion, it is a tool. And every job has
the most appropriate tool.

I personally prefer Delphi, even if I don't expect much from Borland anymore
and have no plans to buy their latest compilers (unless they manage to pull
a real miracle).


Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool
 
A

Austin Stephens

Dmitry,

C was written with no particular purpose in mind, save to port some funny
new operating system. C# does have a purpose and that was to write some,
currently funny, Framework which provides a Common Language Runtime. Not bad
for a start. However, I’m using it to, again, write “data driven†programs.
That’s where the program hasn’t a clue what it was intended to do, like a SQL
user interface or a UNIX shell.
My point is C# has no particular purpose, past the Framwork. And thus has
no limits.

Thanks...
Austin
 
D

Dan Mitchell

Dmitry Streblechenko said:
Using straight unmanaged C or C++ is another extreme example. VB6 is
perfectly adequate for writing COM addins for Outlook. Using
IDispatch-friendly COM libraries was exactly what VB6 was designed to
do, and it does that very nicely. .Net was designed for a totally
different purpose, and COM interop is an afterthought.

Even within C/C++ there's a lot of ways to make your life easier -- you
can write code in C++ to use the OOM that's basically as simple as VB
code would be, you just have to use #import -- and then you get all the
other "good" (depending on your tastes) stuff from C++.

That step is optional, you can do all the IDispatch stuff by hand in
C++, but it makes your life a lot harder.

And, again, you can do COM/IDispatch in C if you really really want to,
but that makes your life another step harder.

Heck, you could do all this stuff in assembly if you were insane
enough, but nobody does this sort of thing.

Different languages are good for different things -- if you want to
talk to Microsoft components that provide COM interfaces, then C++/VB
are the best languages for the job because a lot of support from MS has
gone into making that work. I'm sure Delphi is great too if you know
that.

If you want to write big scientific numbercrunching stuff, use Fortran.
If you want to write quick string processing apps, use Perl. etc, etc.

As Dmitry says, C# has a purpose, and that purpose is not necessarily
one that goes nicely with driving bits of Office..

-- dan
 

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