473,387 Members | 1,548 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

CDO, C# and file-locking problem.

I have created a windows service that reads emails from a
drop directory and moves them to the appropriate mail
folder every 15 seconds. I can move, rename and delete
the files as needed, up until the
CDO.DropDirectory.GetMessages() method is called. At
this point, the files are locked until I shut down the
service. After processing and delivery, I need to be
able to delete all the files in the drop directory.

I can delete them via Windows Explorer, but when using my
C# service and the DropDirectory.GetMessages().DeleteAll
() method I receive the error "One or more messages could
not be deleted" and none of the messages are deleted.
Attempts to use other methods to delete the files, such
as FileInfo objects, also result in no file deletion and
errors being thrown.

However, when I shut down the service, it does finally
clear out the folder. It seems like the CDO object only
marks the files for deletion and locks them until it can,
which seems to be only when the CDO object is permanently
destroyed. Is there any way to force the CDO object to
immediately DeleteAll() messages?
Nov 22 '05 #1
5 5431
Hi Matt,
From your description, you try to use getmessages and deleteAll to delete
all the message in the drop directory.
Am I right?

As you guessed before, you need update after using deleteall method.

Here is the reason:
Each time a message is opened and a property is viewed, the message becomes
locked and other application will recieve an error when they attempt to
open the message.

I suggest you calling msg.datasource.save to update. Please let me know if
it works. Thanks!
Rhett Gong[MS]
Microsoft Online Partner Support

This posting is provided "AS IS" with no warranties, and confers no rights.
Please reply to newsgroups only. Thanks.



Nov 22 '05 #2
That didn't work. When I tried to loop through all
messages after reading the properties (to deliver them) I
got an Access Denied message.

However, I finally did get it working by calling
GC.Collect() before I attempted to DeleteAll().

There seems to be no other way to explicitly release the
messages.

-----Original Message-----
Hi Matt,
From your description, you try to use getmessages and deleteAll to deleteall the message in the drop directory.
Am I right?

As you guessed before, you need update after using deleteall method.
Here is the reason:
Each time a message is opened and a property is viewed, the message becomeslocked and other application will recieve an error when they attempt toopen the message.

I suggest you calling msg.datasource.save to update. Please let me know ifit works. Thanks!
Rhett Gong[MS]
Microsoft Online Partner Support

This posting is provided "AS IS" with no warranties, and confers no rights.Please reply to newsgroups only. Thanks.



.

Nov 22 '05 #3
Hello Matt,

I reviewed the complete thread and would like to jump in to provide some
information.

Without your complete source code, I have not clear understanding at this
time. To keep us on the same page about the issue, I assume the issue as
follows. If I made any misunderstanding, please let me know.

====
You initialize DropDirectory object to open drop directory and call
GetMessages and get reference to all messages collection under the
directory. After that, enumerate all messages under the directory in the
collection to deal with them one by one, such as rename, move, delivery,
reply or others. After that, you and then perform deletion by call
deleteall().

At the time, you encournter the error: One or more messages could not be
deleted.
===

I wonder if all messages are closed before you call deleteall()? For
example, if you want to move or copy some messages into another directory,
you may open a file stream to open a message file. Did you make sure you
close it after completing operation?

Here is simple VB sample to do similiar thing. I know you are working with
C# and I just provided it for your reference.

Dim iDropDir as New CDO.DropDirectory

Dim iMsgs as CDO.IMessages

Dim iMsg as CDO.Message

Dim iStream as ADODB.Stream

Dim strTo as String

Dim ToRecipients as Variant

Dim strEmailName as String

Dim strAccountName as String

Dim strFileName as String

Dim strMailboxDir as String

Set iMsgs = iDropDir.GetMessages

For Each iMsg in iMsgs

strFileName = iMsgs.FileName(iMsg)

' trim to get the short file name

' from the full path

strFileName = Right(strFileName, Len(strFileName) -
InStrRev(strFileName,"\")
)

' Get the To recipients...and assume they are all local accounts

strTo = iMsg.To

ToRecipients = Split(strTo,",")

Dim j, lpos, rpos, posdiff

' loop through recipients and get account names for each

' Each address will be in either the "Name" <na**@micrsoft.com> or

' simply <na**@microsoft.com>

' We get the account name by getting the string

' between "<" and "@"

For j = LBound(ToRecipients) to UBound(ToRecipients)

strEmailName = ToRecipients(j)

lpos = InStr(strEmailName,"<")

rpos = InStr(strEmailName,"@")

posdiff = rpos - lpos - 1

strAccountName = Mid(strEmailName,lpos + 1, posdiff)

' For the purposes of this example,

' each account's mailbox directory resides in the

' directory c:\mailboxes. For user Joe, their account

' directory would be c:\mailboxes\joe

strMailboxDir = "c:\mailboxes\" & strAccountName

' Get the message stream

Set iStream = iMsg.GetStream

' write the stream to the user's mailbox directory

' the file name is the same as the one in the drop directory

iStream.SaveToFile strMailboxDir & "\" & strFileName

iStream.Close

Set iStream = Nothing

Next j

Next iMsg

' once we're done, delete the picked up messages

' this deletes the files from the file system as well.

iMsgs.DeleteAll

Set iMsgs = Nothing

Set iDropDir = Nothing
If my information doesn't help, please provide a complete repro sample. I
may investigate it by checking its souce code. Thank you!

Regards,
Justin Wan
Microsoft Partner Online Support

This posting is provided "AS IS" with no warranties, and confers no rights.

Nov 22 '05 #4
Everything is being closed. Also, I have tried
processing the mails, then not performing a DeleteAll()
until before the next mail processing 15 seconds later
and it still hangs up. It works as it is as long as I
include the GC.Collect() call.

Source code:
using System;
using System.Data;
using System.IO;
using System.Text;
using CDO;
using System.Configuration;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace MailService
{
/// <summary>
/// Contains methods used for copying e-mail
messages from a drop folder to
/// the appropriate recipients' inboxes.
/// </summary>
public class SmtpReceive:IDisposable
{
private String _dropDirectory =
@"C:\Inetpub\mailroot\Drop";
private String _tempDirectory =
@"C:\Inetpub\mailroot\Temp";
private String _badmailDirectory =
@"C:\Inetpub\mailroot\Badmail";
private String _mailboxDirectoryPrefix =
@"C:\Inetpub\mailroot\Mailbox\";
private String _mailboxDirectorySuffix =
@"\inbox";
private String _emailSuffix
= "@myDomain.net";
private EventLog log;
private String _machineName = "MYMACHINE";

// Pointer to an external unmanaged
resource.
private IntPtr handle;
// Track whether Dispose has been called.
private bool disposed = false;
/// <summary>
/// Default constructor.
/// </summary>
public SmtpReceive()
{
this.handle = handle;
log = new EventLog("Application",
_machineName, "MailService.exe:SMTPReceive");
}
/// <summary>
/// Checks to see if the specified path
exists; if not, create it.
/// </summary>
/// <param name="directoryPath">Path to
be validated/created.</param>
private void ValidateDirectory(String
directoryPath)
{
try
{
DirectoryInfo di = new
DirectoryInfo(directoryPath);
if(!di.Exists)

Directory.CreateDirectory(directoryPath);
}
catch(Exception ex)
{
log.WriteEntry("Error in
ValidateDirectory: " + ex.Message);
}
}
/// <summary>
/// Gets all the email addresses in the
drop directory and delivers them
/// to the recipients.
/// </summary>
public void Receive()
{
ValidateDirectory(_tempDirectory);
ValidateDirectory
(_badmailDirectory);
//move emails to a temp directory
so we know that no more will be added
//during processing:
FileMove(_dropDirectory,
_tempDirectory);
ProcessMails();
DeleteTempFiles();
}
private void ProcessMails()
{
CDO.DropDirectory drop = new
CDO.DropDirectory();
CDO.IMessages imsg;
imsg = drop.GetMessages
(_tempDirectory);
try
{
for(int i=1; i <=
imsg.Count; i++)
{
string fileName =
imsg.get_FileName(i);
string[]
toAddresses = null;
string[]
ccAddresses = null;
string[]
bccAddresses = null;
try
{
//get
email addresses to send to

toAddresses = imsg[i].To.Split(Convert.ToChar
(","));

ccAddresses = imsg[i].CC.Split(Convert.ToChar
(","));

bccAddresses = imsg[i].BCC.Split(Convert.ToChar
(","));
//get rid
of extra whitespace and other unneeded characters

FixArrayStrings(ref toAddresses);

FixArrayStrings(ref ccAddresses);

FixArrayStrings(ref bccAddresses);
}
catch
{
//bad
mail, drop in BadMail directory
string
badMailPath = _badmailDirectory + @"\" + Path.GetFileName
(fileName);
FileInfo
fi1 = new FileInfo(fileName);
FileInfo
fi2 = new FileInfo(badMailPath);
// Create
the file and clean up handles.
using
(FileStream fs = fi1.Create()) {}
//Ensure
that the target does not exist.
fi2.Delete
();
//Copy
the file.
fi1.CopyTo
(badMailPath,true);
}

//copy email file
to imail folders
//Send "To":
if(toAddresses !=
null)
{
foreach
(string s in toAddresses)
{

CopyMail(fileName, s);
}
}
if(ccAddresses !=
null)
{

//Send "CC":
foreach
(string s in ccAddresses)
{

CopyMail(fileName, s);
}
}
if(bccAddresses !
= null)
{

//Send "BCC":
foreach
(string s in bccAddresses)
{

CopyMail(fileName, s);
}
}
}
}
catch(Exception ex)
{
log.WriteEntry("Error in
ProcessMails: " + ex.Message);
}
finally
{
int iRefCount =
Marshal.ReleaseComObject( drop );
Marshal.ReleaseComObject
(imsg);
/*
* THIS IS THE CALL
TO GC.Collect() THAT SOLVES THE PROBLEM:
*/
GC.Collect();
}
}
/// <summary>
/// Delete temporary files after
processing
/// </summary>
private void DeleteTempFiles()
{
CDO.DropDirectory drop = new
CDO.DropDirectory();
try
{
drop.GetMessages
(_tempDirectory).DeleteAll();
}
catch(Exception ex)
{
log.WriteEntry("Error in
DeleteTempFiles: " + ex.Message);
}
finally
{
int iRefCount =
Marshal.ReleaseComObject( drop );
}
}
/// <summary>
/// Copy file from drop directory to
recipient's inbox
/// </summary>
/// <param name="fileName">Name of the
file to copy</param>
/// <param name="recipient">Email address
of the recipient</param>
private void CopyMail(string fileName,
string recipient)
{
try
{
string userID =
recipient.Substring(0, (recipient.Length -
_emailSuffix.Length));
string suffix =
recipient.Substring(recipient.Length -
_emailSuffix.Length);
if(suffix != _emailSuffix)
return;

string mailbox =
_mailboxDirectoryPrefix + userID +
_mailboxDirectorySuffix;
string inboxPath =
Path.Combine(mailbox, Path.GetFileName(fileName));
FileInfo fi1 = new
FileInfo(fileName);

//check to see if mailbox
exists, create if not
ValidateDirectory
(mailbox);
fi1.CopyTo(inboxPath,
true);
fi1 = null;
}
catch(Exception ex)
{
log.WriteEntry("Error in
CopyMail: " + ex.Message);
}
}
/// <summary>
/// Trims all whitespace from each string
in the array, converts all characters
/// to lowercase and extracts the e-mail
address from the field.
/// </summary>
/// <param name="arr">The array to be
cleansed.</param>
private void FixArrayStrings(ref string[]
arr)
{
try
{
if((arr.Length == 1) &&
(arr[0].Length == 0))
{
arr = null;
return;
}
for(int i = 0; i <
arr.Length; i++)
{
arr[i] = arr
[i].Trim();
arr[i] = arr
[i].ToLower();
arr[i] = arr
[i].Remove(0, arr[i].IndexOf("<") + 1);
arr[i] = arr
[i].Remove(arr[i].IndexOf(">"), arr[i].Length - arr
[i].IndexOf(">"));
}
}
catch(Exception ex)
{
log.WriteEntry("Error in
FixArrayStrings: " + ex.Message);
}
}
/// <summary>
/// Moves files from one directory to
another
/// </summary>
/// <param name="srcdir">The source
directory</param>
/// <param name="destdir">The destination
directory</param>
private void FileMove(string srcdir,
string destdir)
{
try
{
DirectoryInfo dir;
FileInfo[] files;
string tmppath;

//determine if the
destination directory exists, if not create it
ValidateDirectory
(destdir);

dir = new DirectoryInfo
(srcdir);

//if the source dir
doesn't exist, throw
if (! dir.Exists)
{
throw new
ArgumentException("source dir doesn't exist -> " +
srcdir);
}

//get all files in the
current dir
files = dir.GetFiles();

//loop through each file
foreach(FileInfo file in
files)
{
//create the path
to where this file should be in destdir

tmppath=Path.Combine(destdir,
file.Name);

//copy file to
dest dir
file.MoveTo
(tmppath);
}
//cleanup
files = null;
dir = null;
}
catch(Exception ex)
{
log.WriteEntry("Error in
FileMove: " + ex.Message);
}
}
#region IDisposable Members

/// <summary>
/// Dispose
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);

}
private void Dispose(bool disposing)
{
// Check to see if Dispose has
already been called.
if(!this.disposed)
{
CloseHandle(handle);
handle =
IntPtr.Zero;
}
disposed = true;
}

[System.Runtime.InteropServices.DllImport
("Kernel32")]
private extern static Boolean CloseHandle
(IntPtr handle);

/// <summary>
/// Destructor
/// </summary>
~SmtpReceive()
{
Dispose(false);
}
#endregion
}
}
-----Original Message-----
Hello Matt,

I reviewed the complete thread and would like to jump in to provide someinformation.

Without your complete source code, I have not clear understanding at thistime. To keep us on the same page about the issue, I assume the issue asfollows. If I made any misunderstanding, please let me know.
====
You initialize DropDirectory object to open drop directory and callGetMessages and get reference to all messages collection under thedirectory. After that, enumerate all messages under the directory in thecollection to deal with them one by one, such as rename, move, delivery,reply or others. After that, you and then perform deletion by calldeleteall().

At the time, you encournter the error: One or more messages could not bedeleted.
===

I wonder if all messages are closed before you call deleteall()? Forexample, if you want to move or copy some messages into another directory,you may open a file stream to open a message file. Did you make sure youclose it after completing operation?

Here is simple VB sample to do similiar thing. I know you are working withC# and I just provided it for your reference.

Dim iDropDir as New CDO.DropDirectory

Dim iMsgs as CDO.IMessages

Dim iMsg as CDO.Message

Dim iStream as ADODB.Stream

Dim strTo as String

Dim ToRecipients as Variant

Dim strEmailName as String

Dim strAccountName as String

Dim strFileName as String

Dim strMailboxDir as String

Set iMsgs = iDropDir.GetMessages

For Each iMsg in iMsgs

strFileName = iMsgs.FileName(iMsg)

' trim to get the short file name

' from the full path

strFileName = Right(strFileName, Len(strFileName) -
InStrRev(strFileName,"\")
)

' Get the To recipients...and assume they are all local accounts
strTo = iMsg.To

ToRecipients = Split(strTo,",")

Dim j, lpos, rpos, posdiff

' loop through recipients and get account names for each

' Each address will be in either the "Name" <na**@micrsoft.com> or
' simply <na**@microsoft.com>

' We get the account name by getting the string

' between "<" and "@"

For j = LBound(ToRecipients) to UBound(ToRecipients)

strEmailName = ToRecipients(j)

lpos = InStr(strEmailName,"<")

rpos = InStr(strEmailName,"@")

posdiff = rpos - lpos - 1

strAccountName = Mid(strEmailName,lpos + 1, posdiff)

' For the purposes of this example,

' each account's mailbox directory resides in the

' directory c:\mailboxes. For user Joe, their account

' directory would be c:\mailboxes\joe

strMailboxDir = "c:\mailboxes\" & strAccountName

' Get the message stream

Set iStream = iMsg.GetStream

' write the stream to the user's mailbox directory

' the file name is the same as the one in the drop directory
iStream.SaveToFile strMailboxDir & "\" & strFileName

iStream.Close

Set iStream = Nothing

Next j

Next iMsg

' once we're done, delete the picked up messages

' this deletes the files from the file system as well.

iMsgs.DeleteAll

Set iMsgs = Nothing

Set iDropDir = Nothing
If my information doesn't help, please provide a complete repro sample. Imay investigate it by checking its souce code. Thank you!

Regards,
Justin Wan
Microsoft Partner Online Support

This posting is provided "AS IS" with no warranties, and confers no rights.
.

Nov 22 '05 #5
Hi Matt,

To make sure all files/messages are closed, please install process explorer
from http://www.sysinternals.com/ntw2k/fr.../procexp.shtml to check it.

Regards,
Justin Wan
Microsoft Partner Online Support

This posting is provided "AS IS" with no warranties, and confers no rights.

Nov 22 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: Dave Smithz | last post by:
Hi There, I have a PHP script that sends an email with attachment and works great when provided the path to the file to send. However this file needs to be on the same server as the script. ...
5
by: simon place | last post by:
is the code below meant to produce rubbish?, i had expected an exception. f=file('readme.txt','w') f.write(' ') f.read() ( PythonWin 2.3 (#46, Jul 29 2003, 18:54:32) on win32. ) I got...
3
by: Pernell Williams | last post by:
Hi all: I am new to Python, and this is my first post (and it won't be my last!), so HELLO EVERYONE!! I am attempting to use "xreadlines", an outer loop and an inner loop in conjunction with...
7
by: Joseph | last post by:
Hi, I'm having bit of questions on recursive pointer. I have following code that supports upto 8K files but when i do a file like 12K i get a segment fault. I Know it is in this line of code. ...
3
by: StGo | last post by:
How can i read/write file's custom attributs(like subject,author...) in C#??? Thanks :))
13
by: Sky Sigal | last post by:
I have created an IHttpHandler that waits for uploads as attachments for a webmail interface, and saves it to a directory that is defined in config.xml. My question is the following: assuming...
3
by: Shapper | last post by:
Hello, I created a script to upload a file. To determine the file type I am using userPostedFile.ContentType. For example, for a png image I get "image/png". My questions are: 1. Where can...
0
by: troutbum | last post by:
I am experiencing problems when one user has a document open through a share pointing to the web site. I use the dsolefile to read the contents of a particular directory and then display them in a...
1
by: Mika M | last post by:
I have made Setup and Deployment Project for my application. This application uses couble of Crysral Report .rpt -files, so I included following into Setup and Deployment Project ... -...
2
by: Derik | last post by:
I've got a XML file I read using a file_get_contents and turn into a simpleXML node every time index.php loads. I suspect this is causing a noticeable lag in my page-execution time. (Or the...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.