    // main.cs SNF-SDK-WIN C# OEM Demonstration Code
    // Copyright (C) 2009 ARM Research Labs, LLC
    //
    // This app simply exercises the API provided by snfmultidll.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    using System.Collections;

    using System.Runtime.InteropServices;

    namespace SNFMultiDLLExampleCsharp
    {
        class SNFMultiDLLExample
        {

    #region DLL Imports
            // Location of SNFMulti.dll.
            const string SNFMULTI_DLL = "..\\..\\..\\64bitDll\\SNFMulti.dll";       // Set CPU type to "Any CPU"
            //const string SNFMULTI_DLL = "..\\..\\..\\..\\64bitDll\\SNFMulti.dll";   // Set CPU type to "x64
            //const string SNFMULTI_DLL = "..\\..\\..\\..\\32bitDll\\SNFMulti.dll";   // Set CPU type to "x86"

            // int setThrottle(int Threads);                                        /* Set scan thread limit. */
            [DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "setThrottle", CallingConvention = CallingConvention.Winapi)]
            public static extern int setThrottle(int throttle);

            // int startupSNF(char* Path);                                          /* Start SNF with configuration. */
            [DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "startupSNF", CallingConvention = CallingConvention.Winapi)]
            public static extern int startupSNF([MarshalAs(UnmanagedType.LPStr)] string Path);

            //  EXP int startupSNFAuthenticated(char* Path, char* Lic, char* Auth); /* Start SNF with conf & auth. */
            [DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "startupSNFAuthenticated",
                       CallingConvention = CallingConvention.Winapi)]
            public static extern int startupSNFAuthenticated(
                [MarshalAs(UnmanagedType.LPStr)] string Path,
                [MarshalAs(UnmanagedType.LPStr)] string Lic,
                [MarshalAs(UnmanagedType.LPStr)] string Auth);

            // int shutdownSNF();                                                   /* Shutdown SNF. */
            [DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "shutdownSNF", CallingConvention = CallingConvention.Winapi)]
            public static extern int shutdownSNF();

            // int testIP(unsigned long int IPToCheck);                             /* Test the IP for a GBUdb range. */
            [DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "testIP", CallingConvention = CallingConvention.Winapi)]
            public static extern int testIP(ulong IPToCheck);

            // double getIPReputation(unsigned long int IPToCheck);                 /* Get reputation figure for IP. */
            [DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "getIPReputation", CallingConvention = CallingConvention.Winapi)]
            public static extern double getIPReputation(ulong IPToCheck);

            // int scanBuffer(unsigned char* Bfr, int Length, char* Name, int Setup);/* Scan msgBuffer, name, setup time. */
            [DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "scanBuffer", CallingConvention = CallingConvention.Winapi)]
            public static extern int scanBuffer(
                [MarshalAs(UnmanagedType.LPStr)] string Bfr,
                int Length,
                [MarshalAs(UnmanagedType.LPStr)] string Name,
                int Setup);

            // int scanFile(char* FilePath, int Setup);                             /* Scan msgFile, setup time. */
            [DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "scanFile", CallingConvention = CallingConvention.Winapi)]
            public static extern int scanFile([MarshalAs(UnmanagedType.LPStr)] string Path, int Setup);

            // int getScanXHeaders(int ScanHandle, char** Bfr, int* Length);        /* Get result & XHeaders. */
            [DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "getScanXHeaders", CallingConvention = CallingConvention.Winapi)]
            public static extern int getScanXHeaders(int ScanHandle,
                out IntPtr Bfr,
                out int Length);

            // int getScanXMLLog(int ScanHandle, char** Bfr, int* Length);          /* Get result & XML Log. */
            [DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "getScanXMLLog", CallingConvention = CallingConvention.Winapi)]
            public static extern int getScanXMLLog(int ScanHandle,
                out IntPtr Bfr,
                out int Length);

            // int getScanClassicLog(int ScanHandle, char** Bfr, int* Length);      /* Get result & Classic Log. */
            [DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "getScanClassicLog", CallingConvention = CallingConvention.Winapi)]
            public static extern int getScanClassicLog(int ScanHandle,
                out IntPtr Bfr,
                out int Length);

            // int getScanResult(int ScanHandle);                                   /* Get just the scan result. */
            [DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "getScanResult", CallingConvention = CallingConvention.Winapi)]
            public static extern int getScanResult(int ScanHandle);

            // int closeScan(int ScanHandle);                                       /* Close the scan result. */
            [DllImport(SNFMULTI_DLL, CharSet = CharSet.Auto, EntryPoint = "closeScan", CallingConvention = CallingConvention.Winapi)]
            public static extern int closeScan(int ScanHandle);

    #endregion

            static void Main(string[] args)
            {
                //// Setup the basics we need to run this test.

                // const string LicenseID = "licensid";                             // SNF License ID can be passed
                // const string Authentication = "authenticationxx";                // directly or read from the
                                                                                    // configuration. OEMs go direct!
                const string ConfigurationPath = "..\\..\\snf_engine.xml";          // For "Any CPU"  platform.
                //const string ConfigurationPath = "..\\..\\..\\snf_engine.xml";      // For "x86" or "x64" platforms.

                const uint IPToTest = 0x0c22384e;                                   // Same as IP 12.34.56.78

                const string SampleMessage =
                    "Received: from mx-out.example.com [12.34.56.78] (HELO Somebody)\r\n" +
                    "  by mx-in.example.com (nosuchserver v1.0) for nobody@example.com\r\n" +
                    "From: <somebody@example.com>\r\n" +
                    "To: <nobody@example.com>\r\n" +
                    "Subject: Nothing to see here\r\n" +
                    "\r\n" +
                    "So this is the big thing that's not here to see.\r\n" +
                    "I thought it would be more interesting than this.\r\n" +
                    "\r\n" +
                    "_M\r\n" +
                    ".\r\n";

                //// Here is a simple example. Startup, exercise the API, shut down.
                //// Note that we're doing this in a very "C" style becuase the DLL API is C

                int Result = 0;

                Result = startupSNF(ConfigurationPath);

                //Result = startupSNFAuthenticated(
                //    ConfigurationPath,
                //    LicenseID,
                //    Authentication);

                System.Console.WriteLine("Started with config " + ConfigurationPath + " Result: " + Result);

                // IP tests can be done asynchrounously - they do not have to be part of any particular scan.

                Result = testIP(IPToTest);
                System.Console.WriteLine("IP test result: " + Result);

                double IPReputation = getIPReputation(IPToTest);
                System.Console.WriteLine("IP Reputation: " + IPReputation);

                // Messgae scans happen in a scan, read, close cycle as shown inside this loop.

                const int NumberOfScans = 10;
                for(int i = 0; i < NumberOfScans; i++) {

                    // Show how the IP reputation changes over time.

                    IPReputation = getIPReputation(IPToTest);
                    System.Console.WriteLine("IP Reputation: " + IPReputation);

                    // Scan a message from a buffer.

                    int SetupTime = 12;
                    int ScanHandle = 0;
                    ScanHandle = scanBuffer(SampleMessage, SampleMessage.Length, "TestMessage", SetupTime);

                    System.Console.WriteLine("Scan Handle: " + ScanHandle);

                    // Retrieve the X-Headers for the scan.

                    IntPtr XHeadersPtr = IntPtr.Zero;
                    int XHeadersLength = 0;
                    int ScanResult = 0;
                    ScanResult = getScanXHeaders(ScanHandle, out XHeadersPtr, out XHeadersLength);
                    string XHeaders;
                    XHeaders = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(XHeadersPtr, XHeadersLength);

                    // Close the scan.

                    Result = closeScan(ScanHandle);

                    System.Console.WriteLine("Scan Close Result: " + Result);

                    // X- headers were captured in a string BEFORE closing the scan so we can
                    // use them here.

                    System.Console.WriteLine("Scan result code: " + ScanResult);
                    System.Console.WriteLine("Scan X- headers: " + XHeaders);

                }

                // Now that all scanning is done we shut down.

                Result = shutdownSNF();

            }
        }
    }