Where does Outlook store which PST files are mounted? [closed] - outlook

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I'd like to programmatically add a PST file to a person's Outlook profile. I found some code here:
http://www.eggheadcafe.com/community/aspnet/65/10030171/try-this-code.aspx
While that does the trick, it still leaves the question - "Where does outlook keep this list of mounted PST files?" Is it in the registry? A config file somewhere? Anybody?

That's an internal implementation detail subject to change from version to version.

This code (from a current project) searches for and decodes the names and paths of both Unicode & Non-Unicode PST files.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Outlook = Microsoft.Office.Interop.Outlook;
using Microsoft.Win32;
namespace PSTRemoval_v2
{
class PSTRReg
{
public RegistryKey regOPs, regPR, regCU, regCP, regCC;
public Dictionary<string, string> OpenPSTs = new Dictionary<string, string>();
public Dictionary<string, string> ClosedPSTs = new Dictionary<string, string>();
public Dictionary<string, string> PurgedPSTs = new Dictionary<string, string>();
public void ValidRegEntries(Outlook.Application olApp)
{
string prf = olApp.Session.CurrentProfileName; // retrieve current Outlook profile name. Needed in case user has multiple profiles
regCU = Registry.CurrentUser;
regOPs = regCU.CreateSubKey(String.Format(#"Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\{0}",prf));
regPR = regCU.CreateSubKey(String.Format(#"Software\WRT\OutlookAddins\PSTRemoval\{0}", prf)); // create a subkey in the registry for this profile
regCC = regPR.CreateSubKey(#"ClosedPSTs");
regCP = regPR.CreateSubKey(#"PurgedPSTs");
}
public void OpenPSTs_REG_Read()
{
PSTRNet regnet = new PSTRNet();
regnet.EnumerateNetworkDrives();
string[] sk = regOPs.GetSubKeyNames();
foreach (string subkey in sk)
{
RegistryKey rk2 = regOPs.OpenSubKey(subkey);
if (rk2.ValueCount > 0)
{
string[] vn = rk2.GetValueNames();
Array.Sort(vn);
int bs = Array.BinarySearch(vn, "001f3001"); // search for the PST Name
int bs1 = Array.BinarySearch(vn, "001f3006"); // PST Name alternative
if ((bs > -1) || (bs1 > -1))
{
int bs2 = Array.BinarySearch(vn, "001f6700"); // search for the PST Path
if (bs2 > -1)
{
// decode the Name & Path to text strings
string PSTName;
try { PSTName = decode(vn[bs], rk2); }
catch { PSTName = decode(vn[bs1], rk2); }
string PSTPath = decode(vn[bs2], rk2);
if (regnet.PSTOnNet(PSTPath)) // add the PST to the list if it is on a network drive
{
try
{
OpenPSTs.Add(PSTPath, PSTName);
}
catch { }
regOPs.DeleteSubKey(subkey); // then delete the entry from the main part of the registry
}
}
}
}
}
}
public void PSTs_REG_Read(RegistryKey regkey, Dictionary<string, string> entries)
{
string[] RK = regkey.GetValueNames();
if (RK.Length > 0)
foreach (string ValueName in RK)
try { entries.Add(ValueName, regkey.GetValue(ValueName).ToString()); }
catch { }
}
public void PSTs_Reg_write(RegistryKey regKey, Dictionary<string, string> entries)
{
string[] RK_Delete = regKey.GetValueNames();
if (RK_Delete.Length > 0)
foreach (string ValueName in RK_Delete)
regKey.DeleteValue(ValueName);
foreach (KeyValuePair<string, string> kvp in entries)
regKey.SetValue(kvp.Key, kvp.Value);
}
private string decode(string value, RegistryKey rk) // decode registry entries from Unicode to plain text
{
byte[] b = (byte[])rk.GetValue(value);
return Encoding.Unicode.GetString(b);
}
}
}
}
The registry entry is Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\<ProfileName>
001f301 is the name of the unicode PST

It's in the registry, by the way.

Related

Combining forms while retaining form fonts in itext7

I am trying to fill and combine multiple forms without flattening(need to keep them interactive for users). However I notice a problem. I have PDF files that contain the forms I am trying to fill. The form fields have their fonts set in adobe PDF. I notice after I combine the forms the fields lose their original fonts. Here is my program.
using iText.Forms;
using iText.Kernel.Pdf;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace PdfCombineTest
{
class Program
{
static void Main(string[] args)
{
Stream file1;
Stream file2;
using (var stream = new FileStream("./pdf-form-1.pdf", FileMode.Open, FileAccess.Read))
{
file1 = Program.Fill(stream, new[] { KeyValuePair.Create("Text1", "TESTING"), KeyValuePair.Create("CheckBox1", "Yes") });
}
using (var stream = new FileStream("./pdf-form-2.pdf", FileMode.Open, FileAccess.Read))
{
file2 = Program.Fill(stream, new[] { KeyValuePair.Create("Text2", "text 2 text") });
}
using (Stream output = Program.Combine(new[] { file1, file2 }))
{
using (var fileStream = File.Create("./output.pdf"))
{
output.CopyTo(fileStream);
}
}
}
public static Stream Combine(params Stream[] streams)
{
MemoryStream copyStream = new MemoryStream();
PdfWriter writer = new PdfWriter(copyStream);
writer.SetSmartMode(true);
writer.SetCloseStream(false);
PdfPageFormCopier formCopier = new PdfPageFormCopier();
using (PdfDocument combined = new PdfDocument(writer))
{
combined.InitializeOutlines();
foreach (var stream in streams)
{
using (PdfDocument document = new PdfDocument(new PdfReader(stream)))
{
document.CopyPagesTo(1, document.GetNumberOfPages(), combined, formCopier);
}
}
}
copyStream.Seek(0, SeekOrigin.Begin);
return copyStream;
}
public static Stream Fill(Stream inputStream, IEnumerable<KeyValuePair<string, string>> keyValuePairs)
{
MemoryStream outputStream = new MemoryStream();
PdfWriter writer = new PdfWriter(outputStream);
writer.SetCloseStream(false);
using (PdfDocument document = new PdfDocument(new PdfReader(inputStream), writer))
{
PdfAcroForm acroForm = PdfAcroForm.GetAcroForm(document, true);
acroForm.SetGenerateAppearance(true);
IDictionary<string, iText.Forms.Fields.PdfFormField> fields = acroForm.GetFormFields();
foreach (var kvp in keyValuePairs)
{
fields[kvp.Key].SetValue(kvp.Value);
}
}
outputStream.Seek(0, SeekOrigin.Begin);
return outputStream;
}
}
}
I've noticed after several hours of debugging that PdfPageFormCopier excludes the default resources which contain fonts when merging form fields, is there a way around this? The project I'm working on currently does this process in ItextSharp and it works as intended. However we are looking to migrate to iText7.
Here are links to some sample pdf's I made I can't upload the actual pdf's I'm working with but these display the same problem.
https://www.dropbox.com/s/pukt91d4xe8gmmo/pdf-form-1.pdf?dl=0
https://www.dropbox.com/s/c52x6bc99gnrvo6/pdf-form-2.pdf?dl=0
So my solution was to modify the PdfPageFormCopier class from iText. The main issue is in the function below.
public virtual void Copy(PdfPage fromPage, PdfPage toPage) {
if (documentFrom != fromPage.GetDocument()) {
documentFrom = fromPage.GetDocument();
formFrom = PdfAcroForm.GetAcroForm(documentFrom, false);
}
if (documentTo != toPage.GetDocument()) {
documentTo = toPage.GetDocument();
formTo = PdfAcroForm.GetAcroForm(documentTo, true);
}
if (formFrom == null) {
return;
}
//duplicate AcroForm dictionary
IList<PdfName> excludedKeys = new List<PdfName>();
excludedKeys.Add(PdfName.Fields);
excludedKeys.Add(PdfName.DR);
PdfDictionary dict = formFrom.GetPdfObject().CopyTo(documentTo, excludedKeys, false);
formTo.GetPdfObject().MergeDifferent(dict);
IDictionary<String, PdfFormField> fieldsFrom = formFrom.GetFormFields();
if (fieldsFrom.Count <= 0) {
return;
}
IDictionary<String, PdfFormField> fieldsTo = formTo.GetFormFields();
IList<PdfAnnotation> annots = toPage.GetAnnotations();
foreach (PdfAnnotation annot in annots) {
if (!annot.GetSubtype().Equals(PdfName.Widget)) {
continue;
}
CopyField(toPage, fieldsFrom, fieldsTo, annot);
}
}
Specifically the line here.
excludedKeys.Add(PdfName.DR);
If you walk the the code in the CopyField() function eventually you will end in the PdfFormField class. You can see the constructor below.
public PdfFormField(PdfDictionary pdfObject)
: base(pdfObject) {
EnsureObjectIsAddedToDocument(pdfObject);
SetForbidRelease();
RetrieveStyles();
}
The function RetrieveStyles() will try to set the font for the field based on the default appearance. However that will not work. Due to the function below.
private PdfFont ResolveFontName(String fontName) {
PdfDictionary defaultResources = (PdfDictionary)GetAcroFormObject(PdfName.DR, PdfObject.DICTIONARY);
PdfDictionary defaultFontDic = defaultResources != null ? defaultResources.GetAsDictionary(PdfName.Font) :
null;
if (fontName != null && defaultFontDic != null) {
PdfDictionary daFontDict = defaultFontDic.GetAsDictionary(new PdfName(fontName));
if (daFontDict != null) {
return GetDocument().GetFont(daFontDict);
}
}
return null;
}
You see it is trying to see if the font exists in the default resources which was explicitly excluded in the PdfPageFormCopier class. It will never find the font.
So my solution was to create my own class that implements the IPdfPageExtraCopier interface. I copied the code from the PdfPageFormCopier class and removed the one line excluding the default resources. Then I use my own copier class in my code. Not the prettiest solution but it works.

File upload example for grapevine

I am new to Web API and REST services and looking to build a simple REST server which accepts file uploads. I found out grapevine which is simple and easy to understand. I couldn't find any file upload example?
This is an example using System.Web.Http
var streamProvider = new MultipartFormDataStreamProvider(ServerUploadFolder);
await Request.Content.ReadAsMultipartAsync(streamProvider);
but the grapevine Request property does not have any method to do that. Can someone point me to an example?
If you are trying to upload a file as a binary payload, see this question/answer on GitHub.
If you are trying to upload a file from a form submission, that will be a little bit trickier, as the multi-part payload parsers haven't been added yet, but it is still possible.
The following code sample is complete untested, and I just wrote this off the top of my head, so it might not be the best solution, but it's a starting point:
public static class RequestExtensions
{
public static IDictionary<string, string> ParseFormUrlEncoded(this IHttpRequest request)
{
var data = new Dictionary<string, string>();
foreach (var tuple in request.Payload.Split('='))
{
var parts = tuple.Split('&');
var key = Uri.UnescapeDataString(parts[0]);
var val = Uri.UnescapeDataString(parts[1]);
if (!data.ContainsKey(key)) data.Add(key, val);
}
return data;
}
public static IDictionary<string, FormElement> ParseFormData(this IHttpRequest request)
{
var data = new Dictionary<string, FormElement>();
var boundary = GetBoundary(request.Headers.Get("Content-Type"));
if (boundary == null) return data;
foreach (var part in request.Payload.Split(new[] { boundary }, StringSplitOptions.RemoveEmptyEntries))
{
var element = new FormElement(part);
if (!data.ContainsKey(element.Name)) data.Add(element.Name, element);
}
return data;
}
private static string GetBoundary(string contenttype)
{
if (string.IsNullOrWhiteSpace(contenttype)) return null;
return (from part in contenttype.Split(';', ',')
select part.TrimStart().TrimEnd().Split('=')
into parts
where parts[0].Equals("boundary", StringComparison.CurrentCultureIgnoreCase)
select parts[1]).FirstOrDefault();
}
}
public class FormElement
{
public string Name => _dispositionParams["name"];
public string FileName => _dispositionParams["filename"];
public Dictionary<string, string> Headers { get; private set; }
public string Value { get; }
private Dictionary<string, string> _dispositionParams;
public FormElement(string data)
{
var parts = data.Split(new [] { "\r\n\r\n", "\n\n" }, StringSplitOptions.None);
Value = parts[1];
ParseHeaders(parts[0]);
ParseParams(Headers["Content-Disposition"]);
}
private void ParseHeaders(string data)
{
Headers = data.TrimStart().TrimEnd().Split(new[] {"\r\n", "\n"}, StringSplitOptions.RemoveEmptyEntries).Select(header => header.Split(new[] {':'})).ToDictionary(parts => parts[0].TrimStart().TrimEnd(), parts => parts[1].TrimStart().TrimEnd());
}
private void ParseParams(string data)
{
_dispositionParams = new Dictionary<string, string>();
foreach (var part in data.Split(new[] {';'}))
{
if (part.IndexOf("=") == -1) continue;
var parts = part.Split(new[] {'='});
_dispositionParams.Add(parts[0].TrimStart(' '), parts[1].TrimEnd('"').TrimStart('"'));
}
}
}
If you are looking for something async to use immediately, you can try to implement the answer to this stackoverflow question, which has not been tested by me.

using existing SqlCe database in windows phone

I have a SqlCe database which i made for another project. Now i want to use it for a windows phone project. My database structure is
I copied my database into my project folder and set it's build action as "content" and copy to output directory as "copy always".
In my main page i used this:
private const string Con_String = #"isostore:/mydb.sdf";
public MainPage()
{
InitializeComponent();
IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication();
using (mTableDatabaseContext context = new mTableDatabaseContext(Con_String))
{
if (!context.DatabaseExists())
{
context.CreateDatabase();
}
if (!iso.FileExists("mydb.sdf"))
{
MoveReferenceDatabase();
}
}
}
public static void MoveReferenceDatabase()
{
IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication();
using (Stream input = Application.GetResourceStream(new Uri("mydb.sdf", UriKind.Relative)).Stream)
{
using (IsolatedStorageFileStream output = iso.CreateFile("mydb.sdf"))
{
byte[] readBuffer = new byte[4096];
int bytesRead = -1;
while ((bytesRead = input.Read(readBuffer, 0, readBuffer.Length)) > 0)
{
output.Write(readBuffer, 0, bytesRead);
}
}
}
}
and my mTableDatabaseContext class is like that:
public class mTableDatabaseContext:DataContext
{
public mTableDatabaseContext(string connectionString): base(connectionString)
{
}
public Table<dic> my_dics
{
get
{
return this.GetTable<dic>();
}
}
public Table<learn_table> my_learn_tables
{
get
{
return this.GetTable<learn_table>();
}
}
}
But i cant use my database and copy of my database cant be performed???
What can i do to do this??
How can i do this?? Can anyone help me??
You should use
private const string Con_String = #"Data Source=isostore:/mydb.sdf";
instead of
private const string Con_String = #"isostore:/mydb.sdf";

Get the Readable Message from ManagementObject.InvokeMethod

Is there any way to get the Message Text from the return value of WMI InvokeMethod e.g. for the following code
ManagementBaseObject outParam = nicMO.InvokeMethod("SetGateways", newGateway, null);
int result = outParam["ReturnValue"];
Microsoft has published return values
Is there anyway to get the readable message from the return values instead creating hardcoded return value and message dictionary.
note: Please give me something which can work in .net 2.0 (and/or .net 1.1)
You can get the description of the value returned by the SetGateWays method using the ValueMap and Value Qualifiers .
Try this sample
using System;
using System.Collections.Generic;
using System.Text;
using System.Management;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<String> LValues = new List<String>();
List<String> LValuesDesc = new List<String>();
Dictionary<String, String> LValuesDict = new Dictionary<String, String>();
ManagementClass WClass = new ManagementClass("Win32_NetworkAdapterConfiguration");
WClass.Options.UseAmendedQualifiers = true;
foreach (MethodData md in WClass.Methods)
{
if (md.Name.Equals("SetGateways"))
{
//fill a list with the ValuesMap
foreach (QualifierData q in md.Qualifiers)
{
if (q.Name.Equals("ValueMap"))
{
foreach (object Value in ((Array)q.Value))
{
LValues.Add(Convert.ToString(Value));
}
}
}
//fill a list with the Values
foreach (QualifierData q in md.Qualifiers)
{
if (q.Name.Equals("Values"))
{
foreach (object Value in ((Array)q.Value))
{
LValuesDesc.Add(Convert.ToString(Value));
}
}
}
//Merge both lists in a dictionary
for (int i = 0; i <= LValues.Count - 1; i++)
LValuesDict.Add(LValues[i], LValuesDesc[i]);
}
}
//Get the description of some return values
Console.WriteLine(LValuesDict["1"]);
Console.WriteLine(LValuesDict["64"]);
Console.WriteLine(LValuesDict["77"]);
Console.WriteLine(LValuesDict["91"]);
Console.ReadKey();
}
}
}

Encrypting and Decrypting Isolated Storage File

I want to encrypt and decrypt the isolated storage file.
The Microsoft site took me here
While using Isolated Storage on the emulator, it can persist only until the emulator is running.
There is no way to get the physical location of the Isolated Storage.
I hope the above statements of mine are correct.
Now, I want to know how can I encrypt the Isolated Storage file ?
Taking the example provided by Microsoft, (application name is GasMileage)
here is the code
namespace CodeBadger.GasMileage.Persistence
{
public class IsolatedStorageGateway
{
private const string StorageFile = "data.txt";
private readonly XmlSerializer _serializer;
public IsolatedStorageGateway()
{
_serializer = new XmlSerializer(typeof (Notebook));
}
public Notebook LoadNotebook()
{
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
{
using (var stream = GetStorageStreamForReading(store))
using (var reader = new StreamReader(stream))
{
return reader.EndOfStream
? new Notebook()
: (Notebook) _serializer.Deserialize(reader);
}
}
}
public NotebookEntry LoadEntry(Guid guid)
{
var notebook = LoadNotebook();
return notebook.Where(x => x.Id == guid).FirstOrDefault();
}
public void StoreEntry(NotebookEntry entry)
{
var notebook = LoadNotebook();
AssignId(entry);
RemoveExistingEntryFromNotebook(notebook, entry);
Console.WriteLine(entry);
notebook.Add(entry);
WriteNotebookToStorage(notebook);
}
public void DeleteEntry(NotebookEntry entry)
{
var notebook = LoadNotebook();
RemoveExistingEntryFromNotebook(notebook, entry);
WriteNotebookToStorage(notebook);
}
private void WriteNotebookToStorage(Notebook notebook)
{
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
using (var stream = GetStorageStreamForWriting(store))
{
_serializer.Serialize(stream, notebook);
}
}
private static void AssignId(NotebookEntry entry)
{
if (entry.Id == Guid.Empty) entry.Id = Guid.NewGuid();
}
private static void RemoveExistingEntryFromNotebook(Notebook notebook, NotebookEntry entry)
{
var toRemove = notebook.Where(x => x.Id == entry.Id).FirstOrDefault();
if (toRemove == null) return;
notebook.Remove(toRemove);
}
private static IsolatedStorageFileStream GetStorageStreamForWriting(IsolatedStorageFile store)
{
return new IsolatedStorageFileStream(StorageFile, FileMode.Create, FileAccess.Write, store);
}
private static IsolatedStorageFileStream GetStorageStreamForReading(IsolatedStorageFile store)
{
return new IsolatedStorageFileStream(StorageFile, FileMode.OpenOrCreate, FileAccess.Read, store);
}
}
Now I want to know, How to encrypt the data.txt given in the context.
On Application load, decrypt the file and on application termination, it should encrypt.
Can someone help me on this ?
The ProtectedData class will encrypt/decrypt a byte array for storing on isolated storage. You can supply your own additional entropy, but by default:
In Silverlight for Windows Phone, both the user and machine credentials are used to encrypt or decrypt data
For more information, see How to: Encrypt Data in a Windows Phone Application

Resources