Link to home
Start Free TrialLog in
Avatar of Member_2_1348041
Member_2_1348041Flag for Ireland

asked on

Open files...

Given a Process (Process ID, whatnot), is it possible to establish what files are currently in use / locked by that process?

I've looked all over but I can't find a good example of this. A lot of talk about internal windows APIs (getNth something or other) immediately followed by dire warnings that you shouldn't use those. Fine. But then what SHOULD you use?

Please, a simple example in VB.NET, if you don't mind. C# at a push, but preferably VB.NET

Thank you kindly.
Avatar of ste5an
ste5an
Flag of Germany image

Well, as you want it simple: Imho there's no simple solution.

Especially that this task requires a kernel driver. For details see Listing Used Files.
As ste5an told there are no simple solution. Again, it depends on your task what solution you may use. Read this for a VB.Net example: [URL="http://www.xtremevbtalk.com/showthread.php?t=297132"]Determine if File is in Use[/URL]
Avatar of Member_2_1348041

ASKER

Ugh.... seriously?
Yup. It's time to get the C/C++ from the attic and free it from all the dust :)

When you really need it: then there is imho no other solution than setting up a secondary C/C++ solution (e.g. a Windows service) and IPC with it.

Another approach: use Handle. But this requires a complex setup, cause you're imho not allowed to distribute it.
I just tried "Handle" but it doesn't work. For example, I opened an excel spreadsheet, and then ran "Handle excel". It gave me a list of DLLs it was using, which is lovely, but the .xlsx file that I had just opened was not among the list of files...

Maybe I'm barking up the wrong tree altogether. Here's the actual situation I need to deal with:

We have created an Outlook Add-in. This Add-in stores messages from outlook into our repositories, by saving them out as .msg files. When someone opens a message, the system checks whether that message is already stored in the system. This is where the pain starts.

If we were just looking at messages in Outlook, it would be so easy. All we would need to do in that case is get the sender's SMTP address and the date/time on which the message was sent, and use that as a "key" in our database, in order to check whether information about that message is already stored. Now Outlook doesn't even make your life easy there, but thankfully there is a product called "Redemption" that works around some of those limitations, and it pretty much always works.

But if you're outside Outlook, all you have is the .msg file. When you launch that, it starts Outlook alright, but the message in question won't have an EntryID. Now I worked around THAT problem  by moving the MailObject into the Deleted Items folder, which is equivalent to making it part of Outlook's actual message store rather than an external .msg file, at which point it does get an EntryID.

But now I have found a number of scenarios in which even then I am unable to establish the sender's SMTP address. Even Redemption is powerless to help, here. So if only I know which .msg file was opened.... I have a "MSG Reader" class that can open .MSG files and read information out of them. But do you think Outlook exposes something like a ".filename" property on the MailItem object? Mwahhaaahahahahahaahahahahah [twitching eyelid]

So I thought "you know what, all I need to do is find out which files have been opened by Outlook"

But obviously that is a non-runner as well.


gngngngngng


*pop* goes the aneurysm
ASKER CERTIFIED SOLUTION
Avatar of ste5an
ste5an
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Well, now. First of all, SMTP address + sent date/time is pretty much unique. None of our customers will ever be archiving SPAM, and other than that I can see no conceivable scenario in which the same sender would send more than one message at the same second.

Having said that, the "hash" scenario can't work either. What would I be "hashing" when I'm in an actual Outlook message? There is no guarantee that the "hash" would be the same if: a) a user saves the message more than once or (even worse) b) two different recipients save the same message.
The problem is that there are so many different ways to access what to the human looking at it would be "the same message". A user could have the message sitting in their Inbox in outlook. Another user could open the saved .msg from our software's "message store". Even the latter is not consistent. One user could open the saved .msg from our message store through our software, another one could bypass our software and navigate directly to it. A third user could manually save the message into their own file system and open it from there. In all these scenarios it should accurately identify that message as having already been stored. Hilarious *sob*
First of all, SMTP address + sent date/time is pretty much unique. None of our customers will ever be archiving SPAM, and other than that I can see no conceivable scenario in which the same sender would send more than one message at the same second

Yes and no. Write mails off-line and go online again. tada.

Having said that, the "hash" scenario can't work either. What would I be "hashing" when I'm in an actual Outlook message? There is no guarantee that the "hash" would be the same if: a) a user saves the message more than once or (even worse) b) two different recipients save the same message.

Hash the entire message. In a clean OOP architecture you have already your own class encapsulating messages. Thus use the GetHash() method of this class. Implement GetHash(). For Outlook messages it's afaik quite simple: Each message has a path according to its storage. Use this path (Namespace (name or StoreID) and Folder(EntryID or FolderPath)).

a) When the hash differs, the message differs. Why ignoring those differences?
b) When the hash is the same, then the messages are the same. Why does the recipient play a role?
> Use this path (Namespace (name or StoreID) and Folder(EntryID or FolderPath))

No can do. Imagine an organisation X, in which person A sends an e-mail to persons B, C and D

Person B simply leaves the message in his or her Inbox
Person C has a rule set up that moves the message to some other Outlook folder
Person D saves the message to their hard drive as a .msg file (people do silly things)

Person B opens the message and uses our Add-in to store it in our repository. Obviously, when Person B opens the message a second time it should tell him or her that the message is stored in our repository.

When person C opens the message from their different location, the Add-in must identify the message as having already been stored in the repository. So, by the way, must it be when the sender (Person A) of the message opens the message from their Sent Items folder. And when person D double-clicks on the .msg file.... you guessed it.
That's exactly what I've described. You load a message into your class. The source is not important. Your class implements GetHashCode(). The actual loading and the actual GetHashCode() is implemented with the strategy pattern. The strategy depends on the source type and is provided by a builder. After loading it, you can query your add-ins store for messages with the same hash. Thus disabling further processing.
ok, I'm afraid that went way over my head.

> "Your class" - what class?

> GetHashCode()
Well, as far as I understand this, Hashing processes binary data and produces from that a short "hash", a string or whatnot, that is almost guaranteed to be unique. Well, this is the problem, isn't it? MAYBE, and I wouldn't even count on THAT, Outlook would produce identical Binary objects when it loads the various copies of the message from A's Sent Item folders and from B and C's Outlook folders. But I'm pretty damn sure that it will not produce an identical Binary object from opening D's ".msg" copy of the e-mail.

What *might* work is this: I could take the .Body (text) from the MailItem object, and produce a Hash from that.
"Your class" - what class?

Okay, let's talk about OOP:

You said that you store messages in your own add-in, right? How do you do this?

Object oriented programming tells use to encapsulate entities in classes. Thus there should be a class Message in your source tree. Does such a class exist?
Okay, let's talk about Outlook Add-ins.....

Messages are presented to me, through the magic Voodoo of Outlook, as so-called MailItem objects. Where they come from and where they go is a mystery to confound. All we can do in our data repository is store metadata about said objects. We do not store the objects themselves, nor is the software retrieving them from our data repository. Outlook does all that. We're at its mercy. And it's a sea of pain we're swimming in.
So you have an open handler where your add-in hooks into?
How do you read and store the meta-data?
Outlook exposes events for its "Explorer"s (which are, essentially, the outlook folders such as "Inbox", "Sent Items", "Deleted Items" and so on, and for its "Inspector"s (which are the "windows" that host the message when it's displayed to the user. When that event triggers you can, in your "Add-in" code, do things like ask Outlook to give your Explorer's Selected Items or your Inspector's CurrentItem, which may (or may not) be an object of type Outlook.MailItem (it can also be an Appointment or a number of other object types).

For example, when a user double-clicks on a .msg file, the Add-in would register that a new Inspector object is loaded, and then access its CurrentItem object, cast it to an Outlook.MailItem and then discover that is has no EntryID or that it's impossible to establish the SMTP address for the MailItem's Sender.
I read data directly from the MailItem object by accessing its properties, or in some cases I have to use "Redemption" - for example when I want to get the SMTP address for an Exchange sender (if you get the Address directly from Outlook itself it'll give you some insanely formatted mail address in Exchange format, which makes no sense to anyone).

We store the mail items by using the .SaveAs function to create a ".msg" copy, and then storing that copy away. But the user doesn't see that, nor do they care. They may still see the message in Outlook and open it from there.
We need the .msg copy because - to continue with the above example - while the e-mail is still happily sitting in A's Sent Items, B's Inbox and C's personal folder, D may well have deleted the message from Outlook and then access it again through our application's repository, or it could even be a case of E (another person in the organisation who was never involved in the e-mail exchange) finding the message in our application and launching it from there.
I read data directly from the MailItem object by accessing its properties,

How and where do you store this values? These values should be stored in one object per MailItem. And the GetHashCode of this class is your key. Additionally as you said you store the .msg file, the hash of the file is also a property of this class
[bashes head against desk]

Please... it's *outlook*. Outlook is a Microsoft product. We have NO control over how Microsoft handles its MailItem objects internally, how it creates them from its own storage and how it stores them. We have NO control over how Microsoft saves an Outlook MailItem object when the user chooses "Save As" and decides to save it as a .msg file on their own hard disk. All we can do is consume the MailItem objects if and when Microsoft deigns to expose these to us.
Sorry, but I have to give up...

Seems that the data from Outlook tunnels to your add-in...
Yup. Let me tell you something. If somebody ever suggests to you that you should develop an Outlook Add-in for them, RUN. RUN LIKE THE WIND. And don't look back. LOL - but seriously, it's friggin' evil. It's like Microsoft have gone out of their way to make a developer's life hell.

Thanks for trying to help though. It's appreciated.
However, while this is ugly and by no means foolproof, your idea of Hashing is not a bad one. It's just that I may have to do it with something that is not likely to change, for example the message subject and the message body, in combination with the sent date/time. I might apply that as a "fallback" for when Outlook and Redemption fail to generate an intelligible SMTP Address from the MailItem object. It's not ideal, but it's better than a kick in the teeth. So I'll give you the poinks for that.