this program going loop
and not resulting files with the data
namespace csv1
{
class A
{
public static async Task<List<string>> sql_to_csv(string connectionString, string providerName, string tableName, string outputFilepath, Encoding outputFileEncoding, long maxNbOfRows, bool addHeaderRow = true, string separator = ";")
{
DbProviderFactory factory = DbProviderFactories.GetFactory(providerName);
using (DbConnection connection = factory.CreateConnection())
{
connection.ConnectionString = connectionString;
await connection.OpenAsync();
DbCommand command = connection.CreateCommand();
command.CommandText = "SELECT top 10 * FROM table";
long totalRecords = 0;
long fileCount = 0;
List<string> filesCreated = new List<string>();
string filePattern = calculateFilePattern(outputFilepath);
using (var reader = await command.ExecuteReaderAsync())
{
// if (reader == null || !reader.HasRows)
// return filesCreated;//Table is empty
while (reader.HasRows)
{
string curFileName = string.Format(filePattern,++fileCount);
using (var writer = new System.IO.StreamWriter(curFileName))
{
totalRecords += await _exportToSplittedCsv(reader, writer, maxNbOfRows, addHeaderRow, separator) ;
}
filesCreated.Add(filePattern);
}
}
//You can return totalRecords or the list of files created or event the fileCount if you prefer
return filesCreated;
}
}
private static string calculateFilePattern(string path)
{
//The path already contains the Counter placeHolder on it
if (path.Contains("{0"))
return path;
int extIndex = path.LastIndexOf('.');
if (extIndex == -1)
return path + "{0:00000}";
else
return path.Substring(0, extIndex) + "{0:00000}" + path.Substring(extIndex);
}
/// <summary>
/// Exports Database until reader has no more records or until maxNbOfRows is reached
/// </summary>
/// <param name="reader">System.Data.Common.DbDataReader used to read data from database</param>
/// <param name="writer">Writer that will write CSV content in the current file</param>
/// <param name="maxNbOfRows">Maximum number of rows to write on the output file</param>
/// <param name="addHeaderRow">When true: first row in the CSV file will contain the Column names</param>
/// <param name="separator">CSV field separator</param>
/// <returns></returns>
private static async Task<long> _exportToSplittedCsv(System.Data.Common.DbDataReader reader, System.IO.StreamWriter writer, long maxNbOfRows, bool addHeaderRow, string separator)
{
long rowCount = 0;
if (addHeaderRow)
{
await writer.WriteAsync(getColNames(reader, separator));
await writer.WriteLineAsync();
}
while (await reader.ReadAsync() && (maxNbOfRows < 1 || rowCount < maxNbOfRows))
{
// await writer.WriteLineAsync();
await writer.WriteLineAsync(buildCsvRow(reader, separator));
++rowCount;
}
await writer.FlushAsync();
writer.Close();
return rowCount;
}
/// <summary>
/// Builds CSV row containing the column names
/// </summary>
/// <param name="reader">System.Data.Common.DbDataReader used to read data from database</param>
/// <param name="separator">CSV field separator</param>
/// <returns></returns>
private static string getColNames(System.Data.Common.DbDataReader reader, string separator)
{
var rowBuilder = new StringBuilder();
for (int i = 0; i < reader.FieldCount; i++)
{
rowBuilder.Append(separator).Append(reader.GetName(i));
}
//We remove extra separator from the begin...
return rowBuilder.Remove(0, 1).ToString();
}
/// <summary>
/// Builds a CSV row containing a database row
/// </summary>
/// <param name="reader">System.Data.Common.DbDataReader used to read data from database</param>
/// <param name="separator">CSV field separator</param>
/// <returns></returns>
private static string buildCsvRow(System.Data.Common.DbDataReader reader, string separator)
{
var rowBuilder = new StringBuilder();
for (int i = 0; i < reader.FieldCount; i++)
{
//If you want to format DateTime to a specific value...
/*switch (reader.GetDataTypeName(i))
{
case : //The typename changes depending of the Database type...
DateTime dt = reader.GetDateTime(i);
if (dt == null)
rowBuilder.Append(separator);
else
rowBuilder.Append(separator).Append(dt.ToString("yyyy-MM-dd HH:mm:ss"));
break;
default:
rowBuilder.Append(separator).Append(reader.GetValue(i).ToString());
}*/
rowBuilder.Append(separator).Append(reader.GetValue(i).ToString());
}
//We remove extra separator from the begin...
return rowBuilder.Remove(0, 1).ToString();
}
static void Main(string[] args)
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
// replace these with your own values
builder.DataSource = "xxxxx";
builder.InitialCatalog = "xxxxxx";
builder.IntegratedSecurity = true;
string provider = "System.Data.SqlClient";
Task task = sql_to_csv(builder.ConnectionString, provider, "table", "C:\\export_customerOrders{0:00000}.csv", Encoding.Default, 5, true, ",");
task.Wait(360);
}
}
}
Related
I have some SQL request:
go
Update dbo.Parameter set ValueAsStr = '{
"CreateDepoUrl": "https://sandbox.sg...../",
"CheckDepoStatusUrl": "https://sandbox.sg..../",
"CreatePayoutUrl": "https://sandbox.sg....../",
"CheckPayoutStatusUrl": "https://sandbox.sg..../",
"PayoutTerminalIds": {
....
go
If I send this request in SSMS all is alright
My method for send SQL request from C# code:
public static void SendToMainSqlRequest(MainDbContext mainDbContext, string queryString)
{
using (var conn = mainDbContext.Database.GetDbConnection())
{
conn.Open();
var command = mainDbContext.Database.GetDbConnection().CreateCommand();
command.CommandText = queryString;
command.CommandType = CommandType.Text;
int number = command.ExecuteNonQuery();
Console.WriteLine("count of updates: {0}", number);
conn.Close();
}
}
When I send request in C# code I get an exception:
Incorrect syntax near '.'
If I delete "dbo." in the SQL request I get an exception:
Incorrect syntax near '='
Table and field names are correct. Without typos.
How I can solve this problem?
Thanks!
I use the code bellow to do this :
...
var lines = GoSplitter.Split(queryString);
foreach(var line in lines)
{
command.CommandText = line;
command.CommandType = CommandType.Text;
int number = command.ExecuteNonQuery();
// process number if needed
}
...
The class GoSplitter (sorry comments are in french):
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
namespace DatabaseAndLogLibrary.DataBase
{
/// <summary>
/// Coupe un texte SQL en fonction des GO
/// Prend en compte les Go dans les chaines ou les commentaires SQL qui eux doivent être ignorés
/// Retire aussi les instruction SQL : USE
/// </summary>
internal class GoSplitter
{
/// <summary>
/// Pour détection des instruction USE
/// </summary>
private static Regex regUse = new Regex(#"^\s*USE\s");
/// <summary>
/// Renvoie la liste des instructions SQL séparé en fonction des GO dans le script d'origine
/// Prend en compte les Go dans les chaines ou les commentaires SQL qui eux doivent être ignorés
/// </summary>
/// <param name="fileContent"></param>
/// <returns></returns>
public static IEnumerable<string> Split(string fileContent)
{
if (string.IsNullOrWhiteSpace(fileContent))
{
yield break;
}
string res;
var currentState = EState.Normal;
List<Marker> markers = LoadMarker(fileContent).OrderBy(x => x.Index).ToList();
int index0 = 0;
for (int i = 0; i < markers.Count; i++)
{
switch (currentState)
{
case EState.Normal:
switch (markers[i].Event)
{
case EMarker.Go:
res = fileContent.Substring(index0, markers[i].Index - index0).Trim();
res = ReplaceUse(res);
if (!string.IsNullOrWhiteSpace(res))
{
yield return res;
}
index0 = markers[i].Index + 2; // 2 lettres dans go
break;
case EMarker.Quote:
currentState = EState.InText;
break;
case EMarker.Comment:
currentState = EState.InComment;
break;
}
break;
case EState.InText:
if (markers[i].Event == EMarker.Quote)
{
currentState = EState.Normal;
}
break;
case EState.InComment:
if (markers[i].Event == EMarker.EndComment)
{
currentState = EState.Normal;
}
break;
}
}
res = fileContent.Substring(index0, fileContent.Length - index0).Trim();
res = ReplaceUse(res);
if (!string.IsNullOrWhiteSpace(res))
{
yield return res;
}
}
/// <summary>
/// Charge les points clés du script
/// </summary>
/// <param name="fileContent"></param>
/// <returns></returns>
private static IEnumerable<Marker> LoadMarker(string fileContent)
{
var regGo = new Regex(#"\bgo\b", RegexOptions.Multiline | RegexOptions.IgnoreCase);
foreach(var m in regGo.Matches(fileContent).Where(x => x.Success).Select(x => new Marker() { Index = x.Index, Event = EMarker.Go }))
{
yield return m;
}
var regQuote = new Regex(#"'", RegexOptions.Multiline);
foreach (var m in regQuote.Matches(fileContent).Where(x => x.Success).Select(x => new Marker() { Index = x.Index, Event = EMarker.Quote }))
{
yield return m;
}
var regComment1 = new Regex(#"-(-)+[\s\S]*?$", RegexOptions.Multiline);
foreach (Match m in regComment1.Matches(fileContent).Where(x => x.Success))
{
yield return new Marker() { Index = m.Index, Event = EMarker.Comment };
yield return new Marker() { Index = m.Index + m.Length, Event = EMarker.EndComment };
}
var regComment2 = new Regex(#"/\*[\s\S]*?\*/", RegexOptions.Multiline);
foreach (Match m in regComment2.Matches(fileContent).Where(x => x.Success))
{
yield return new Marker() { Index = m.Index, Event = EMarker.Comment };
yield return new Marker() { Index = m.Index + m.Length, Event = EMarker.EndComment };
}
}
/// <summary>
/// Remplace les instructions using
/// </summary>
/// <param name="sqlLine"></param>
/// <returns></returns>
private static string ReplaceUse(string sqlLine)
=> regUse.Replace(sqlLine, string.Empty); // .Replace("USE", "---");
[DebuggerDisplay("{Index} - {Event}")]
private class Marker
{
public int Index {get; set;}
public EMarker Event { get; set; }
}
/// <summary>
/// les types de détection qui aggissent sur l'automate
/// </summary>
private enum EMarker
{
Go,
Quote,
Comment,
EndComment
}
/// <summary>
/// Les états de l'automate
/// </summary>
private enum EState
{
Normal,
InComment,
InText
}
}
}
Enjoy!
You can use the SQL Server Management Objects library to execute SQL commands with GO statements. We use this internally for executing database migration scripts to update our database schema.
Here's the library.
And some sample code demonstrating how to use it:
using System;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.Data.SqlClient;
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
var server = new Server(new ServerConnection(connection));
//this is to get script output (if you have any)
server.ConnectionContext.ServerMessage += (sender, eventArgs) =>
{
Console.WriteLine(eventArgs.Error.Message);
};
server.ConnectionContext.ExecuteNonQuery("some SQL with GO statements");
}
So it is in the tables and I have searched online but nothing could help.
Here is the code. I don't understand why it is giving me bugs now, it was not before.
I am using Visual Studio 2015 btw.
public partial class loginpage : Form
{
public loginpage()
{
InitializeComponent();
}
// Connection String
string cs = #"Data Source=MS-LAPTOP\SQLEXPRESS;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False";
//btn_Submit Click event
public sealed class SecurePasswordHasher
{
/// <summary>
/// Size of salt
/// </summary>
private const int SaltSize = 16;
/// <summary>
/// Size of hash
/// </summary>
private const int HashSize = 20;
/// <summary>
/// Creates a hash from a password
/// </summary>
/// <param name="password">the password</param>
/// <param name="iterations">number of iterations</param>
/// <returns>the hash</returns>
public static string Hash(string password, int iterations)
{
//create salt
byte[] salt;
new RNGCryptoServiceProvider().GetBytes(salt = new byte[SaltSize]);
//create hash
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations);
var hash = pbkdf2.GetBytes(HashSize);
//combine salt and hash
var hashBytes = new byte[SaltSize + HashSize];
Array.Copy(salt, 0, hashBytes, 0, SaltSize);
Array.Copy(hash, 0, hashBytes, SaltSize, HashSize);
//convert to base64
var base64Hash = Convert.ToBase64String(hashBytes);
//format hash with extra information
return string.Format("$MYHASH$V1${0}${1}", iterations, base64Hash);
}
/// <summary>
/// Creates a hash from a password with 10000 iterations
/// </summary>
/// <param name="password">the password</param>
/// <returns>the hash</returns>
public static string Hash(string password)
{
return Hash(password, 10000);
}
/// <summary>
/// Check if hash is supported
/// </summary>
/// <param name="hashString">the hash</param>
/// <returns>is supported?</returns>
public static bool IsHashSupported(string hashString)
{
return hashString.Contains("$MYHASH$V1$");
}
/// <summary>
/// verify a password against a hash
/// </summary>
/// <param name="password">the password</param>
/// <param name="hashedPassword">the hash</param>
/// <returns>could be verified?</returns>
public static bool Verify(string password, string hashedPassword)
{
//check hash
if (!IsHashSupported(hashedPassword))
{
throw new NotSupportedException("The hashtype is not supported");
}
//extract iteration and Base64 string
var splittedHashString = hashedPassword.Replace("$MYHASH$V1$", "").Split('$');
var iterations = int.Parse(splittedHashString[0]);
var base64Hash = splittedHashString[1];
//get hashbytes
var hashBytes = Convert.FromBase64String(base64Hash);
//get salt
var salt = new byte[SaltSize];
Array.Copy(hashBytes, 0, salt, 0, SaltSize);
//create hash with given salt
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations);
byte[] hash = pbkdf2.GetBytes(HashSize);
//get result
for (var i = 0; i < HashSize; i++)
{
if (hashBytes[i + SaltSize] != hash[i])
{
return false;
}
}
return true;
}
}
private void button2_Click(object sender, EventArgs e)
{
//Hash
var hash = SecurePasswordHasher.Hash("password");
//Verify
var result = SecurePasswordHasher.Verify("password", hash);
if (txtUsername.Text == "" || txt_Password.Text == "")
{
MessageBox.Show("Please provide a Username and Password");
return;
}
try
{
//Create SqlConnection
SqlConnection con = new SqlConnection(cs);
SqlCommand cmd = new SqlCommand("Select * from tabl_login where UserName=#username and Password=#password", con);
cmd.Parameters.AddWithValue("#username", txtUsername.Text);
cmd.Parameters.AddWithValue("#password", txt_Password.Text);
con.Open();
SqlDataAdapter adapt = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
adapt.Fill(ds);
con.Close();
int count = ds.Tables[0].Rows.Count;
//If count is equal to 1, than show frmMain form
if (count == 1)
{
MessageBox.Show("Login Successful!");
Form1 objFrmMain = new Form1();
this.Hide();
objFrmMain.ShowDialog();
this.Close();
}
else
{
MessageBox.Show("Login Failed!");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
And as well here is a screenshot
Your connection srtring not correct. It missed the database name.
// Connection String
string cs = #"Data Source=MS-LAPTOP\SQLEXPRESS;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False";
Change it to
// Connection String
string cs = #"Data Source=MS-LAPTOP\SQLEXPRESS;Integrated Security=True;Initial Catalog=DataBaseName;Connect Timeout=15;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False";
You want it to be
[databasename].[schema].[tablename]
instead of
tabl_login
I need to create an application that parses a PST file and converts the mails into multiple EML files. Basically, I need to do the opposite of what's being asked in this question.
Is there any sample code or guidelines to achieve this feature?
You could use the Outlook Redemption library which is capable of opening PST and extracting messages as .EML (among other formats). Redemption is a COM Object (32 or 64 bit) that can be used in C# without any problem. Here is a Console Application sample code that demonstrates this:
using System;
using System.IO;
using System.Text;
using Redemption;
namespace DumpPst
{
class Program
{
static void Main(string[] args)
{
// extract 'test.pst' in the 'test' folder
ExtractPst("test.pst", Path.GetFullPath("test"));
}
public static void ExtractPst(string pstFilePath, string folderPath)
{
if (pstFilePath == null)
throw new ArgumentNullException("pstFilePath");
RDOSession session = new RDOSession();
RDOPstStore store = session.LogonPstStore(pstFilePath);
ExtractPstFolder(store.RootFolder, folderPath);
}
public static void ExtractPstFolder(RDOFolder folder, string folderPath)
{
if (folder == null)
throw new ArgumentNullException("folder");
if (folderPath == null)
throw new ArgumentNullException("folderPath");
if (folder.FolderKind == rdoFolderKind.fkSearch)
return;
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
foreach(RDOFolder child in folder.Folders)
{
ExtractPstFolder(child, Path.Combine(folderPath, ToFileName(child.Name)));
}
foreach (var item in folder.Items)
{
RDOMail mail = item as RDOMail;
if (mail == null)
continue;
mail.SaveAs(Path.Combine(folderPath, ToFileName(mail.Subject)) + ".eml", rdoSaveAsType.olRFC822);
}
}
/// <summary>
/// Converts a text into a valid file name.
/// </summary>
/// <param name="fileName">The file name.</param>
/// <returns>
/// A valid file name.
/// </returns>
public static string ToFileName(string fileName)
{
return ToFileName(fileName, null, null);
}
/// <summary>
/// Converts a text into a valid file name.
/// </summary>
/// <param name="fileName">The file name.</param>
/// <param name="reservedNameFormat">The reserved format to use for reserved names. If null '_{0}_' will be used.</param>
/// <param name="reservedCharFormat">The reserved format to use for reserved characters. If null '_x{0}_' will be used.</param>
/// <returns>
/// A valid file name.
/// </returns>
public static string ToFileName(string fileName, string reservedNameFormat, string reservedCharFormat)
{
if (fileName == null)
throw new ArgumentNullException("fileName");
if (string.IsNullOrEmpty(reservedNameFormat))
{
reservedNameFormat = "_{0}_";
}
if (string.IsNullOrEmpty(reservedCharFormat))
{
reservedCharFormat = "_x{0}_";
}
if (Array.IndexOf(ReservedFileNames, fileName.ToLowerInvariant()) >= 0 ||
IsAllDots(fileName))
return string.Format(reservedNameFormat, fileName);
char[] invalid = Path.GetInvalidFileNameChars();
StringBuilder sb = new StringBuilder(fileName.Length);
foreach (char c in fileName)
{
if (Array.IndexOf(invalid, c) >= 0)
{
sb.AppendFormat(reservedCharFormat, (short)c);
}
else
{
sb.Append(c);
}
}
string s = sb.ToString();
// directory limit is 255
if (s.Length > 254)
{
s = s.Substring(0, 254);
}
if (string.Equals(s, fileName, StringComparison.Ordinal))
{
s = fileName;
}
return s;
}
private static bool IsAllDots(string fileName)
{
foreach (char c in fileName)
{
if (c != '.')
return false;
}
return true;
}
private static readonly string[] ReservedFileNames = new[]
{
"con", "prn", "aux", "nul",
"com0", "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9",
"lpt0", "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9"
};
}
}
You need essentially to do the inverse of what is being asked in that question.
Load the PST file using Outlook interop (or redemption as above)
Enumerate all the files.
Use CDO, System.Mail or similar to compose an EML file for each file in the PST.
The thing to note is that a PST doesn't contain EML files, it contains MSG files. So you will have to do some form of conversion, and you will not get back exactly what was originally sent.
See also this question: Are there .NET Framework methods to parse an email (MIME)?
I am attempting to retrieve the most recent date that my users have logged into any Google app service such as Gmail (or had this done for them via mobile device/imap/pop etc). I am an administrator of the domain on Google apps for Education and using the C# gdata-api.
I would like to recycle student usernames if they have been gone for longer than a year without signing into their gmail apps and require the last accessed date to accomplish this.
Please let me know if this is possible
Thank you.
I used the gmail reporting API. I forget where I got this from but I stole it from somewhere. If you know where, please put a comment link.
/// <summary>
/// This contains the logic for constructing and submitting a report
/// request to the Google Apps reporting service and reading the response.
///
/// The description of the web service protocol can be found at:
///
/// http://code.google.com/apis/apps/reporting/google_apps_reporting_api.html
///
/// Example usage:
/// Get the latest accounts report to standard output.
/// client.getReport("accounts", null, null);
/// Get the accounts report for May 15, 2007 and save it to out.txt.
/// client.getReport("accounts", "2007-05-15", "out.txt");
/// </summary>
public class ReportsManager
{
/// <summary>
/// URL to POST to obtain an authentication token
/// </summary>
private const string CLIENT_LOGIN_URL =
"https://www.google.com/accounts/ClientLogin";
/// <summary>
/// URL to POST to retrive resports from the API
/// </summary>
private const string REPORTING_URL =
"https://www.google.com/hosted/services/v1.0/reports/ReportingData";
/// <summary>
/// Date format of the API
/// </summary>
private const string DATE_FORMAT = "yyyy-MM-dd";
/// <summary>
/// Hour of the day when the API data gets published
/// </summary>
private const int PUBLISH_HOUR_OF_DAY = 13; // Publish hour + 1 hour;
/// <summary>
/// Time diference to UTC
/// </summary>
private const int PUBLISH_TIME_DIFERENCE_TO_UTC = -8;
/// <summary>
/// Email command-line argument
/// </summary>
private const string EMAIL_ARG = "email";
/// <summary>
/// Password command-line argument
/// </summary>
private const string PASSWORD_ARG = "password";
/// <summary>
/// Domain command-line argument
/// </summary>
private const string DOMAIN_ARG = "domain";
/// <summary>
/// Report command-line argument
/// </summary>
private const string REPORT_ARG = "report";
/// <summary>
/// Date command-line argument
/// </summary>
private const string DATE_ARG = "date";
/// <summary>
/// Output File command-line argument
/// </summary>
private const string OUT_FILE_ARG = "out";
/// <summary>
/// Message for command-line usage
/// </summary>
private const string USAGE = "Usage: " +
"ReportingAPI --" + EMAIL_ARG + " <email> --" +
PASSWORD_ARG + " <password> [ --" +
DOMAIN_ARG + " <domain> ] --" +
REPORT_ARG + " <report name> [ --" +
DATE_ARG + " <YYYY-MM-DD> ] [ --" +
OUT_FILE_ARG + " <file name> ]";
/// <summary>
/// List of command-line arguments
/// </summary>
private static string[] PROPERTY_NAMES = new String[] {EMAIL_ARG,
PASSWORD_ARG, DOMAIN_ARG, REPORT_ARG, DATE_ARG, OUT_FILE_ARG};
/// <summary>
/// List of required command-line arguments
/// </summary>
private static string[] REQUIRED_PROPERTY_NAMES = new String[] {
EMAIL_ARG, PASSWORD_ARG, REPORT_ARG};
/// <summary>
/// Google Apps Domain
/// </summary>
public string domain = null;
/// <summary>
/// Email address of an Administrator account
/// </summary>
public string email = null;
/// <summary>
/// Password of the Administrator account
/// </summary>
public string password = null;
/// <summary>
/// Identifies the type of account
/// </summary>
private string accountType = "HOSTED";
/// <summary>
/// Identifies the Google service
/// </summary>
private string service = "apps";
/// <summary>
/// Contains a token value that Google uses to authorize
/// access to the requested report data
/// </summary>
private string token = null;
/// <summary>
/// Default constructor
/// </summary>
public ReportsManager(string username, string password, string domain)
{
this.email = username + "#" + domain;
this.password = password;
this.domain = domain;
}
/// <summary>
/// Retrieves the Authentication Token
/// </summary>
/// <returns>Returns the authentication token.</returns>
public string GetToken()
{
return this.token;
}
/// <summary>
/// Logs in the user and initializes the Token
/// </summary>
public void ClientLogin()
{
string token = null;
UTF8Encoding encoding = new UTF8Encoding();
string postData = "Email=" + System.Web.HttpUtility.UrlEncode(this.email) +
"&Passwd=" + System.Web.HttpUtility.UrlEncode(this.password) +
"&accountType=" + System.Web.HttpUtility.UrlEncode(this.accountType) +
"&service=" + System.Web.HttpUtility.UrlEncode(this.service);
byte[] data = encoding.GetBytes(postData);
HttpWebRequest request =
(HttpWebRequest)WebRequest.Create(CLIENT_LOGIN_URL);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
Stream inputStream = request.GetRequestStream();
inputStream.Write(data, 0, data.Length);
inputStream.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string responseStr = (new StreamReader(
response.GetResponseStream())).ReadToEnd();
char[] tokenizer = { '\r', '\n' };
string[] parts = responseStr.Split(tokenizer);
foreach (string part in parts)
{
if (part.StartsWith("SID="))
{
token = part.Substring(4);
break;
}
}
this.token = token;
}
/// <summary>
/// Creates a XML request for the Report
/// </summary>
/// <param name="reportName">The name of the Report: activity,
/// disk_space, email_clients, quota_limit_accounts,
/// summary, suspended_account</param>
/// <param name="date">Date of the Report</param>
/// <returns>Thx XML request as a string</returns>
public string createRequestXML(string reportName, string date)
{
if (this.domain == null)
{
this.domain = getAdminEmailDomain();
}
string xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
xml += "<rest xmlns=\"google:accounts:rest:protocol\"";
xml += " xmlns:xsi=\"";
xml += "http://www.w3.org/2001/XMLSchema-instance\">";
xml += "<type>Report</type>";
xml += "<token>" + this.GetToken() + "</token>";
xml += "<domain>" + this.domain + "</domain>";
xml += "<date>" + date + "</date>";
xml += "<reportType>daily</reportType>";
xml += "<reportName>" + reportName + "</reportName>";
xml += "</rest>";
return xml;
}
/// <summary>
/// Get the domain of the admin's email address.
/// </summary>
/// <returns>the domain, otherwise returns null</returns>
public string getAdminEmailDomain()
{
if (this.email != null)
{
int atIndex = this.email.IndexOf('#');
if (atIndex > 0 && atIndex + 1 < this.email.Length)
{
return this.email.Substring(atIndex + 1);
}
}
else
{
throw new ArgumentNullException("Invalid Email");
}
return null;
}
public enum ReportType
{
accounts,
activity,
disk_space,
email_clients,
quota_limit_accounts,
summary,
suspended_account
}
/// <summary>
/// Get the reports by reportName for a Date, and writes the report
/// at filename /// or to the console if filename is null.
/// </summary>
/// <param name="reportName">The name of the Report: activity,
/// disk_space, email_clients, quota_limit_accounts,summary,
/// suspended_account</param>
/// <param name="date">Date of the Report,
/// null date gets latest date available</param>
private Dictionary<string, ArrayList> getReport(string reportName, string date)
{
if (date == null)
{
date = getLatestReportDate().ToString(DATE_FORMAT);
}
else
{
try
{
date = System.Convert.ToDateTime(date).ToString
(DATE_FORMAT);
}
catch
{
throw new ArgumentException("Invalid Date");
}
}
string xml = createRequestXML(reportName, date);
HttpWebRequest request =
(HttpWebRequest)WebRequest.Create(REPORTING_URL);
request.Method = "POST";
UTF8Encoding encoding = new UTF8Encoding();
byte[] postBuffer = encoding.GetBytes(xml);
request.ContentLength = postBuffer.Length;
request.ContentType = "application/x-www-form-urlencoded";
Stream requestStream = request.GetRequestStream();
requestStream.Write(postBuffer, 0, postBuffer.Length);
requestStream.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(
response.GetResponseStream());
String firstLine = null;
String lineBuffer = String.Empty;
if (reader.Peek() >= 0)
{
firstLine = reader.ReadLine();
checkError(firstLine, reader);
}
Dictionary<string, ArrayList> csv = new Dictionary<string, ArrayList>();
string[] headers = null;
if (firstLine != null)
{
headers = firstLine.Split(',');
foreach (string header in headers)
{
csv.Add(header, new ArrayList());
}
}
if (headers != null)
{
while ((lineBuffer = reader.ReadLine()) != null)
{
string[] dataLine = lineBuffer.Split(',');
for (int i = 0; i < csv.Keys.Count; i++)
{
csv[headers[i]].Add(dataLine[i]);
}
}
}
reader.Close();
return csv;
}
/// <summary>
/// Get the reports by reportName for a Date, and writes the report
/// at filename or to the console if filename is null.
/// </summary>
/// <param name="reportName">The name of the Report: activity,
/// disk_space, email_clients, quota_limit_accounts,summary,
/// suspended_account</param>
/// <param name="date">
/// Date of the Report, null date gets latest date available</param>
public Dictionary<string, ArrayList> getReport(ReportType reportType, DateTime date)
{
string reportName = Enum.GetName(typeof(ReportType), reportType);
return this.getReport(reportName, date.ToString(DATE_FORMAT));
}
/// <summary>
/// Checks for errors on the Http Response, errors are on XML format.
/// When the response is xml throws an Exception with the xml text.
/// </summary>
/// <param name="firstLine">
/// First line of the StreamReader from the Http Response</param>
/// <param name="reader">StreamReader from the Http Response</param>
private void checkError(string firstLine, StreamReader reader)
{
if (firstLine.Trim().StartsWith("<?xml"))
{
String xmlText = firstLine;
while (reader.Peek() >= 0)
{
xmlText += reader.ReadLine();
}
throw new Exception(xmlText);
}
}
/// <summary>
/// Get latest available report date,
/// based on report service time zone.
/// Reports for the current date are available after 12:00 PST8PDT
/// the following day.
/// </summary>
/// <returns>Lastest date available</returns>
public DateTime getLatestReportDate()
{
if (DateTime.UtcNow.AddHours(PUBLISH_TIME_DIFERENCE_TO_UTC).Hour
< PUBLISH_HOUR_OF_DAY)
{
return DateTime.Now.AddDays(-2);
}
else
{
return DateTime.Now.AddDays(-1);
}
}
/// <summary>
/// Gets the properties from the command-line arguments.
/// </summary>
/// <param name="args">command-line arguments</param>
/// <returns>Properties Hashtable</returns>
private static Hashtable getProperties(string[] args)
{
Hashtable properties = new Hashtable();
for (int i = 0; i < args.Length; i++)
{
bool found = false;
for (int j = 0; j < PROPERTY_NAMES.Length; j++)
{
if (args[i].Equals("--" + PROPERTY_NAMES[j]))
{
found = true;
if (i + 1 < args.Length)
{
properties.Add(PROPERTY_NAMES[j], args[i + 1]);
i++;
break;
}
else
{
throw new ArgumentException("Missing value for " +
"command-line parameter " + args[i]);
}
}
}
if (!found)
{
throw new ArgumentException(
"Unrecognized parameter " + args[i]);
}
}
for (int i = 0; i < REQUIRED_PROPERTY_NAMES.Length; i++)
{
if (properties[REQUIRED_PROPERTY_NAMES[i]] == null)
{
throw new ArgumentException("Missing value for " +
"command-line parameter " + REQUIRED_PROPERTY_NAMES[i]);
}
}
return properties;
}
}
To use it:
ReportsManager reports = new ReportsManager("*", "*", "*");
reports.ClientLogin();
Dictionary<string, ArrayList> accountReport = reports.getReport(ReportsManager.ReportType.accounts, DateTime.Today);
int count = accountReport["account_name"].Count;
Hashtable usersLastLoggedIn = new Hashtable();
for (int i = 0; i < count; i++)
{
DateTime lastLogged = DateTime.Parse(accountReport["last_login_time"][i].ToString());
DateTime lastWebMail = DateTime.Parse(accountReport["last_web_mail_time"][i].ToString());
DateTime lastPop = DateTime.Parse(accountReport["last_pop_time"][i].ToString());
if (lastWebMail > lastLogged) { lastLogged = lastWebMail; }
if (lastPop > lastLogged) { lastLogged = lastPop; }
usersLastLoggedIn.Add(accountReport["account_name"][i].ToString().Replace('#' + ConfigurationManager.AppSettings["domain"], string.Empty), lastLogged);
}
I spent a lot of time trying to figure out a good way to embed any file into Microsoft Word using OpenXml 2.0; Office documents are fairly easy but what about other file types such as PDF, TXT, GIF, JPG, HTML, etc....
What is a good way to get this to work for any file type, in C#?
Embedding Foreign Objects (PDF, TXT, GIF, etc…) into Microsoft Word using OpenXml 2.0
(Well, in collaboration with COM)
I got a lot from this site, so here I asked and answered my own question in order to give back a little on a topic in which I had difficulty finding answers on, hope it helps people.
There are several examples out there that show how to embed an Office Document into another Office Document using OpenXml 2.0, what’s not out there and easily understandable is how to embed just about any file into and Office Document.
I have learned a lot from other people’s code, so this is my attempt to contribute. Since I am already using OpenXml to generate documents, and I am in need of embedding other files into Word, I have decided use a collaboration of OpenXml and COM (Microsoft Office 2007 dll’s) to achieve my goal. If you are like me, “invoking the OLE server application to create an IStorage” doesn’t mean much to you.
In this example I’d like to show how I use COM to PROGRMATICALLY get the OLE-binary data information of the attached file, and then how I used that information within my OpenXml document. Basically, I am programmatically looking at the OpenXml 2.0 Document Reflector to get the information I need.
My code below is broken down into several classes, but here is an outline of what I am doing:
Create an OpenXml WordProcessingDocument, get the System.IO.FileInfo for the file you want to Embed
Create a custom OpenXmlEmbeddedObject object (this is what holds all the binary data)
Use the binary data from the above step to create Data and Image Streams
Use those Streams as the File Object and File Image for your OpenXml Document
I know there is a lot of code, and not much explanation… Hopefully it is easy to follow and will help people out
Requirements:
• DocumentFormat.OpenXml dll (OpenXml 2.0)
• WindowsBase dll
• Microsoft.Office.Interop.Word dll (Office 2007 – version 12)
• This the main class that starts everything, opens a WordProcessingDocument and class to have the file attached
using DocumentFormat.OpenXml.Packaging;
using System.IO;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Wordprocessing;
public class MyReport
{
private MainDocumentPart _mainDocumentPart;
public void CreateReport()
{
using (WordprocessingDocument wpDocument = WordprocessingDocument.Create(#"TempPath\MyReport.docx", WordprocessingDocumentType.Document))
{
_mainDocumentPart = wpDocument.AddMainDocumentPart();
_mainDocumentPart.Document = new Document(new Body());
AttachFile(#"MyFilePath\MyFile.pdf", true);
}
}
private void AttachFile(string filePathAndName, bool displayAsIcon)
{
FileInfo fileInfo = new FileInfo(filePathAndName);
OpenXmlHelper.AppendEmbeddedObject(_mainDocumentPart, fileInfo, displayAsIcon);
}
}
• This class in an OpenXml helper class, holds all the logic to embed an object into your OpenXml File
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Validation;
using DocumentFormat.OpenXml.Wordprocessing;
using OVML = DocumentFormat.OpenXml.Vml.Office;
using V = DocumentFormat.OpenXml.Vml;
public class OpenXmlHelper
{
/// <summary>
/// Appends an Embedded Object into the specified Main Document
/// </summary>
/// <param name="mainDocumentPart">The MainDocument Part of your OpenXml Word Doc</param>
/// <param name="fileInfo">The FileInfo object associated with the file being embedded</param>
/// <param name="displayAsIcon">Whether or not to display the embedded file as an Icon (Otherwise it will display a snapshot of the file)</param>
public static void AppendEmbeddedObject(MainDocumentPart mainDocumentPart, FileInfo fileInfo, bool displayAsIcon)
{
OpenXmlEmbeddedObject openXmlEmbeddedObject = new OpenXmlEmbeddedObject(fileInfo, displayAsIcon);
if (!String.IsNullOrEmpty(openXmlEmbeddedObject.OleObjectBinaryData))
{
using (Stream dataStream = new MemoryStream(Convert.FromBase64String(openXmlEmbeddedObject.OleObjectBinaryData)))
{
if (!String.IsNullOrEmpty(openXmlEmbeddedObject.OleImageBinaryData))
{
using (Stream emfStream = new MemoryStream(Convert.FromBase64String(openXmlEmbeddedObject.OleImageBinaryData)))
{
string imagePartId = GetUniqueXmlItemID();
ImagePart imagePart = mainDocumentPart.AddImagePart(ImagePartType.Emf, imagePartId);
if (emfStream != null)
{
imagePart.FeedData(emfStream);
}
string embeddedPackagePartId = GetUniqueXmlItemID();
if (dataStream != null)
{
if (openXmlEmbeddedObject.ObjectIsOfficeDocument)
{
EmbeddedPackagePart embeddedObjectPart = mainDocumentPart.AddNewPart<EmbeddedPackagePart>(
openXmlEmbeddedObject.FileContentType, embeddedPackagePartId);
embeddedObjectPart.FeedData(dataStream);
}
else
{
EmbeddedObjectPart embeddedObjectPart = mainDocumentPart.AddNewPart<EmbeddedObjectPart>(
openXmlEmbeddedObject.FileContentType, embeddedPackagePartId);
embeddedObjectPart.FeedData(dataStream);
}
}
if (!displayAsIcon && !openXmlEmbeddedObject.ObjectIsPicture)
{
Paragraph attachmentHeader = CreateParagraph(String.Format("Attachment: {0} (Double-Click to Open)", fileInfo.Name));
mainDocumentPart.Document.Body.Append(attachmentHeader);
}
Paragraph embeddedObjectParagraph = GetEmbeededObjectParagraph(openXmlEmbeddedObject.FileType,
imagePartId, openXmlEmbeddedObject.OleImageStyle, embeddedPackagePartId);
mainDocumentPart.Document.Body.Append(embeddedObjectParagraph);
}
}
}
}
}
/// <summary>
/// Gets Paragraph that includes the embedded object
/// </summary>
private static Paragraph GetEmbeededObjectParagraph(string fileType, string imageID, string imageStyle, string embeddedPackageID)
{
EmbeddedObject embeddedObject = new EmbeddedObject();
string shapeID = GetUniqueXmlItemID();
V.Shape shape = new V.Shape() { Id = shapeID, Style = imageStyle };
V.ImageData imageData = new V.ImageData() { Title = "", RelationshipId = imageID };
shape.Append(imageData);
OVML.OleObject oleObject = new OVML.OleObject()
{
Type = OVML.OleValues.Embed,
ProgId = fileType,
ShapeId = shapeID,
DrawAspect = OVML.OleDrawAspectValues.Icon,
ObjectId = GetUniqueXmlItemID(),
Id = embeddedPackageID
};
embeddedObject.Append(shape);
embeddedObject.Append(oleObject);
Paragraph paragraphImage = new Paragraph();
Run runImage = new Run(embeddedObject);
paragraphImage.Append(runImage);
return paragraphImage;
}
/// <summary>
/// Gets a Unique ID for an XML Item, for reference purposes
/// </summary>
/// <returns>A GUID string with removed dashes</returns>
public static string GetUniqueXmlItemID()
{
return "r" + System.Guid.NewGuid().ToString().Replace("-", "");
}
private static Paragraph CreateParagraph(string paragraphText)
{
Paragraph paragraph = new Paragraph();
ParagraphProperties paragraphProperties = new ParagraphProperties();
paragraphProperties.Append(new Justification()
{
Val = JustificationValues.Left
});
paragraphProperties.Append(new SpacingBetweenLines()
{
After = Convert.ToString(100),
Line = Convert.ToString(100),
LineRule = LineSpacingRuleValues.AtLeast
});
Run run = new Run();
RunProperties runProperties = new RunProperties();
Text text = new Text();
if (!String.IsNullOrEmpty(paragraphText))
{
text.Text = paragraphText;
}
run.Append(runProperties);
run.Append(text);
paragraph.Append(paragraphProperties);
paragraph.Append(run);
return paragraph;
}
}
• This is the most important part of this process, it is using Microsoft's internal OLE Server, creates the Binary DATA and Binary EMF information for a file. All you have to here is call the OpenXmlEmbeddedObject constructor and all get’s taken care of. It will mimic the process that goes on when you manually drag any file into Word; there is some kind of conversion that goes on when you do that, turning the file into an OLE object, so that Microsoft can recognize the file.
o The most imporant parts of this class are the OleObjectBinaryData and OleImageBinaryData properties; they contain the 64Bit string binary info for the file data and ‘.emf’ image.
o If you choose to not display the file as an icon, then the ‘.emf’ image data will create a snapshot of the file, like the first page of the pdf file for example, in which you can still double-click to open
o If you are embedding an image and choose not to display it as an Icon, then the OleObjectBinaryData and OleImageBinaryData properties will be the same
using System.Runtime.InteropServices;
using System.Xml;
using System.Diagnostics;
using System.IO;
using System.Drawing;
using Microsoft.Office.Interop.Word;
public class OpenXmlEmbeddedObject
{
#region Constants
private const string _defaultOleContentType = "application/vnd.openxmlformats-officedocument.oleObject";
private const string _oleObjectDataTag = "application/vnd";
private const string _oleImageDataTag = "image/x-emf";
#endregion Constants
#region Member Variables
private static FileInfo _fileInfo;
private static string _filePathAndName;
private static bool _displayAsIcon;
private static bool _objectIsPicture;
private object _objectMissing = System.Reflection.Missing.Value;
private object _objectFalse = false;
private object _objectTrue = true;
#endregion Member Variables
#region Properties
/// <summary>
/// The File Type, as stored in Registry (Ex: a GIF Image = 'giffile')
/// </summary>
public string FileType
{
get
{
if (String.IsNullOrEmpty(_fileType) && _fileInfo != null)
{
_fileType = GetFileType(_fileInfo, false);
}
return _fileType;
}
}
private string _fileType;
/// <summary>
/// The File Context Type, as storered in Registry (Ex: a GIF Image = 'image/gif')
/// * Is converted into the 'Default Office Context Type' for non-office files
/// </summary>
public string FileContentType
{
get
{
if (String.IsNullOrEmpty(_fileContentType) && _fileInfo != null)
{
_fileContentType = GetFileContentType(_fileInfo);
if (!_fileContentType.Contains("officedocument"))
{
_fileContentType = _defaultOleContentType;
}
}
return _fileContentType;
}
}
private string _fileContentType;
/// <summary>
/// Gets the ContentType Text for the file
/// </summary>
public static string GetFileContentType(FileInfo fileInfo)
{
if (fileInfo == null)
{
throw new ArgumentNullException("fileInfo");
}
string mime = "application/octetstream";
string ext = System.IO.Path.GetExtension(fileInfo.Name).ToLower();
Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);
if (rk != null && rk.GetValue("Content Type") != null)
{
mime = rk.GetValue("Content Type").ToString();
}
return mime;
}
public bool ObjectIsOfficeDocument
{
get { return FileContentType != _defaultOleContentType; }
}
public bool ObjectIsPicture
{
get { return _objectIsPicture; }
}
public string OleObjectBinaryData
{
get { return _oleObjectBinaryData; }
set { _oleObjectBinaryData = value; }
}
private string _oleObjectBinaryData;
public string OleImageBinaryData
{
get { return _oleImageBinaryData; }
set { _oleImageBinaryData = value; }
}
private string _oleImageBinaryData;
/// <summary>
/// The OpenXml information for the Word Application that is created (Make-Shoft Code Reflector)
/// </summary>
public string WordOpenXml
{
get { return _wordOpenXml; }
set { _wordOpenXml = value; }
}
private String _wordOpenXml;
/// <summary>
/// The XmlDocument that is created based on the OpenXml Data from WordOpenXml
/// </summary>
public XmlDocument OpenXmlDocument
{
get
{
if (_openXmlDocument == null && !String.IsNullOrEmpty(WordOpenXml))
{
_openXmlDocument = new XmlDocument();
_openXmlDocument.LoadXml(WordOpenXml);
}
return _openXmlDocument;
}
}
private XmlDocument _openXmlDocument;
/// <summary>
/// The XmlNodeList, for all Nodes containing 'binaryData'
/// </summary>
public XmlNodeList BinaryDataXmlNodesList
{
get
{
if (_binaryDataXmlNodesList == null && OpenXmlDocument != null)
{
_binaryDataXmlNodesList = OpenXmlDocument.GetElementsByTagName("pkg:binaryData");
}
return _binaryDataXmlNodesList;
}
}
private XmlNodeList _binaryDataXmlNodesList;
/// <summary>
/// Icon Object for the file
/// </summary>
public Icon ObjectIcon
{
get
{
if (_objectIcon == null)
{
_objectIcon = Enterprise.Windows.Win32.Win32.GetLargeIcon(_filePathAndName);
}
return _objectIcon;
}
}
private Icon _objectIcon;
/// <summary>
/// File Name for the Icon being created
/// </summary>
public string ObjectIconFile
{
get
{
if (String.IsNullOrEmpty(_objectIconFile))
{
_objectIconFile = String.Format("{0}.ico", _filePathAndName.Replace(".", ""));
}
return _objectIconFile;
}
}
private string _objectIconFile;
/// <summary>
/// Gets the original height and width of the emf file being created
/// </summary>
public string OleImageStyle
{
get
{
if (String.IsNullOrEmpty(_oleImageStyle) && !String.IsNullOrEmpty(WordOpenXml))
{
XmlNodeList xmlNodeList = OpenXmlDocument.GetElementsByTagName("v:shape");
if (xmlNodeList != null && xmlNodeList.Count > 0)
{
foreach (XmlAttribute attribute in xmlNodeList[0].Attributes)
{
if (attribute.Name == "style")
{
_oleImageStyle = attribute.Value;
}
}
}
}
return _oleImageStyle;
}
set { _oleImageStyle = value; }
}
private string _oleImageStyle;
#endregion Properties
#region Constructor
/// <summary>
/// Generates binary information for the file being passed in
/// </summary>
/// <param name="fileInfo">The FileInfo object for the file to be embedded</param>
/// <param name="displayAsIcon">Whether or not to display the file as an Icon (Otherwise it will show a snapshot view of the file)</param>
public OpenXmlEmbeddedObject(FileInfo fileInfo, bool displayAsIcon)
{
_fileInfo = fileInfo;
_filePathAndName = fileInfo.ToString();
_displayAsIcon = displayAsIcon;
SetupOleFileInformation();
}
#endregion Constructor
#region Methods
/// <summary>
/// Creates a temporary Word App in order to add an OLE Object, get's the OpenXML data from the file (similar to the Code Reflector info)
/// </summary>
private void SetupOleFileInformation()
{
Microsoft.Office.Interop.Word.Application wordApplication = new Microsoft.Office.Interop.Word.Application();
Microsoft.Office.Interop.Word.Document wordDocument = wordApplication.Documents.Add(ref _objectMissing, ref _objectMissing,
ref _objectMissing, ref _objectMissing);
object iconObjectFileName = _objectMissing;
object objectClassType = FileType;
object objectFilename = _fileInfo.ToString();
Microsoft.Office.Interop.Word.InlineShape inlineShape = null;
if (_displayAsIcon)
{
if (ObjectIcon != null)
{
using (FileStream iconStream = new FileStream(ObjectIconFile, FileMode.Create))
{
ObjectIcon.Save(iconStream);
iconObjectFileName = ObjectIconFile;
}
}
object objectIconLabel = _fileInfo.Name;
inlineShape = wordDocument.InlineShapes.AddOLEObject(ref objectClassType,
ref objectFilename, ref _objectFalse, ref _objectTrue, ref iconObjectFileName,
ref _objectMissing, ref objectIconLabel, ref _objectMissing);
}
else
{
try
{
Image image = Image.FromFile(_fileInfo.ToString());
_objectIsPicture = true;
OleImageStyle = String.Format("height:{0}pt;width:{1}pt", image.Height, image.Width);
wordDocument.InlineShapes.AddPicture(_fileInfo.ToString(), ref _objectMissing, ref _objectTrue, ref _objectMissing);
}
catch
{
inlineShape = wordDocument.InlineShapes.AddOLEObject(ref objectClassType,
ref objectFilename, ref _objectFalse, ref _objectFalse, ref _objectMissing, ref _objectMissing,
ref _objectMissing, ref _objectMissing);
}
}
WordOpenXml = wordDocument.Range(ref _objectMissing, ref _objectMissing).WordOpenXML;
if (_objectIsPicture)
{
OleObjectBinaryData = GetPictureBinaryData();
OleImageBinaryData = GetPictureBinaryData();
}
else
{
OleObjectBinaryData = GetOleBinaryData(_oleObjectDataTag);
OleImageBinaryData = GetOleBinaryData(_oleImageDataTag);
}
// Not sure why, but Excel seems to hang in the processes if you attach an Excel file…
// This kills the excel process that has been started < 15 seconds ago (so not to kill the user's other Excel processes that may be open)
if (FileType.StartsWith("Excel"))
{
Process[] processes = Process.GetProcessesByName("EXCEL");
foreach (Process process in processes)
{
if (DateTime.Now.Subtract(process.StartTime).Seconds <= 15)
{
process.Kill();
break;
}
}
}
wordDocument.Close(ref _objectFalse, ref _objectMissing, ref _objectMissing);
wordApplication.Quit(ref _objectMissing, ref _objectMissing, ref _objectMissing);
}
/// <summary>
/// Gets the binary data from the Xml File that is associated with the Tag passed in
/// </summary>
/// <param name="binaryDataXmlTag">the Tag to look for in the OpenXml</param>
/// <returns></returns>
private string GetOleBinaryData(string binaryDataXmlTag)
{
string binaryData = null;
if (BinaryDataXmlNodesList != null)
{
foreach (XmlNode xmlNode in BinaryDataXmlNodesList)
{
if (xmlNode.ParentNode != null)
{
foreach (XmlAttribute attr in xmlNode.ParentNode.Attributes)
{
if (String.IsNullOrEmpty(binaryData) && attr.Value.Contains(binaryDataXmlTag))
{
binaryData = xmlNode.InnerText;
break;
}
}
}
}
}
return binaryData;
}
/// <summary>
/// Gets the image Binary data, if the file is an image
/// </summary>
/// <returns></returns>
private string GetPictureBinaryData()
{
string binaryData = null;
if (BinaryDataXmlNodesList != null)
{
foreach (XmlNode xmlNode in BinaryDataXmlNodesList)
{
binaryData = xmlNode.InnerText;
break;
}
}
return binaryData;
}
/// <summary>
/// Gets the file type description ("Application", "Text Document", etc.) for the file.
/// </summary>
/// <param name="fileInfo">FileInfo containing extention</param>
/// <returns>Type Description</returns>
public static string GetFileType(FileInfo fileInfo, bool returnDescription)
{
if (fileInfo == null)
{
throw new ArgumentNullException("fileInfo");
}
string description = "File";
if (string.IsNullOrEmpty(fileInfo.Extension))
{
return description;
}
description = string.Format("{0} File", fileInfo.Extension.Substring(1).ToUpper());
RegistryKey typeKey = Registry.ClassesRoot.OpenSubKey(fileInfo.Extension);
if (typeKey == null)
{
return description;
}
string type = Convert.ToString(typeKey.GetValue(string.Empty));
RegistryKey key = Registry.ClassesRoot.OpenSubKey(type);
if (key == null)
{
return description;
}
if (returnDescription)
{
description = Convert.ToString(key.GetValue(string.Empty));
return description;
}
else
{
return type;
}
}
#endregion Methods
}
_objectIcon = Enterprise.Windows.Win32.Win32.GetLargeIcon(_filePathAndName);
seems to be broken, but
_objectIcon = System.Drawing.Icon.ExtractAssociatedIcon(_filePathAndName);
should also work.
My answer here will tell you how to do this, but not show you with the SDK or a specific language.
This is a great answer and it helped me a lot, but the potential bug that user bic mentioned also exists
in
OpenXmlEmbeddedObject(FileInfo fileInfo, bool displayAsIcon)
at line 242,
_filePathAndName = fileInfo.ToString();
in
SetupOleFileInformation()
at line 264,
object objectFilename = _fileInfo.ToString();
line 289, and
Image image = Image.FromFile(_fileInfo.ToString());
line 293
wordDocument.InlineShapes.AddPicture(_fileInfo.toString(), ref _objectMissing, ref _objectTrue, ref _objectMissing);
All of these need to be "FullName" instead of "ToString()" if the code should work with relative paths as well. Hope this helps anyone who wants to use D Lyonnais's code!
Make a copy of the document how you wanted to get through code and then use Open XML SDK Tool 2.5 for Microsoft Office for writing code. This tool reflects code. which you can simply copy paste.