Save Mail in MIME format (*.eml) in Outlook Add-In - c#

I want to write a little Outlook addin (C#), which saves a selected mail (MailItem) to disk in plain MIME format (.eml).
The MailItem.SaveAs() method only allows to save in .msg format.
Is there any other (simple) way, to save the mail in eml-format? I want to keep all details of the original mail.
I've read something about the Outlook WebServices. Maybe I can search the exchange server for the currently in outlook selected mail and receive it again from exchange and save it as .eml? What will I need for this option?
Is it possible to convert a saved .msg to .eml in an easy way (with keeping all details, headers and so on)?
I hope someone can help me with this problem, because I have spent a couple of hours on searching for a solution without any result.

Here's an IConvertSession proxy for C#:
using Microsoft.Office.Interop.Outlook;
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace Exchange.Export.MAPIMessageConverter
{
internal class MAPIMethods
{
[Flags]
public enum MAPITOMIMEFLAGS
{
CCSF_SMTP = 0x0002,
CCSF_NOHEADERS = 0x0004,
CCSF_USE_TNEF = 0x0010,
CCSF_INCLUDE_BCC = 0x0020,
CCSF_8BITHEADERS = 0x0040,
CCSF_USE_RTF = 0x0080,
CCSF_PLAIN_TEXT_ONLY = 0x1000,
CCSF_NO_MSGID = 0x4000,
}
[Flags]
public enum CLSCTX
{
CLSCTX_INPROC_SERVER = 0x1,
CLSCTX_INPROC_HANDLER = 0x2,
CLSCTX_LOCAL_SERVER = 0x4,
CLSCTX_REMOTE_SERVER = 0x10,
CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,
CLSCTX_ALL = CLSCTX_SERVER | CLSCTX_INPROC_HANDLER
}
public static Guid CLSID_IConverterSession = new Guid("{4e3a7680-b77a-11d0-9da5-00c04fd65685}");
public static Guid IID_IConverterSession = new Guid("{4b401570-b77b-11d0-9da5-00c04fd65685}");
public enum ENCODINGTYPE
{
IET_BINARY = 0,
IET_BASE64 = 1,
IET_UUENCODE = 2,
IET_QP = 3,
IET_7BIT = 4,
IET_8BIT = 5,
IET_INETCSET = 6,
IET_UNICODE = 7,
IET_RFC1522 = 8,
IET_ENCODED = 9,
IET_CURRENT = 10,
IET_UNKNOWN = 11,
IET_BINHEX40 = 12,
IET_LAST = 13
}
public enum MIMESAVETYPE
{
SAVE_RFC822 = 0,
SAVE_RFC1521 = 1
}
[ComVisible(false)]
[ComImport()]
[Guid("00020307-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IMessage
{
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("4b401570-b77b-11d0-9da5-00c04fd65685")]
public interface IConverterSession
{
[PreserveSig]
int Placeholder0();
[PreserveSig]
uint SetEncoding(
[In, MarshalAs(UnmanagedType.I4)] ENCODINGTYPE DispId
);
[PreserveSig]
int Placeholder1();
[PreserveSig]
uint MIMEToMAPI(
[In, MarshalAs(UnmanagedType.Interface)]
Stream pstm,
[Out, MarshalAs(UnmanagedType.Interface)]
MailItem pmsg,
object pszSrcSrv,
uint ulFlags
);
[PreserveSig]
uint MAPIToMIMEStm(
[In, MarshalAs(UnmanagedType.Interface)]
IMessage pmsg,
[Out, MarshalAs(UnmanagedType.Interface)]
IStream pstm,
MAPITOMIMEFLAGS ulFlags
);
[PreserveSig]
int Placeholder2();
[PreserveSig]
int Placeholder3();
[PreserveSig]
int Placeholder4();
[PreserveSig]
int SetTextWrapping(
bool fWrapText,
uint ulWrapWidth
);
[PreserveSig]
uint SetSaveFormat(
[In, MarshalAs(UnmanagedType.I4)]
MIMESAVETYPE mstSaveFormat
);
[PreserveSig]
int Placeholder5();
[PreserveSig]
int Placeholder6();
}
}
}
Using it:
private Stream GetEmlStream(Outlook.MailItem mail)
{
Type converter = Type.GetTypeFromCLSID(MAPIMethods.CLSID_IConverterSession);
object obj = Activator.CreateInstance(converter);
MAPIMethods.IConverterSession session = (MAPIMethods.IConverterSession)obj;
if (session != null)
{
uint hr = session.SetEncoding(MAPIMethods.ENCODINGTYPE.IET_QP);
hr = session.SetSaveFormat(MAPIMethods.MIMESAVETYPE.SAVE_RFC822);
var stream = new ComMemoryStream();
hr = session.MAPIToMIMEStm((MAPIMethods.IMessage)mail.MAPIOBJECT, stream, MAPIMethods.MAPITOMIMEFLAGS.CCSF_SMTP);
if (hr != 0)
throw new ArgumentException(There are some invalid COM arguments");
stream.Position = 0;
return stream;
}
return null;
}
ComMemoryStream: https://stackoverflow.com/a/6602066/2532356
Other fonts:
http://www.pcreview.co.uk/threads/iconvertersession-in-c.3716714/
http://www.microsoft-questions.com/microsoft/Plaform-SDK-Mapi/31018989/mimetomapi-and-mapitomimestm-method-take-a-pointer-to-an-imessage-extended.aspx

You can either
Create MIME file explicitly in your code one property at a time. You can also use existing MIME converters (I used Lumisoft in the past) - but they won't convert Outlook messages in a single call; you will need to expliiclty build all the headers and MIME parts.
Use IConverterSession object (C++ or Delphi only) - this is the same MIME converter used by Outlook. You can play with it in OutlookSpy (I am its author) - click IConverterSession button. Note that as of Outlook 2016, IConverterSession interface can be used only if running inside the outlook.exe address space (COM addin). You cannot create an instance of that interface when running in a separate process.
Use Redemption (I am also its author) and its RDOMail.SaveAs or SafeMailItem.SaveAs methods - it can save in the MIME format (olRfc822) along with a dozen or so other formats. It uses IConverterSession object when it is available (Outlook 2003 and up) or its own converter otherwise. The following script (VBS) will save the currently selected message in Outlook as an EML file
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set rItem = Session.GetMessageFromID(Application.ActiveExplorer.Selection(1).EntryID)
rItem.SaveAs "c:\temp\test.eml", 1024`

Related

Is it possible to send Toast notification from console application?

Is it possible to send Toast notifications from console application using ToastNotificationManager ?
I know that it is possible to send Toast notifications from Windows Universal app:
var toast = new ToastNotification(doc);
ToastNotificationManager.CreateToastNotifier().Show(toast);
*doc - Toast stored in XML string
To use ToastNotificaionManager I need Windows.UI.Notifications library which I can't reference in console application project.
The library I mentionet before is actualy used by WinRT. Is it possible to use WinRT APIs in Windows console application ?
At first you need to declare that your program will be using winRT libraries:
Right-click on your yourProject, select Unload Project
Right-click on your yourProject(unavailable) and click Edit yourProject.csproj
Add a new property group:<targetplatformversion>8.0</targetplatformversion>
Reload project
Add reference Windows from Windows > Core
Now you need to add this code:
using Windows.UI.Notifications;
and you will be able to send notifications using this code:
var toast = new ToastNotification(doc);
ToastNotificationManager.CreateToastNotifier().Show(toast);
Reference: How to call WinRT APIs in Windows 8 from C# Desktop Applications - WinRT Diagram
I ran into some problems here with Evaldas B's Code I was missing a string.
(Where It Says Need String Here)
.CreateToastNotifier(<needed a string here>).Show(toast);
warning I am kind of new to C# so my code probably sucks- but it does work and is pretty simplistic and that's more than I can say for most solutions I have found
Also I was having a hell of a time getting the xml document to read. I was fighting with System.xml (I think) and Windows.Data.Dom.Xml (also not completely sure).
In the end I settled on making them hard coded strings for my example file and used a switch statement to switch between them.
I have found a ton of people, looking for the solution that I have come up with, on stack overflow. It seems use of the toast notification system with console or background applications would be super useful, and the documentation that surrounds the toast notification system with windows applications all suggest that it needs to be used with an application. The Action Center is super useful for notifications vrs the NotificationTray/NotifyIcon route. I have not found a full solution anywhere else on the web. Here is example code.
/*
At first you need to declare that your program will be using winRT libraries:
1. Right click on your yourProject, select Unload Project
2. Right click on your youProject(unavailable) and click Edit yourProject.csproj
3. Add a new property group:<TargetPlatformVersion>8.0</TargetPlatformVersion>
4. Reload project
5. Add referece Windows from Windows > Core
*/
using System;
using Windows.Data.Xml.Dom;
using Windows.Storage;
using Windows.Storage.Streams;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Notifications;
namespace ConsoleApplication6
{
public class NewToastNotification
{
public NewToastNotification(string input, int type)
{
string NotificationTextThing = input;
string Toast = "";
switch (type)
{
case 1:
{
//Basic Toast
Toast = "<toast><visual><binding template=\"ToastImageAndText01\"><text id = \"1\" >";
Toast += NotificationTextThing;
Toast += "</text></binding></visual></toast>";
break;
}
default:
{
Toast = "<toast><visual><binding template=\"ToastImageAndText01\"><text id = \"1\" >";
Toast += "Default Text String";
Toast += "</text></binding></visual></toast>";
break;
}
}
XmlDocument tileXml = new XmlDocument();
tileXml.LoadXml(Toast);
var toast = new ToastNotification(tileXml);
ToastNotificationManager.CreateToastNotifier("New Toast Thing").Show(toast);
}
}
class Program
{
static void Main(string[] args)
{
NewToastNotification Window = new NewToastNotification("Yes",1);
}
}
}
1) For a toast notification to appear using a console or Desktop application, your application must have a shortcut on the start menu.
2) For an application to have a shortcut icon(not tile icon) in the start menu of Windows, your app must have an AppId.
To create a short cut for you you application create a new class named ShellHelpers.cs and Paste this code in it.
using System;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.WindowsAPICodePack.Shell.PropertySystem;
using MS.WindowsAPICodePack.Internal;
namespace DesktopToastsSample.ShellHelpers
{
internal enum STGM : long
{
STGM_READ = 0x00000000L,
STGM_WRITE = 0x00000001L,
STGM_READWRITE = 0x00000002L,
STGM_SHARE_DENY_NONE = 0x00000040L,
STGM_SHARE_DENY_READ = 0x00000030L,
STGM_SHARE_DENY_WRITE = 0x00000020L,
STGM_SHARE_EXCLUSIVE = 0x00000010L,
STGM_PRIORITY = 0x00040000L,
STGM_CREATE = 0x00001000L,
STGM_CONVERT = 0x00020000L,
STGM_FAILIFTHERE = 0x00000000L,
STGM_DIRECT = 0x00000000L,
STGM_TRANSACTED = 0x00010000L,
STGM_NOSCRATCH = 0x00100000L,
STGM_NOSNAPSHOT = 0x00200000L,
STGM_SIMPLE = 0x08000000L,
STGM_DIRECT_SWMR = 0x00400000L,
STGM_DELETEONRELEASE = 0x04000000L,
}
internal static class ShellIIDGuid
{
internal const string IShellLinkW = "000214F9-0000-0000-C000-000000000046";
internal const string CShellLink = "00021401-0000-0000-C000-000000000046";
internal const string IPersistFile = "0000010b-0000-0000-C000-000000000046";
internal const string IPropertyStore = "886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99";
}
[ComImport,
Guid(ShellIIDGuid.IShellLinkW),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IShellLinkW
{
UInt32 GetPath(
[Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
int cchMaxPath,
//ref _WIN32_FIND_DATAW pfd,
IntPtr pfd,
uint fFlags);
UInt32 GetIDList(out IntPtr ppidl);
UInt32 SetIDList(IntPtr pidl);
UInt32 GetDescription(
[Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,
int cchMaxName);
UInt32 SetDescription(
[MarshalAs(UnmanagedType.LPWStr)] string pszName);
UInt32 GetWorkingDirectory(
[Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,
int cchMaxPath
);
UInt32 SetWorkingDirectory(
[MarshalAs(UnmanagedType.LPWStr)] string pszDir);
UInt32 GetArguments(
[Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,
int cchMaxPath);
UInt32 SetArguments(
[MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
UInt32 GetHotKey(out short wHotKey);
UInt32 SetHotKey(short wHotKey);
UInt32 GetShowCmd(out uint iShowCmd);
UInt32 SetShowCmd(uint iShowCmd);
UInt32 GetIconLocation(
[Out(), MarshalAs(UnmanagedType.LPWStr)] out StringBuilder pszIconPath,
int cchIconPath,
out int iIcon);
UInt32 SetIconLocation(
[MarshalAs(UnmanagedType.LPWStr)] string pszIconPath,
int iIcon);
UInt32 SetRelativePath(
[MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,
uint dwReserved);
UInt32 Resolve(IntPtr hwnd, uint fFlags);
UInt32 SetPath(
[MarshalAs(UnmanagedType.LPWStr)] string pszFile);
}
[ComImport,
Guid(ShellIIDGuid.IPersistFile),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IPersistFile
{
UInt32 GetCurFile(
[Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile
);
UInt32 IsDirty();
UInt32 Load(
[MarshalAs(UnmanagedType.LPWStr)] string pszFileName,
[MarshalAs(UnmanagedType.U4)] STGM dwMode);
UInt32 Save(
[MarshalAs(UnmanagedType.LPWStr)] string pszFileName,
bool fRemember);
UInt32 SaveCompleted(
[MarshalAs(UnmanagedType.LPWStr)] string pszFileName);
}
[ComImport]
[Guid(ShellIIDGuid.IPropertyStore)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IPropertyStore
{
UInt32 GetCount([Out] out uint propertyCount);
UInt32 GetAt([In] uint propertyIndex, out PropertyKey key);
UInt32 GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
UInt32 SetValue([In] ref PropertyKey key, [In] PropVariant pv);
UInt32 Commit();
}
[ComImport,
Guid(ShellIIDGuid.CShellLink),
ClassInterface(ClassInterfaceType.None)]
internal class CShellLink { }
public static class ErrorHelper
{
public static void VerifySucceeded(UInt32 hresult)
{
if (hresult > 1)
{
throw new Exception("Failed with HRESULT: " + hresult.ToString("X"));
}
}
}
}
Code for creating a shortcut(This code can be added to the same class where you will be showing the toast)
public bool TryCreateShortcut()
{
String shortcutPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Microsoft\\Windows\\Start Menu\\Programs\\FixSus Toasts Sample .lnk";
if (!File.Exists(shortcutPath))
{
InstallShortcut(shortcutPath);
return true;
}
return false;
}
private void InstallShortcut(String shortcutPath)
{
// Find the path to the current executable
String exePath = Process.GetCurrentProcess().MainModule.FileName;
IShellLinkW newShortcut = (IShellLinkW)new CShellLink();
// Create a shortcut to the exe
DesktopToastsSample.ShellHelpers.ErrorHelper.VerifySucceeded(newShortcut.SetPath(exePath));
DesktopToastsSample.ShellHelpers.ErrorHelper.VerifySucceeded(newShortcut.SetArguments(""));
// Open the shortcut property store, set the AppUserModelId property
IPropertyStore newShortcutProperties = (IPropertyStore)newShortcut;
using (PropVariant appId = new PropVariant(APP_ID))
{
DesktopToastsSample.ShellHelpers.ErrorHelper.VerifySucceeded(newShortcutProperties.SetValue(SystemProperties.System.AppUserModel.ID, appId));
DesktopToastsSample.ShellHelpers.ErrorHelper.VerifySucceeded(newShortcutProperties.Commit());
}
// Commit the shortcut to disk
IPersistFile newShortcutSave = (IPersistFile)newShortcut;
DesktopToastsSample.ShellHelpers.ErrorHelper.VerifySucceeded(newShortcutSave.Save(shortcutPath, true));
}
Now you can create an show a toast
// Get a toast XML template
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastImageAndText04);
// Fill in the text elements
XmlNodeList stringElements = toastXml.GetElementsByTagName("text");
stringElements[1].AppendChild(toastXml.CreateTextNode("Message" + newMessage));
// Specify the absolute path to an image
string codeWebFolderPath = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, #"..\..\"));
String imagePath = "file:///" + Path.GetFullPath(codeWebFolderPath+ "Resources\\FixSus.png");
XmlNodeList imageElements = toastXml.GetElementsByTagName("image");
imageElements[0].Attributes.GetNamedItem("src").NodeValue = imagePath;
// Create the toast and attach event listeners
ToastNotification toast = new ToastNotification(toastXml);
toast.Activated += ToastActivated;
toast.Dismissed += ToastDismissed;
toast.Failed += ToastFailed;
// Show the toast. Be sure to specify the AppUserModelId on your application's shortcut!
ToastNotificationManager.CreateToastNotifier(APP_ID).Show(toast);
The APP_ID can be any string. In my case it was "NotificationTest.KEY"
Note: Dont modify the ShellHelper class.
Edit : Follow Evaldas B's answer first then apply this solution.

Intellisense/documentation of WIA constants and values

Looking at the WIA driver documentation for the WIA_IPS_DOCUMENT_HANDLING_SELECT property, the valid values are listed as:
BACK_FIRST
BACK_ONLY
DUPLEX
FRONT_FIRST
FRONT_ONLY
Just the names, no values.
The documentation of the properties from the application developer's perspective (WIA_IPS_DOCUMENT_HANDLING_SELECT looks the same.
If I want to write the following code, using WIA Automation and VB.NET (could just as easily be in C#):
Dim manager = New DeviceManager
Dim deviceinfo = manager.DeviceInfos.Cast(Of DeviceInfo).First() 'Assuming there is an available device
Dim device = deviceinfo.Connect
device.Properties(WIA_IPS_DOCUMENT_HANDLING_SELECT).Value = FRONT_FIRST
I cannot do so, because these constants are not available from the WIA Automation layer, and therefore not available from Intellisense.
I can define specific constants that I need, or use magic numbers when I know them:
device.Properties(3088).Value = ???
How can I get these constants in Intellisense without defining them myself, or where is there documentation for the values of these constants?
You mean like this?
Public Class Const_WIA
Public Const WIA_RESERVED_FOR_NEW_PROPS As UInt32 = 1024
Public Const WIA_DIP_FIRST As UInt32 = 2
Public Const WIA_DPA_FIRST As UInt32 = WIA_DIP_FIRST + WIA_RESERVED_FOR_NEW_PROPS
Public Const WIA_DPC_FIRST As UInt32 = WIA_DPA_FIRST + WIA_RESERVED_FOR_NEW_PROPS '
' //
' // Scanner only device properties (DPS)
' //
Public Const WIA_DPS_FIRST As UInt32 = WIA_DPC_FIRST + WIA_RESERVED_FOR_NEW_PROPS
Public Const WIA_DPS_DOCUMENT_HANDLING_STATUS As UInt32 = WIA_DPS_FIRST + 13
Public Const WIA_DPS_DOCUMENT_HANDLING_SELECT As UInt32 = WIA_DPS_FIRST + 14
End Class
here's a list with matching values

Accessing the X509Store in Silverlight

I'm currently developing a Silverlight app in order to access the X509Store to sign data with a private key embedded into a USB Security Token.
I started from a C# application that works this way :
public byte[] SignData(byte[] HashTosign, string Cert_To_Use_b64)
{
byte[] Signature = null;
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
store.Close();
try {
foreach (X509Certificate2 Certificate in collection) {
if (ToBase64(Certificate.RawData) == Cert_To_Use_b64) {
RSACryptoServiceProvider Rsa = new RSACryptoServiceProvider();
Rsa = (RSACryptoServiceProvider)Certificate.PrivateKey;
try {
RSACryptoServiceProvider aesRsa = new RSACryptoServiceProvider();
string strPk = Certificate.PrivateKey.ToXmlString(true);
aesRsa.FromXmlString(strPk);
Signature = aesRsa.SignHash(HashTosign, CryptoConfig.MapNameToOID("SHA256"));
} catch (Exception ex) {
Throw new exception("FAILURE : " + ex.Message());
}
lgSignature = Signature.Length;
return 0;
}
}
} catch (CryptographicException ex) {
Throw new exception("FAILURE : " + ex.Message());
} catch (Exception ex) {
Throw new exception("FAILURE : " + ex.Message());
}
}
That method works great in a C# application. But when I try to adapt it to Silverlight, the X509Store doesn't seem to be implemented.
The name “X509Store” does not exist in the namespace System.Security.Cryptography. Are you missing an assembly reference?
I tried to apply a .NET Framework DLL but I got the following error :
It is not possible to add a reference to System.Security.dll because it was not created with the Silverlight runtime. Silverlight projects only work with Silverlight assemblies.
Can I recreate the System.Security.dll assembly to Silverlight ? Or is there a better means to do what I want to do ?
Thanks in advance.
There are two possible ways to do what you want:
CryptoAPI via P/Invoke
My fist guess was to use native Windows library crypt32.dll (commonly known as CryptoApi). After all System.Security.dll is just a managed wrapper around it (browsing decompiled source with tool like ILSpy will show you how MS is wrapping it). You can use it in Silverlight with P/Invoke when running in elevated trust (Properties -> Silverlight -> Require elevated trust) and with administrator rights (to be able to open certificate store). However there are couple of drawbacks:
It is rather unfriendly (brings me back old good C/C++ days)
You need to operate on low level system structures and operations (like pointers)
You will need to use this style for both certificate retrieval and signature computing
Documentation reference:
MSDN CryptoApi
This way I managed to acquire handle (IntPtr pointer) to certificate enrolled on my smart card:
using System;
using System.Runtime.InteropServices;
namespace SilverlightX509Store
{
public static class CapiNative
{
public const string MY = "MY";
public const uint PKCS_7_ASN_ENCODING = 0x00010000;
public const uint X509_ASN_ENCODING = 0x00000001;
public const uint CERT_FIND_SUBJECT_STR = 0x00080007;
public const int ACCESS_DENIED = 5;
[DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CertOpenSystemStore(
IntPtr hCryptProv,
string storename);
[DllImport("crypt32.dll", SetLastError = true)]
public static extern IntPtr CertFindCertificateInStore(
IntPtr hCertStore,
uint dwCertEncodingType,
uint dwFindFlags,
uint dwFindType,
[In, MarshalAs(UnmanagedType.LPWStr)]String pszFindString,
IntPtr pPrevCertCntxt);
}
public class CapiWrapper
{
public IntPtr FindCert(string subject)
{
IntPtr storeHandle = CapiNative.CertOpenSystemStore(
IntPtr.Zero,
CapiNative.MY);
if (Marshal.GetLastWin32Error() == CapiNative.ACCESS_DENIED)
{
return IntPtr.Zero;
}
IntPtr certHandle = CapiNative.CertFindCertificateInStore(
storeHandle,
CapiNative.PKCS_7_ASN_ENCODING | CapiNative.X509_ASN_ENCODING,
0,
CapiNative.CERT_FIND_SUBJECT_STR,
"subject to find",
IntPtr.Zero);
return certHandle;
}
}
}
Converting .NET dll to Silverlight compliant
There seems to be a way to convert .NET library into SL. See article Reusing .NET Assemblies in Silverlight.
I haven't tested it yet. Potential issue might be that .NET security end encryption is built in deep into mscorlib and System.Security and it might not be so easy to convert those libraries (or even not possible at all).

Enable a deskband (windows toolbar) programatically

I am trying to programtically enable a deskband that I wrote using this from code project. The deskband works fine, and I have corrected the problem with the IStream interface that prevents the toolbar from saving it's state. But I can't figure out how to "turn it on" via code.
I have been trying to get the solution in this question, but I'm not sure I am doing it correctly.
I tried taking the code from that question:
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("4CF504B0-DE96-11D0-8B3F-00A0C911E8E5")]
public interface IBandSite
{
[PreserveSig]
uint AddBand([In, MarshalAs(UnmanagedType.IUnknown)] Object pUnkSite);
[PreserveSig]
void RemoveBand(uint dwBandID);
}
private uint AddDeskbandToTray(Guid Deskband)
{
Guid IUnknown = new Guid("{00000000-0000-0000-C000-000000000046}");
Guid ITrayBand = new Guid("{F60AD0A0-E5E1-45cb-B51A-E15B9F8B2934}");
Type TrayBandSiteService = Type.GetTypeFromCLSID(ITrayBand, true);
IBandSite BandSite = Activator.CreateInstance(TrayBandSiteService) as IBandSite;
object DeskbandObject = CoCreateInstance(Deskband, null, CLSCTX.CLSCTX_INPROC_SERVER, IUnknown);
return BandSite.AddBand(DeskbandObject);
}
But couldn't find how to call "CoCreateInstance" or what "usings" I should use. I had a look on pinvoke.net, and tried adding the following interface and enum:
[DllImport("ole32.dll", ExactSpelling = true, PreserveSig = false)]
[return: MarshalAs(UnmanagedType.Interface)]
static extern object CoCreateInstance(
[In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
[MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter,
CLSCTX dwClsContext,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid);
[Flags]
enum CLSCTX : uint
{
CLSCTX_INPROC_SERVER = 0x1,
CLSCTX_INPROC_HANDLER = 0x2,
CLSCTX_LOCAL_SERVER = 0x4,
CLSCTX_INPROC_SERVER16 = 0x8,
CLSCTX_REMOTE_SERVER = 0x10,
CLSCTX_INPROC_HANDLER16 = 0x20,
CLSCTX_RESERVED1 = 0x40,
CLSCTX_RESERVED2 = 0x80,
CLSCTX_RESERVED3 = 0x100,
CLSCTX_RESERVED4 = 0x200,
CLSCTX_NO_CODE_DOWNLOAD = 0x400,
CLSCTX_RESERVED5 = 0x800,
CLSCTX_NO_CUSTOM_MARSHAL = 0x1000,
CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000,
CLSCTX_NO_FAILURE_LOG = 0x4000,
CLSCTX_DISABLE_AAA = 0x8000,
CLSCTX_ENABLE_AAA = 0x10000,
CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000,
CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,
CLSCTX_ALL = CLSCTX_SERVER | CLSCTX_INPROC_HANDLER
}
...which makes the code build properly, but when I call the AddDeskBandToTray method with the guid of my toolbar, nothing happens.
Environment: XP SP3 with IE7 on vmware, .net 3.5
Up until now I've only ever done c# in a asp.net situation, so I'm a bit new to all this shell stuff. Can someone please point me in the right direction?

How to find available COM ports?

How to find available COM ports in my PC? I am using framework v1.1. Is it possible to find all COM ports? If possible, help me solve the problem.
Framework v1.1 AFAIK doesn't allow you to do this.
In 2.0 there is a static function
SerialPort.GetPortNames()
http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.getportnames.aspx
As others suggested, you can use WMI. You can find a sample in CodeProject
try
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\WMI",
"SELECT * FROM MSSerial_PortName");
foreach (ManagementObject queryObj in searcher.Get())
{
Console.WriteLine("-----------------------------------");
Console.WriteLine("MSSerial_PortName instance");
Console.WriteLine("-----------------------------------");
Console.WriteLine("InstanceName: {0}", queryObj["InstanceName"]);
Console.WriteLine("-----------------------------------");
Console.WriteLine("MSSerial_PortName instance");
Console.WriteLine("-----------------------------------");
Console.WriteLine("PortName: {0}", queryObj["PortName"]);
//If the serial port's instance name contains USB
//it must be a USB to serial device
if (queryObj["InstanceName"].ToString().Contains("USB"))
{
Console.WriteLine(queryObj["PortName"] + "
is a USB to SERIAL adapter/converter");
}
}
}
catch (ManagementException e)
{
Console.WriteLine("An error occurred while querying for WMI data: " + e.Message);
}
The available serial ports can also be found at the values at the HKEY_LOCAL_MACHINE\hardware\devicemap\serialcomm key in the registry.
How about asking a straight question from operating system:
using System;
using System.Collections.Generic;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
public class MyClass
{
private const uint GENERIC_ALL = 0x10000000;
private const uint GENERIC_READ = 0x80000000;
private const uint GENERIC_WRITE = 0x40000000;
private const uint GENERIC_EXECUTE = 0x20000000;
private const int OPEN_EXISTING = 3;
public const int INVALID_HANDLE_VALUE = -1;
public static void Main()
{
for (int i = 1; i <= 32; i++)
Console.WriteLine ("Port {0}: {1}", i, PortExists (i));
}
private static bool PortExists (int number) {
SafeFileHandle h = CreateFile (#"\\.\COM" + number.ToString (), GENERIC_READ + GENERIC_WRITE,
0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
bool portExists = !h.IsInvalid;
if (portExists)
h.Close ();
return portExists;
}
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern SafeFileHandle CreateFile (string lpFileName, System.UInt32 dwDesiredAccess,
System.UInt32 dwShareMode, IntPtr pSecurityAttributes, System.UInt32 dwCreationDisposition,
System.UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile);
}
WMI contains a lot of hardware information. Query for instances of Win32_SerialPort.
(OTOH I can't recall how much WMI query support was in .NET 1.1.)
There is no support for SerialPort communication in .net v1.1. The most common solution for this was to use the MSCOMMCTL active X control from a VB6.0 installation (import into your .net project as a COM component from the add reference dialog box).
In later versions the Serial Port support is available through the System.IO.Ports name space. Also please note there is no API which will get you the list of free ports.
You can get a list of all the port names and then try opening a connection. An exception occurs if the port is already in use.
Since you are using .net 1.1 one option is to use the AxMSCommLib control.
Here is a web page that assisted me in starting to use AxMSCommLib control. There is even a FindDevicePort() method listed that can be easily modified.
I have since switched to System.IO.Ports which appears to be much more robust.
http://www.devhood.com/tutorials/tutorial_details.aspx?tutorial_id=320
Thanks
Joe
Use QueryDosDevice API function. This is a VB6 snippet:
ReDim vRet(0 To 255)
sBuffer = String(100000, 1)
Call QueryDosDevice(0, sBuffer, Len(sBuffer))
sBuffer = Chr$(0) & sBuffer
For lIdx = 1 To 255
If InStr(1, sBuffer, Chr$(0) & "COM" & lIdx & Chr$(0), vbTextCompare) > 0 Then
vRet(lCount) = "COM" & lIdx
lCount = lCount + 1
End If
Next
Maybe you will find this useful?
I am showing you a simple way to check all the COM ports in you PC. To get started follow these steps:
Create a WinForms application in Visual Studio.
Darg and drop a comboBox in your form and name it comboBoxCOMPORT
Copy the following code and paste after the public Form1() method (autogenerated).
private void Form1_Load(object sender, EventArgs e)
{
string[] ports = SerialPort.GetPortNames();
comboBoxCOMPORT.Items.AddRange(ports);
}
Run the app and click on drop down arrow on the comboBox to reveal all the available COM PORTS.
The above method works for Edgeport USB-to-serial converters as well as virtual ports. I implemented this in my project and works smoothly. Let me know if I can provide any further assistance.

Categories