DocumentProperties, CustomDocumentProperties and MetaProperties of PowerPoint


Some time you want to change the DocumentProperties or CustomDocumentProperties or MetaProperties of a PowerPoint document by programming. I have came around a similar situation in one of my recent project and found some useful bit of knowledge.

I was working with PowerPoint automation through C# (2005). So this solution is for PowerPoint only. If you want for Word/ Excel you’ll get lot of useful solutions by googling. But before you try you need to know that many of the solutions might not work in your case and Office Automation is not supported by Microsoft.

Still want to go through the pain! OK, here are the codes:

First add a reference to PowerPoint in your project:

using PowerPoint = Microsoft.Office.Interop.PowerPoint;

Then, in your suitable method instantiate the Object:

object oMissing = System.Reflection.Missing.Value;

//Prepare PowerPoint
PowerPoint.Application oPP = new PowerPoint.ApplicationClass();
// If you are running is a batch mode then you might not want the alert message boxes
oPP.DisplayAlerts = Microsoft.Office.Interop.PowerPoint.PpAlertLevel.ppAlertsNone;
oPP.Visible = MsoTriState.msoTrue;
PowerPoint.Presentations oPresSet = oPP.Presentations;
PowerPoint._Presentation _activePres = oPresSet.Open("YOUR_FILE_PATH",
MsoTriState.msoTrue, MsoTriState.msoFalse,
MsoTriState.msoTrue);

Now, once you have your PowerPoint object created, then you can go for the Properties.
First, BuiltInDocumentProperties

Here is a function which I have created for this purpose:

ShowBuiltInDocumentProperties(_activePres.BuiltInDocumentProperties)

public static void ShowBuiltInDocumentProperties(object builtInProps)
{
Console.WriteLine("Builtin Properties: START");

Type etype = builtInProps.GetType();
foreach (int i in Enum.GetValues(etype))
{
object item = GetPropertyValue(builtInProps, "Item", i);

object val = null;
try { val = GetPropertyValue(item, "Value"); }
catch { continue; }

string name = Enum.GetName(etype, i).Substring(10);

Console.WriteLine(String.Format("Item: {0} Name : {1} Value : {0} ", Convert.ToString(item), name,
(null != val) ? Convert.ToString(val) : ""));
}

Console.WriteLine("Builtin Properties: END");
}

public static object GetPropertyValue(object src, object source,
string name, params object[] parameters)
{
return source.GetType().InvokeMember(name,
BindingFlags.Default | BindingFlags.GetProperty,
null, source, parameters);
}

So, you are through with BuiltInDocumentProperties. Now, lets look at CustomDocumentProperties. For this I also have a function ShowCustomProperties(_activePres.CustomDocumentProperties)


public static void ShowCustomProperties(object customProps)
{
Console.WriteLine("Custom Properties: START");
Type typeCustomProps = customProps.GetType();

int count = Convert.ToInt32(
GetPropertyValue(typeCustomProps, customProps, "Count"));

Console.WriteLine("Custom Properties Count: " + Convert.ToString(count));

for (int i = 1; i <= count; i++)
{
object item = GetPropertyValue(typeCustomProps, customProps, "Item", i);
Type typeProp = item.GetType();

object val = GetPropertyValue(typeProp, item, "Value");
string name = GetPropertyValue(typeProp, item, "Name").ToString();

Console.WriteLine(String.Format("Item: {0} Type {1} Name : {2} Value : {3} ",
Convert.ToString(item), typeProp.ToString(), name, Convert.ToString(val)));
}

Console.WriteLine("Custom Properties: END");
}

As you can see, I have used the same GetPropertyValue function in this as well.

Ok, let’s see how to set a CustomDocumentProperty:


public static void SetCustomProperties(object customProps, string _propName, string _value)
{
Console.WriteLine(String.Format("Set Custom Properties: START >> Name: {0} Value {1}", _propName, _value));
Type typeCustomProps = customProps.GetType();

int count = Convert.ToInt32(
GetPropertyValue(typeCustomProps, customProps, "Count"));

for (int i = 1; i <= count; i++)
{
object item = GetPropertyValue(typeCustomProps, customProps, "Item", i);
Type typeProp = item.GetType();

object val = GetPropertyValue(typeProp, item, "Value");
string name = GetPropertyValue(typeProp, item, "Name").ToString();

Console.WriteLine(String.Format("Item: {0} Type {1} Name : {2} Value : {3} ",
Convert.ToString(item), typeProp.ToString(), name, Convert.ToString(val)));

if (name.ToLower().Equals(_propName.ToLower()))
{
object[] oArgs = {_propName,false,
MsoDocProperties.msoPropertyTypeString,
_value};

customProps.GetType().InvokeMember("Item",
BindingFlags.Default |
BindingFlags.SetProperty,
null, customProps,
oArgs);
}
}

Console.WriteLine("Set Custom Properties: END");
}

Ok! We are through with Custom Document Properties and Built In Document Properties. Now, let’s check Meta Properties.

This Meta Properties are bit tricky. Support you have SharePoint document Library for PowerPoint document type. You have designed a content type with few columns. Some of them are type of string or look up or Integer or multi value look up. Now, you want to change those values programmatically. In this case you need to use the MetaProperty of a PowerPoint document.


MetaProperties _activePresentationContentTypeProperties
= _activePres.ContentTypeProperties;

MetaProperty _mp = null;

If you want to find a specific property then you can use the following method:

FindSpecificContentTypeProperty(_activePres.ContentTypeProperties, "Test")


public static MetaProperty FindSpecificContentTypeProperty(MetaProperties _props, String _propName)
{
if (null == _props || _props.Count == 0)
return null;

foreach (object _o in _props)
{
try
{
MetaProperty _mp = (MetaProperty)_o;

if (null != _mp)
{
//Check if the ppt contains valie for a specific property or not
// if value was there then add the value to the template

if (_mp.Id.ToLower().Equals(_propName.ToLower()))
{
Console.WriteLine("Content Type Property found.");
return _mp;
}
}

}
catch (Exception _e)
{
throw _e;
}
}

return null;
}

Now, once you find the Property you might want to get the data or set the data. Following methods are for that purpose:


public static String GetContentTypePropertyValue(MetaProperty _cp)
{
String sReturn = null;

try
{
if (null == _cp)
throw new Exception("Content Type Property is NULL");

if (null == _cp.Value)
throw new Exception("Content Type Property Value is NULL");

switch (_cp.Type)
{
case MsoMetaPropertyType.msoMetaPropertyTypeMultiChoiceFillIn:
String[] _arr = (String[])_cp.Value;
sReturn = "";
for (int i = 0; i < _arr.Length; i++)
{
sReturn += _arr[i] + ",";
}
sReturn = sReturn.Substring(0, sReturn.Length - 1);
break;
case MsoMetaPropertyType.msoMetaPropertyTypeNumber:
sReturn = Convert.ToString(_cp.Value);
break;
case MsoMetaPropertyType.msoMetaPropertyTypeLookup:
sReturn = Convert.ToString(_cp.Value);
break;
default:
sReturn = Convert.ToString(_cp.Value);
break;
}
}
catch (Exception _exp)
{
throw _exp;
}

return sReturn;
}

public static void SetContentTypePropertyValue(ref MetaProperty _mp, String _value)
{
try
{
if (null == _mp)
throw new Exception("Content Type Property is NULL. Please check whether the slide is properly created.");
else
Console.WriteLine("Content Type Property: " + _mp.Name);

if (null == _value)
throw new Exception("Value is NULL.: " + _mp.Name);
else
Console.WriteLine("Value: " + _value);

switch (_mp.Type)
{
case MsoMetaPropertyType.msoMetaPropertyTypeMultiChoiceFillIn:
Console.WriteLine("Value Type: MultiChoiceFillIn");
try
{
String[] _arr = _value.Split(';');
_mp.Value = _arr;
}
catch (Exception)
{
try
{
_mp.Value = _value;
}
catch (Exception _ex)
{
throw _ex;
}
}

break;
case MsoMetaPropertyType.msoMetaPropertyTypeNumber:
Console.WriteLine("Value Type: Number");
_mp.Value = _value;
break;
case MsoMetaPropertyType.msoMetaPropertyTypeLookup:
Console.WriteLine("Value Type: Lookup");
_mp.Value = _value;
break;
default:
_mp.Value = _value;
break;
}
}
catch (Exception _exp)
{
throw _exp;
}
}

And finally here is how I have closed my PowerPoint instances. This is not related to the topic but as I have instantiated those then I need to release them, right 🙂


if (null != _activePres)
{
Console.WriteLine("Close Active Presentation.");
_activePres.Close();

System.Runtime.InteropServices.Marshal.FinalReleaseComObject(_activePres);
_activePres = null;
}

if (null != oPresSet)
{
Console.WriteLine("Close Presentation.");
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oPresSet);
oPresSet = null;
}

if (null != oPP)
{
Console.WriteLine("QUIT Power Point.");
oPP.Quit();
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oPP);
oPP = null;
}

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

I hope this post will come as useful to some one.. Please let me know if there is any issues running the code…

Advertisements

User validation with LDAP in C# (2005)


Once in my project I came to a problem where I need to validate a user with LDAP server. My project was in C# (2005). I have searched a lot in Google and at the end I got a working solution. There is another solution as well which does not worked for me but I guess for somebody else it might. So, I’ll present both of them here:

First the one which is widely used (but didn’t worked for me 😦 )

For this one you need to add a reference to System.DirectoryServices in your code.


public static bool ValidateUserCredentials(string _domain, string _userName, string _password)
{
DirectoryEntry nRoot = null;

try
{
nRoot = new DirectoryEntry("YOUR_LDAP_SERVER_PATH", _domain + "//" + _userName, _password);
//You can omit the domain if you want
nRoot.AuthenticationType = AuthenticationTypes.None;

Object obj = nRoot.NativeObject;

DirectorySearcher search = new DirectorySearcher(nRoot);

search.SearchScope = SearchScope.Subtree;
search.Filter = "(sAMAccountName=" + _userName + ")";
//You can specify the properties to Load
//search.PropertiesToLoad.Add("uid");

SearchResult _sr = search.FindOne();

if (null != _sr)
{
ResultPropertyCollection myResultPropColl = _sr.Properties;

foreach (string myKey in myResultPropColl.PropertyNames)
{
string tab = "    ";
Console.WriteLine(myKey + " = ");

foreach (Object myCollection in myResultPropColl[myKey])
{
string _val = tab + myCollection;
}
}
return true;
}
else
{
throw new Exception("User Not found");
}

}
catch (Exception _exp)
{
throw _exp;
}
finally
{
if (null != nRoot)
nRoot.Close();
}
}

And, following is the one worked for me.

For this one you need to add System.DirectoryServices.AccountManagement namespace in your reference.

 

public static bool ValidateUserCredentials(string _domain, string _userName, string _pwd)
{
try
{
PrincipalContext pc = new PrincipalContext(ContextType.Domain, _domain);

bool isValid = pc.ValidateCredentials(_userName, _pwd);
return isValid;

}
catch (Exception _Exp)
{
throw _Exp;
}
}

Don’t forget to tell me which one works for you 🙂