 |
|
 |
Dear friend,
i am very sorry if i am wrong. because i am new to this.
please tell me how to change the File summary information ??
i could not understand your code.
My Problem is i have own file type and i want to change the file summary through c# can u please tell me how to do that?
i searched in Google
"http://forums.asp.net/p/1050538/1483362.aspx#1483362"
from here i came to your article.
Thank you.
Joe.I
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
This is quite a complicated topic:
- For compound files, such as Office documents, the summary information is stored in the file.
- Office 2007 files can be manipulated with the OpenXML SDK[^];
- For older file versions, you need to use the DSOFile[^] component;
- In Vista, most of the summary information is stored within the file; this is why the available fields varies depending on the file type.
- In older versions of Windows, the information is stored in an alternate data stream, and can be manipulated via the IPropertySetStorage[^] interface.
Unfortunately, I've not done much work with these components, so you'd probably be better off asking in the forums.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks For your Replay.
the funnything is i have posted my question in codeproject forum and one again gave me like to your artical.
http://www.codeproject.com/Forums/1649/Csharp.aspx?fid=1649&select=3102914&fr=1#xx3102914xx
any way thank u friend for your help.
and i shall work on it.
By
Joe
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi, I need a simple sample code to writing a alternative data stream called test with this value "hello ADS" for a file and a simple code for reading the value of that data stream (test). Is there anybody can write it for me here.
thanks
modified on Wednesday, June 10, 2009 3:24 AM
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Try this:
using System; using System.IO; using Trinet.Core.IO.Ntfs;
static class Program { static void Main() { try { string fileName = Path.GetFullPath("Your File Path Here"); if (!File.Exists(fileName)) { Console.WriteLine("Test file not found."); } else { WriteTestStream(fileName); ReadTestStream(fileName); } } catch (Exception ex) { Console.WriteLine(ex); } } static void WriteTestStream(string fileName) { var info = FileSystem.GetAlternateDataStream(fileName, "Test"); using (var fileStream = info.OpenWrite()) using (var writer = new StreamWriter(fileStream)) { writer.Write("hello ADS"); } } static void ReadTestStream(string fileName) { var info = FileSystem.GetAlternateDataStream(fileName, "Test"); if (info.Exists) { Console.WriteLine("Alternate data stream found:"); using (var reader = info.OpenText()) { Console.WriteLine(reader.ReadToEnd()); } } else { Console.WriteLine("Alternate data stream not found: {0}", info); } } }
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
 |
Strange - I'm using Vista SP1 (32-bit), and it works fine!
To list the streams, your process will need SE_BACKUP_NAME and SE_RESTORE_NAME privileges. To test for a specific stream, or to create, open or delete a stream, you should just need access to the file.
using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using Trinet.Core.IO.Ntfs;
static class Program { static void Main() { try { TestStream(new FileInfo("test.jpg")); } catch (Exception ex) { Console.WriteLine(ex); } } static void TestStream(FileInfo file) { var streams = file.ListAlternateDataStreams(); if (0 == streams.Count) { Console.WriteLine("No streams found."); } else { Console.WriteLine("Found {0} stream(s):", streams.Count); foreach (var item in streams) { Console.WriteLine(item.Name); } Console.WriteLine(); } const string ThumbnailStreamName = "thumb"; if (file.AlternateDataStreamExists(ThumbnailStreamName)) { Console.WriteLine("Thumbnail stream exists:"); using (var stream = file.GetAlternateDataStream(ThumbnailStreamName).OpenRead()) using (var thumbnail = Image.FromStream(stream)) { Console.WriteLine("Read thumbnail - size {0}x{1}", thumbnail.Width, thumbnail.Height); } file.DeleteAlternateDataStream(ThumbnailStreamName); } else { Console.WriteLine("Creating thumbnail:"); using (var inputStream = file.OpenRead()) using (var inputImage = Image.FromStream(inputStream)) { int targetWidth = 100; int targetHeight = 100; int w = (int)(inputImage.Width * targetHeight / inputImage.Height); int h = (int)(inputImage.Height * targetWidth / inputImage.Width); if (w > targetWidth) { targetHeight = h; } else if (h > targetHeight) { targetWidth = w; } using (var thumbnail = inputImage.GetThumbnailImage(targetWidth, targetHeight, null, IntPtr.Zero)) using (var outputStream = file.GetAlternateDataStream(ThumbnailStreamName).OpenWrite()) { thumbnail.Save(outputStream, ImageFormat.Jpeg); Console.WriteLine("Created thumbnail: Size {0}x{1}", thumbnail.Width, thumbnail.Height); } } } } }
Output:
...>TestStreams No streams found. Creating thumbnail: Created thumbnail: Size 100x74
...>TestStreams Found 1 stream(s): thumb Thumbnail stream exists: Read thumbnail - size 100x74
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Yes, the example with test.jpg works on my machine. I apologize, perhaps I misunderstood "MetaData" term. I was looking to read MS Office 2003/2007 Summary info. This perhaps is definitely stored in file (solution is to use DSOFile.dll from Microsoft to get that data), not as NTFS data stream. Anyway, thanks for a quick response!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
According the the documentation on BackupRead(), "lpContext [out] Pointer to a variable that receives a pointer to an internal data structure used by BackupRead to maintain context information during a backup operation.
You must set the variable pointed to by lpContext to NULL before the first call to BackupRead for the specified file or directory. The function allocates memory for the data structure, and then sets the variable to point to that structure. You must not change lpContext or the variable that it points to between calls to BackupRead.
To release the memory used by the data structure, call BackupRead with the bAbort parameter set to TRUE when the backup operation is complete."
Also, "bAbort [in] Indicates whether you have finished using BackupRead on the handle. While you are backing up the file, specify this parameter as FALSE. Once you are done using BackupRead, you must call BackupRead one more time specifying TRUE for this parameter and passing the appropriate lpContext. lpContext must be passed when bAbort is TRUE; all other parameters are ignored."
Note the last statement in te first quote of the documentation: "To release the memory...". You need to call BackupRead with bAbort set to true when you are finished with the context to free the memory allocated for the context data structure.
I use alternate streams on millions of files and when I'm verifying that the alternate streams that are supposed to exist actaully do, and contain the correct information, I can use up a lot of memory.
This is a bug. I've fixed it in the code I use.
Here is snippet I added after the while(continue) { } statement to close down the BackupRead()
Kernel32.BackupRead(hFile, ref sid, dwStreamHeaderSize, ref lRead, true, false, ref Context);
I also had to move the definition of lRead but this argument is ignored.
There is also a small performance enhancement that could be achieved by moving the "IntPtr pName = Marshal.AllocHGlobal(sid.dwStreamNameSize);" outside the while loop and moving the
"Marshal.FreeHGlobal(pName);" to the finally block. The only requirement would be to allocate enough memory for the largest alternate stream name.
scooter_jsm
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks for the feedback.
I had't looked at this code for four years, until I needed to write a utility to bulk un-block downloaded files a couple of weeks ago. Needless to say, this old version looked very messy, so I re-wrote it for C# 3. I've managed to fix this bug, and hopefully make it 64-bit compatible.
The new version isn't backwards-compatible with this version, because I've significantly simplified the interface. If I get time (and if there's any interest ), I might update the article.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Just an advisory for the unwary: this code is not 64-bit compatible (e.g. use of int's instead of IntPtr's). It may run inside the IDE but will crash hard if you run it straight from the command line.
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
 |
And just an update for those who may have missed it above and are just reading this particular message/thread - the code has been updated to be 64-bit compatible, as apparently confirmed by the OP (of prev. message) See the article details. 
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
First off nice article and sample code. Everything works great but I was wondering how you would read/write/delete ADS from folders instead of just files. Any help would be appriciated, I know you can do it using the command line method, just not sure how to accomplish this in code.
Thanks.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I never realized you could do that! 
Most of the code should work with directories as well as files. You should only need to change the FileInfo member of the FileStreams class to a FileSystemInfo, and get rid of the FileSize and Size properties.
Let me know if you manage to get it working.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
 |
I am having problem using your example. When I retrieve substream using StreamInfo.open() sometimes I get null stream. When I check StreamInfo object that I am getting stream from it shows non zero size data in it so looks like data is there. I added few millisecond delay and retry and that works for some time but eventually I have same problem. Do you have any idea why this could happen?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I haven't seen any problems on my machine (XP SP1). It sounds as if the file may be locked by another process. 
Try changing the catch block of the Open method (line 177) to display the error message, if there is one. That might give you some more information to track down the problem.
catch (Exception ex) { Console.WriteLine("Error opening stream {0}:\n{1}", _name, ex); return null; }
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Actually I found the problem. In process of iterating through sub streams I was jumping to next substream without closing it. This is why when next time I try to open it it was giving me null as result stream. Thanks for the response.
-Raj
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I needed to make one small change to the code to get it to work with multiple streams. At the bottom of initStreams(), in the code that was
//Skip the stream contents int l = 0; int h = 0; Continue = Kernel32.BackupSeek(hFile, sid.Size.Low, sid.Size.High, ref l, ref h, ref Context); I needed to remove the assignment of Continue to get it to work (by the way, all of my streams were of a zero length during my testing)
//Skip the stream contents int l = 0; int h = 0; Kernel32.BackupSeek(hFile, sid.Size.Low, sid.Size.High, ref l, ref h, ref Context);
The code then falls out of the loop at the top in the first BackupRead
//Read the next stream header int lRead = 0; Continue = Kernel32.BackupRead(hFile, ref sid, dwStreamHeaderSize, ref lRead, false, false, ref Context); if (Continue && lRead == dwStreamHeaderSize) { ... } else break;
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
from the MSDN article:
"When you copy a multi-stream file on non-NTFS volumes, only the main stream is copied. This means you lose your extra data, because they can't come up again even if you copy the file back to an NTFS disk"
That's quite the limitation!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Warren Stevens wrote: That's quite the limitation!
Only if you're moving the files to a non-NTFS drive. If you only work with NTFS, the extra streams will stay with the file until you delete them.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
What applications are you writing where this would be acceptable? (this is a question, I'm not trying to be argumentative).
1) We write desktop (MFC) applications, and a good proportion of users still use 95/98 or use 2000 but wouldn't know if they have NTFS or not.
2) There's also the issue of backup. A lot of people with NTFS hard disks still use CD for backup.
I looked at streams a while ago and I thought they were great, except for this limitation. Anyway, don't take this as a criticism of your article, just of streams.
Warren
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I was thinking more along the lines of web apps. For example, using a stream to store a thumbnail for an image, which could be recreated if it got lost. I agree that they're not much use for critical data that can't be derived from the file unless you're only using NTFS.
With the issue of backup, copying files to the CD will loose the streams, but using the NT backup program *should* preserve them.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |