I am using C# framework 4.5, netoffice 1.6 and sharpdevelop 4.4.1 to manipulate an excel workbook, located on a network share, from within Outlook.
At some point I need to change the file access of the workbook object (ewb) to readwrite like so:
ewb.ChangeFileAccess(Excel.Enums.XlFileAccess.xlReadWrite, System.Reflection.Missing.Value, true);
Before I change the file access, I check if the file is locked on the server. If the file is locked, I will notify the user to retry the action at a later point.
Now, I want to include the username that is locking the excel file in the notification. I have searched msdn, netoffice forum, etcetera... and have not found a solution.
I know that, if you open the excel file readwrite, it will store the user's name in the xlsx file. How can I access that particular piece of information through c#?
EDIT:
I ended up doing this:
public string GetExcelFileOwner(string path, NetOffice.ExcelApi.Enums.XlFileFormat ffmt) {
string tempmark = "~$";
if(ffmt==NetOffice.ExcelApi.Enums.XlFileFormat.xlExcel8) {
tempmark = "";
}
string uspath = Path.Combine(Path.GetDirectoryName(path), tempmark + Path.GetFileName(path));
if (!File.Exists(uspath)) return "";
var sharing = FileShare.ReadWrite | FileShare.Delete;
using (var fs = new FileStream(uspath, FileMode.Open, FileAccess.Read, sharing))
using (var br = new BinaryReader(fs, Encoding.Default)) {
if(ffmt==NetOffice.ExcelApi.Enums.XlFileFormat.xlExcel8) {
byte[] ByteBuffer = new byte[500];
br.BaseStream.Seek(150, SeekOrigin.Begin);
br.Read(ByteBuffer, 0, 500);
return matchRegex(System.Text.Encoding.UTF8.GetString(ByteBuffer), #"(?=\w\w\w)([\w, ]+)").Trim();
}
else {
return br.ReadString();
}
}
}
private static string matchRegex(string txt, string rgx) {
Regex r;
Match m;
try {
r = new Regex(rgx, RegexOptions.IgnoreCase);
m = r.Match(txt);
if (m.Success) {
return m.Groups[1].Value.ToString();
}
else {
return "";
}
}
catch {
return "";
}
}
We are using excel 2003 and excel 2007+ file format (.xls and .xlsx). For .xls I had to look in the .xls file itself. For .xlsx, the locking user is stored in the ~$ temp file.
I know, for the .xls file, it is dirty code, but I have no clue of how the .xls file format is structured. Therefore, i just read a bunch of bytes which includes the ascii username and do a regex to extract that username.
it will store the user's name in the xlsx file
No, not the in .xlsx file. Excel creates another file to store the user name. It has the Hidden file attribute turned on so you cannot normally see it with Explorer.
It normally has the same name as the original file, but prefixed with ~$. So for a file named test.xlsx you'll get a file named ~$test.xlsx. It is a binary file and contains the user name both encoded in the default code page and in utf-16. A hex dump to show what it looks like:
0000000000: 0C 48 61 6E 73 20 50 61 │ 73 73 61 6E 74 20 20 20 ♀Hans Passant
0000000010: 20 20 20 20 20 20 20 20 │ 20 20 20 20 20 20 20 20
0000000020: 20 20 20 20 20 20 20 20 │ 20 20 20 20 20 20 20 20
0000000030: 20 20 20 20 20 20 20 0C │ 00 48 00 61 00 6E 00 73 ♀ H a n s
0000000040: 00 20 00 50 00 61 00 73 │ 00 73 00 61 00 6E 00 74 P a s s a n t
0000000050: 00 20 00 20 00 20 00 20 │ 00 20 00 20 00 20 00 20
0000000060: 00 20 00 20 00 20 00 20 │ 00 20 00 20 00 20 00 20
0000000070: 00 20 00 20 00 20 00 20 │ 00 20 00 20 00 20 00 20
0000000080: 00 20 00 20 00 20 00 20 │ 00 20 00 20 00 20 00 20
0000000090: 00 20 00 20 00 20 00 20 │ 00 20 00 20 00 20 00 20
00000000A0: 00 20 00 20 00 │
The oddish 0x0C word in the file is the string length in characters (not bytes), followed by 54 characters to store the user name, padded with spaces. Easiest way to read it is with BinaryReader.ReadString():
public static string GetExcelFileOwner(string path) {
string uspath = Path.Combine(Path.GetDirectoryName(path), "~$" + Path.GetFileName(path));
if (!File.Exists(uspath)) return "";
var sharing = FileShare.ReadWrite | FileShare.Delete;
using (var fs = new FileStream(uspath, FileMode.Open, FileAccess.Read, sharing))
using (var br = new BinaryReader(fs, Encoding.Default)) {
return br.ReadString();
}
}
But not necessarily the most correct way, you might want to improve the code and try to locate the utf-16 string (not with ReadString) if 8-bit encodings don't work well in your locale. Seek() to offset 0x37 first. Be sure to use the method correctly, it has an implicit race condition so make sure you only use it after the operation failed and expect an empty string return anyway. I cannot guarantee this method will work correctly on all Excel versions, including future ones, I only tested for Office 2013 on a workstation class machine.
Which part are you having problems with?
WIthout knowing anything about xslx, I can only guess that: you want to open file and specify FileAccess.Read & FileShare.ReadWrite as here: How to read open excel file at C# after that, you use some kind of library to turn XSLX into DataTable, and extract the specific row which you need.
Related
I have the following piece of code:
using (Stream inputFileStream = File.OpenRead("C:\\Users\\User\\Downloads\\test.txt"))
{
using (Stream transcodingStream = Encoding.CreateTranscodingStream(inputFileStream, Encoding.GetEncoding(500), new UnicodeEncoding(bigEndian: true, byteOrderMark: true)))
{
using (Stream outputStream = File.OpenWrite("C:\\Users\\User\\Downloads\\test.txt"))
{
await transcodingStream.CopyToAsync(outputStream, cancellationToken);
}
}
}
My file before transcoding has the following first 16 bytes and is of Ebcdic type encoding (code page 500):
F5 F1 F1 F0 F2 C2 D4 E6 40 40 40 40 40 40 F1 F1 = 51102BMW 11
After performing the transcoding to Unicode with Big-Endiant and Byte Order Markings, I expect the file to begin with:
FF FE
However, I get:
00 35 00 31 00 31 00 30 00 32 00 42 00 4D 00 57 = �5�1�1�0�2�B�M�W
Where am I going wrong with this?
It seems like the transcoding stream does not care about maintaining the BOM for target encoding and it's something you have to manage yourself.
I've implemented the following solution:
targetEncoding is of type Encoding
outputStream.Seek(0, SeekOrigin.Begin);
await outputStream.WriteAsync(targetEncoding.Preamble.ToArray(), 0, targetEncoding.Preamble.Length, cancellationToken);
I have a Windows Forms App that basically displays some numbers from some sensors that send data in hex value bytes. I also have a Thermometer that communicates via string.
BACKGROUND INFO
So I had an issue with the Thermometer "data feed" where sometimes it would send something like 56.385 but my software was displaying 6.385 or .385 or some version of a truncated string because some timing got weird and so I started filtering my "received data" by looking for that "CR+NL" that it sends with every value (per the manual). After adding code to do that I stopped having that issue.
After long periods of data logging using the sensors that use bytes I came across the same issue, sometimes my values would be wrong and would get timeouts of data-points for 4 - 10 seconds (expecting 2-per second) because the received "chunk" of data was truncated.
TL;DR: I want to filter my "receiveddata" and clear my buffer every time I find a CR+NL (carriage return + newlinefeed). I can do it using strings, but I dont know if it works the same with bytes.
For my "datareceived" to the Thermometer I have this:
private void ThermometerDataReceived(object sender, SerialDataReceivedEventArgs e)
{
string dataReceived = "";
try
{
dataReceived = HH42Port.ReadExisting();
stringBuffer += dataReceived;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
if (stringBuffer.EndsWith("\r\n"))
{
Console.WriteLine(stringBuffer);
stringBuffer = stringBuffer.Substring(0, stringBuffer.IndexOf("\n"));
StringDataNeedsParsing(HH42ID, "::" + stringBuffer);
stringBuffer = "";
}
Now, this is my "byte" version but it doesnt work. I have the same issue where I sometimes get truncated values and go up to a few seconds without any values (when values are "full" a message of "full packet received" is printed, see bottom for console output.
//According to the manual for the byte-device:
//Every reading starts with 0x02[...DATA...]7E+CR+NL
//#define CR 0x0D
//#define NL 0x0A
private bool didLineEnd(List<byte> listCheck)
{
byte lastByte = 0x00;
byte second2LastByte = 0x00;
if(listCheck.Count > 2)
{
lastByte = listCheck[listCheck.Count - 1];
second2LastByte = listCheck[listCheck.Count - 2];
} else
{
return true;
}
if (lastByte == 0x0A && second2LastByte == 0x0D)
{
return false;
} else
{
return true;
}
}
private void DirectModule_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string resultSeed = "";
byte data;
rxDataBufferRawSeed.Clear();
Thread.Sleep(25);
if (isModuleHardwired)
{
Console.WriteLine("USB Module Data Received:");
while (directUSBPort.BytesToRead != 0 && didLineEnd(rxDataBufferRawSeed))
{
data = (byte)directUSBPort.ReadByte();
rxDataBufferRawSeed.Add(data);
}
resultSeed = ByteArrayToString(rxDataBufferRawSeed.ToArray());
resultSeed = String.Concat(resultSeed.Where(c => !Char.IsWhiteSpace(c)));
Console.WriteLine("SEED RESULT: "+resultSeed);
}
CONSOLE OUTPUT (Showing only TWO good readings, even though I received multiple, the only one that was parsed is the one that says "Full packet received")
USB Module Data Received:
SEED RESULT: 0xCDC2200000C2200000C2200000C220000041B9BA0DC2200000C220000041B5AB7DC2200000C2200000C2200000C2200000C2200000C220000041B8A9CDC2200000C2200000C2200000C220000041B4985DC2200000C2200000C2200000C2200000C2200000C220000041B8061DC2200000C220000041B47CBDC2200000C2200000C2200000C220000041B798CD41B4985DC2200000C2200000C2200000C220000041BB6C3DC2200000C2200000E2247E
Response received:
Length: 0
USB Module Data Received:
SEED RESULT: 0x0200C8000141B6502D00C2200000C2200000C2200000C220000041BF367D41B3BBADC2200000C2200000C2200000C220000041BC449DC2200000C220000041B4B3DDC2200000C2200000C2200000C2200000C2200000C220000041B6A26DC2200000C2200000C2200000C220000041B4985DC2200000C2200000C2200000C2200000C2200000C220000041B558FDC2200000C220000041B42A1DC2200000C2200000C2200000C220000041BA783D41B200EDC2200000C2200000C2200000C220000041BB6C3DC2200000C2200000092D2F7E
Full Packet Received
Parsing Module Readings from module
USB Module Data Received:
SEED RESULT: 0x0200C8000141B8
Response received: 00 C8 00 01 41 B8
Length: 18
USB Module Data Received:
SEED RESULT: 0x061DC2200000C2200000C2200000C220000041BF6C2D0041B6502D00C2200000C2200000C2200000C220000041BA5D1DC2200000C220000041B4B3DDC2200000C2200000C2200000C2200000C2200000C220000041B9321DC2200000C2200000C2200000C220000041B3BBADC2200000C2200000C2200000C2200000C2200000C220000041B4CF6DC2200000C220000041B3D74DC2200000C2200000C2200000C220000041B99EED41B2385DC2200000C2200000C2200000C220000041BA936DC2200000C2200000C4217E
Response received:
Length: 0
USB Module Data Received:
SEED RESULT: 0x0200C8000141B5747DC2200000C2200000C2
Response received: 00 C8 00 01 41 B5 74 7D C2 20 00 00 C2 20 00 00 C2
Length: 51
USB Module Data Received:
SEED RESULT: 0x200000C220000041BEB04D41B5FDCDC2200000C2200000C2200000C220000041BBF38DC2200000C220000041B368CDC2200000C2200000C2200000C2200000C2200000C220000041B857FDC2200000C2200000C2200000C220000041B3BBADC2200000C2200000C2200000C2200000C2200000C220000041B4CF6DC2200000C220000041B34D3DC2200000C2200000C2200000C220000041B94D4D41B2385DC2200000C2200000C2200000C220000041BC449DC2200000C22000005DAB7E
Response received:
Length: 0
USB Module Data Received:
SEED RESULT: 0x0200C8000141B7EABDC2200000C2200000C2200000C220000041BE29
Response received: 00 C8 00 01 41 B7 EA BD C2 20 00 00 C2 20 00 00 C2 20 00 00 C2 20 00 00 41 BE 29
Length: 81
USB Module Data Received:
SEED RESULT: 0xED41B2C2DDC2200000C2200000C2200000C220000041BBF38DC2200000C220000041B4613DC2200000C2200000C2200000C2200000C2200000C220000041B7B42D00C2200000C2200000C2200000C220000041B3BBADC2200000C2200000C2200000C2200000C2200000C220000041B4CF6DC2200000C220000041B34D3DC2200000C2200000C2200000C220000041B94D4D41B3BBADC2200000C2200000C2200000C220000041BA0BADC2200000C22000009E5D7E
Response received:
Length: 0
USB Module Data Received:
SEED RESULT: 0x0200C8000141B5747DC2200000C2200000C2200000C220000041BE29ED41B5FDCDC2200000C2200000C2200000C220000041BE7A8DC2200000C220000041B368CDC2200000C2200000C2200000C2200000C2200000C220000041B6D93DC2200000C2200000C2200000C220000041B3BBADC2200000C2200000C2200000C2200000C2200000C220000041B5747DC2200000C220000041B34D3DC2200000C2200000C2200000C220000041B8C51D41B2385DC2200000C2200000C2200000C220000041BE29EDC2200000C2200000C3B17E
Full Packet Received
Parsing Module Readings from module
USB Module Data Received:
SEED RESULT: 0x0200C8000141B8061DC2
Response received: 00 C8 00 01 41 B8 06 1D C2
Length: 27
USB Module Data Received:
SEED RESULT: 0x200000C2200000C2200000C220000041BFD76D41B634CDC2200000C2200000C2200000C220000041BE7A8DC2200000C220000041B558FDC2200000C2200000C2200000C2200000C2200000C220000041B6D93DC2200000C2200000C2200000C220000041B3BBADC2200000C2200000C2200000C2200000C2200000C220000041B3F2EDC2200000C220000041B34D3DC2200000C2200000C2200000C220000041B8C51D41B2385DC2200000C2200000C2200000C220000041BBF38DC2200000C22000001F7C7E
Response received:
Length: 0
The thread 0x5b4c has exited with code 0 (0x0).
USB Module Data Received:
SEED RESULT: 0x0200C8000141B6502D00C2200000C2200000C2200000C220000041BE29ED41B558FDC2200000C2200000C2200000C220000041BA5D1DC2200000C220000041B5747DC2200000C2200000C2200000C2200000C2200000C220000041B8E04DC2200000C2200000C2200000C220000041B2DE9DC2200000C2200000C2200000C2200000C2200000C220000041B916CDC2200000C220000041B34D3DC2200000C2200000C2200000C220000041B8733D41B3BBADC2200000C2200000C2200000C220000041BB1A
Response received: 00 C8 00 01 41 B6 50 2D C2 20 00 00 C2 20 00 00 C2 20 00 00 C2 20 00 00 41 BE 29 ED 41 B5 58 FD C2 20 00 00 C2 20 00 00 C2 20 00 00 C2 20 00 00 41 BA 5D 1D C2 20 00 00 C2 20 00 00 41 B5 74 7D C2 20 00 00 C2 20 00 00 C2 20 00 00 C2 20 00 00 C2 20 00 00 C2 20 00 00 41 B8 E0 4D C2 20 00 00 C2 20 00 00 C2 20 00 00 C2 20 00 00 41 B2 DE 9D C2 20 00 00 C2 20 00 00 C2 20 00 00 C2 20 00 00 C2 20 00 00 C2 20 00 00 41 B9 16 CD C2 20 00 00 C2 20 00 00 41 B3 4D 3D C2 20 00 00 C2 20 00 00 C2 20 00 00 C2 20 00 00 41 B8 73 3D 41 B3 BB AD C2 20 00 00 C2 20 00 00 C2 20 00 00 C2 20 00 00 41 BB 1A
Length: 585
USB Module Data Received:
SEED RESULT: 0xFDC2200000C2200000D3FA7E
Response received:
Length: 0
USB Module Data Received:
SEED RESULT: 0x0200C8000141B5747DC2200000C2200000C2200000
Response received: 00 C8 00 01 41 B5 74 7D C2 20 00 00 C2 20 00 00 C2 20 00 00
Length: 60
USB Module Data Received:
SEED RESULT: 0xC220000041BD528D41B558FDC2200000C2200000C2200000C220000041BAE4CDC2200000C220000041B4985DC2200000C2200000C2200000C2200000C2200000C220000041B8061DC2200000C2200000C2200000C220000041B5747DC2200000C2200000C2200000C2200000C2200000C220000041B4B3DDC2200000C220000041B34D3DC2200000C2200000C2200000C220000041B8C51D41B2385DC2200000C2200000C2200000C220000041BBD88DC2200000C2200000A41E7E
Response received:
Length: 0
USB Module Data Received:
SEED RESULT: 0x0200C8000141B8061DC2200000C2200000C2200000C220000041BD528D41B5AB
Response received: 00 C8 00 01 41 B8 06 1D C2 20 00 00 C2 20 00 00 C2 20 00 00 C2 20 00 00 41 BD 52 8D 41 B5 AB
Length: 93
USB Module Data Received:
SEED RESULT: 0x7DC2200000C2200000C2200000C220000041BBF38DC2200000C220000041B4985DC2200000C2200000C2200000C2200000C2200000C220000041B8061DC2200000C2200000C2200000C220000041B2DE9DC2200000C2200000C2200000C2200000C2200000C220000041B6F48DC2200000C220000041B42A1DC2200000C2200000C2200000C220000041B7EABD41B3BBADC2200000C2200000C2200000C220000041BAFFEDC2200000C220000009987E
Response received:
Length: 0
Serial Port data often comes in bits and pieces, you need to keep a cache of what you've received so far between subsequent calls to DirectModule_DataReceived. In my experience, you can also get multiple readings in the same call, so you need to be aware of that too. A simple way would be to keep your buffer array live between calls, and check after each call if you have a full message to parse.
private void DirectModule_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (isModuleHardwired)
{
Console.WriteLine("USB Module Data Received:");
while (directUSBPort.BytesToRead != 0)
{
var data = directUSBPort.ReadByte();
rxDataBufferRawSeed.Add(data);
if(data == 0x0A
&& rxDataBufferRawSeed.Count > 2
&& rxDataBufferRawSeed[rxDataBufferRawSeed.Count - 2] == 0x0D
&& rxDataBufferRawSeed[rxDataBufferRawSeed.Count - 3] == 0x7E)
//You have a full packet; process it here
//ProcessBytes(rxDataBufferRawSeed);
//and then reset
rxDataBufferRawSeed.Clear();
}
}
Visual studio memory profiler doesn't make sense to me, I'm looking at a double string array [10,1000]
and trying to figure out how is the memory allocated for it.
How does the "e96" string takes 20 bytes? shouldn't it be: length member(size of int) + string length * size of char? so in this case 4 + 3*2 = 10 bytes
My calculation is based on sizeof string question and Majid answer here
the snapshot below is sorted so the minimum string size at the array is 20 bytes, how is the total size = 40KB? it should be > 10,000 * 20
What am I missing?
Code can be found here
string[,] mat = GetData(); // memory allocation is done here.
Answering your second question first:
Please try to take a snapshot before this line:
string[,] mat = GetData();
Console.WriteLine("Please take a snapshot here!");
Console.ReadLine()
object cellObjectList = GetCells(mat);
You are taking the snapshot where the mat[,] is probably being optimized away. See the inclusive size of your array in a snapshot taken at this point.
To answer your first question:
By debugging and seeing the string [,] memory,
The first string (which is e96) points to this address:
a0 6e c1 02 (0x02c1e6a0)
By examining this address we see these 20 bytes.
84 d4 ad 70 03 00 00 00 65 00 39 00 36 00 00 00 00 00 00 00
The first four and the last zero bytes don't make sense?
In a dump file, !DumpObject on the first string element 0x028923f0 shows:
0:000> !do 028923f0
Name: System.String
MethodTable: 70add484
EEClass: 706b4a50
Size: 20(0x14) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String: e96
Fields:
MT Field Offset Type VT Attr Value Name
70adf2d8 4000273 4 System.Int32 1 instance 3 m_stringLength
70addecc 4000274 8 System.Char 1 instance 65 m_firstChar
70add484 4000278 50 System.String 0 shared static Empty
>> Domain:Value 00c33988:NotInit <<
So our string should be 14 bytes? (4 bytes method table, 4 bytes string length, 3 x 2 = 6 for 3 unicode chars)
But! a string is a link type, so first four bytes contain SyncBlockIndex (starting from address - 4)
By dumping the memory at (0x028923f0 - 4) = 0x028923ec
Now let's take the 20 bytes which we retrieved from the memory window
// e96
00 00 00 80 => SyncBlock for String type
84 d4 ad 70 => Method Table of String class
03 00 00 00 => Number of characters in string (string length = 3)
65 00 => e
39 00 => 9
36 00 => 6
00 00 => Padding it to the nearest 4 bytes, 16 here (excluding sync block)
And we have 20 bytes.
Hope this helps.
I need to write a program that will generate 108 combinaisons of icons (standard windows .ico files) based on a tileset image.
I use the class System.Drawing.Bitmap to build each combinaison, and I save them like this:
Bitmap IconBitmap = new Bitmap(16, 16);
// Some processing, writing different parts of the source tileset
// ...
IconBitmap.Save(Path.Combine(TargetPath, "Icon" + Counter + ".ico"),
ImageFormat.Icon);
But I found out that the file saved is actually a PNG. Neither Windows Explorer nor Visual Studio can display it correctly, but GIMP can, and if I open it in an Hex viewer, here is what i see:
00000000 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 ‰PNG........IHDR
00000010 00 00 00 10 00 00 00 10 08 06 00 00 00 1F F3 FF ..............óÿ
00000020 61 00 00 00 01 73 52 47 42 00 AE CE 1C E9 00 00 a....sRGB.®Î.é..
00000030 00 04 67 41 4D 41 00 00 B1 8F 0B FC 61 05 00 00 ..gAMA..±..üa...
00000040 00 09 70 48 59 73 00 00 0E C3 00 00 0E C3 01 C7 ..pHYs...Ã...Ã.Ç
00000050 6F A8 64 00 00 00 15 49 44 41 54 38 4F 63 60 18 o¨d....IDAT8Oc`.
00000060 05 A3 21 30 1A 02 A3 21 00 09 01 00 04 10 00 01 .£!0..£!........
00000070 72 A5 13 76 00 00 00 00 49 45 4E 44 AE 42 60 82 r¥.v....IEND®B`‚
Also if I rename the .ico to .png Windows Explorer can display it properly.
I have this result even if I do NOTHING on the bitmap (I construct it with new and Save it directly, that gives me a black png).
What am I doing wrong?
I also tried this, which gave me awful 16 color icons, but I would prefer to avoid this solution anyway (using handles) :
Icon NewIcon = Icon.FromHandle(IconBitmap.GetHicon());
FileStream FS = new FileStream(Path.Combine(Target, "Icon" + Counter + ".ico"),
FileMode.Create);
NewIcon.Save(FS);
I made a quick-and-dirty workaround myself, I post it here for the record (it might help someone that need a quick solution, like me).
I won't accept this as the correct answer, it's not an actual icon writer.
It just write a 32bits ARGB bitmap into an ico file, using PNG format (works on Vista or later)
It is based on the ICO file format article from Wikipedia, and some fails and retry.
void SaveAsIcon(Bitmap SourceBitmap, string FilePath)
{
FileStream FS = new FileStream(FilePath, FileMode.Create);
// ICO header
FS.WriteByte(0); FS.WriteByte(0);
FS.WriteByte(1); FS.WriteByte(0);
FS.WriteByte(1); FS.WriteByte(0);
// Image size
FS.WriteByte((byte)SourceBitmap.Width);
FS.WriteByte((byte)SourceBitmap.Height);
// Palette
FS.WriteByte(0);
// Reserved
FS.WriteByte(0);
// Number of color planes
FS.WriteByte(0); FS.WriteByte(0);
// Bits per pixel
FS.WriteByte(32); FS.WriteByte(0);
// Data size, will be written after the data
FS.WriteByte(0);
FS.WriteByte(0);
FS.WriteByte(0);
FS.WriteByte(0);
// Offset to image data, fixed at 22
FS.WriteByte(22);
FS.WriteByte(0);
FS.WriteByte(0);
FS.WriteByte(0);
// Writing actual data
SourceBitmap.Save(FS, ImageFormat.Png);
// Getting data length (file length minus header)
long Len = FS.Length - 22;
// Write it in the correct place
FS.Seek(14, SeekOrigin.Begin);
FS.WriteByte((byte)Len);
FS.WriteByte((byte)(Len >> 8));
FS.Close();
}
Here's a simple ICO file writer I wrote today that outputs multiple System.Drawing.Image images to a file.
// https://en.wikipedia.org/wiki/ICO_(file_format)
public static class IconWriter
{
public static void Write(Stream stream, IReadOnlyList<Image> images)
{
if (images.Any(image => image.Width > 256 || image.Height > 256))
throw new ArgumentException("Image cannot have height or width greater than 256px.", "images");
//
// ICONDIR structure
//
WriteInt16(stream, 0); // reserved
WriteInt16(stream, 1); // image type (icon)
WriteInt16(stream, (short) images.Count); // number of images
var encodedImages = images.Select(image => new
{
image.Width,
image.Height,
Bytes = EncodeImagePng(image)
}).ToList();
//
// ICONDIRENTRY structure
//
const int iconDirSize = 6;
const int iconDirEntrySize = 16;
var offset = iconDirSize + (images.Count*iconDirEntrySize);
foreach (var image in encodedImages)
{
stream.WriteByte((byte) image.Width);
stream.WriteByte((byte) image.Height);
stream.WriteByte(0); // no pallete
stream.WriteByte(0); // reserved
WriteInt16(stream, 0); // no color planes
WriteInt16(stream, 32); // 32 bpp
// image data length
WriteInt32(stream, image.Bytes.Length);
// image data offset
WriteInt32(stream, offset);
offset += image.Bytes.Length;
}
//
// Image data
//
foreach (var image in encodedImages)
stream.Write(image.Bytes, 0, image.Bytes.Length);
}
private static byte[] EncodeImagePng(Image image)
{
var stream = new MemoryStream();
image.Save(stream, ImageFormat.Png);
return stream.ToArray();
}
private static void WriteInt16(Stream stream, short s)
{
stream.WriteByte((byte) s);
stream.WriteByte((byte) (s >> 8));
}
private static void WriteInt32(Stream stream, int i)
{
stream.WriteByte((byte) i);
stream.WriteByte((byte) (i >> 8));
stream.WriteByte((byte) (i >> 16));
stream.WriteByte((byte) (i >> 24));
}
}
It's true that the ImageFormat.Icon does not work for writing as you'd suppose, .NET simply does not support writing .ico files and simply dumps the PNG data.
There are a few projects on CodeProject (and this one) (and another one) and that let you write an .ico file, it's actually not that hard. The file format is pretty straight-forward, and supports BMP and PNG data.
If I have some text file like abc.txt the I want to the hex value of that .txt file
like we see when we open notepad+ can click on hex...something like this
74 68 65 72 77 69 73 65 20 69 73 20 69 74 63 68
therwise is itch
69 6e 27 20 66 6f 72 20 61 20 66 69 67 68 74 2e
in' for a fight.
Now i want these hex values of individual letters.
I know how to read text by using FileStream() and StreamReader().
But now want these hex values how can i get this?
BinaryReader reader = new BinaryReader(new FileStream("C:\\file.ext", FileMode.Open, FileAccess.Read, FileShare.None));
reader.BaseStream.Position = 0x0; // The offset you are reading the data from
byte[] data = reader.ReadBytes(0x10); // Read 16 bytes into an array
reader.Close();
So assuming the input is therwise is itch:
string data_as_str = Encoding.Default.GetString(data); // Output: therwise is itch
string data_as_hex = BitConverter.ToString(data); // Output: 74-68-65-72-77-69-73-65-20-69-73-20-69-74-63-68
Open using FileStream, then use Read to get arrays of byte. For each element in the array convert to a hex pair with byteVal.ToString("x2") (use X2 if you want uppercase hex).