Creating an MMC Snapin Using C# (Part I)



Click here for a larger image.

Environment: C#, WinNT/Win 2k

Introduction

The article/code snippet helps you create an MMC Snapin by using C#.

Background

The framework for building management consoles for Windows NT/2000 is developed by Jim. Jim is the author for ironringsoftware.com. In our article, we will use this framework to derive the UI for the management console. Detailed steps for generating the snapin console are explained below.

Using the Code

Here are the steps to use the MMC library created by the author at ironringsoftware.com to create management consoles for Windows NT/2000.

Step 1: Downloading the framework

You need to download the latest source of MMC Snapin Framework  from ironringsoftware.com.

The zip file downloaded contains three projects:

  • First, the <MMCFormsShim> that is the implementation of the framework in C++.
  • Second, <MCLib> that mainly is the Runtime Callable Wrapper (RCW) for the underlying C++ code and also contains the implementation for the Snapin objects such as nodes, menus, and so forth, with features such as event handlers defined.
  • Finally, <MCTest> is the project that shows the usage of the framework to generate an MMC Snapin.

Step 2: How to view the sample Snapin provided

  • Set <MMCTest> project as the startup project.
  • When executing the project, it displays Micorost Management Console.
  • Click on menu Console -> Add/Remove Snap-in.
  • Click the Add button.
  • Select "MMC Library Test Snapin" and click the Add button and then the Close button.
  • Finally, you shall be viewing the Snapin sample in your Console.

Step 3: Initial setup

  • Create a "C:\FileActDemo" directory with few sample files and sub directories in it.
  • View the properties of the <MMCTest> project. Set the value for the "Working Directory" property under the "Configuration Properties -> Debugging" section appropriately.
  • Open the <dlldatax.c> file in the <MMCFormsShim> project and replace the value for "#define _WIN32_WINNT" from "0x0400" to the appropriate value; for example, "0x0586".

Step 4: How to create new nodes in the Snapin

Let us take an example of creating a node that contains all the directory information on the left pane and the file information in the result pane.

  • Open the <BaseNode.cs> file in the <MMCLib> project and add a new protected class variable, as shown in the code below.
  • //This is the variable that holds the data passed from the
    //framework.
    protected Hashtable m_Properties;
    
  • Initialize the variable in the constructor of the class, as shown in the code below:
  • m_Properties = new Hashtable();
  • This is the public property used to pass the values from the framework to the form. Add a public property for the class to access the protected variable just defined, as shown in the code below.
  • public Hashtable Properties {
      get { return m_Properties; }
      set { m_Properties = value; }
    }
    
  • Add a new .cs file into the <MMCLib> project and name it <DirectoryNode.cs>. Replace the code of the class file with the code below.
  • //
    //Code block for DirectoryNode.cs
    //
    using System;
    using System.IO;
    using System.Data;
    using System.Runtime.InteropServices;
    
    namespace Ironring.Management.MMC {
      /// <summary>
      /// Any node which we create should be derived from the
      /// BaseNode.
      /// This node will get displayed in the left pane of the MMC.
      ///
      /// </summary>
      public class DirectoryNode : BaseNode {
        protected DataTable m_table = null;
    
        public DirectoryNode(SnapinBase snapin) : base(snapin) {
        }
    
        /// <summary>
        /// This is the public property to get/set the datatable
        /// value.
        /// This datatable values are the ones which gets displayed
        /// in the right pane
        /// of the MMC for the respective node item selected in
        /// the left pane.
        /// </summary>
        public DataTable Table {
          get { return m_table; }
          set { m_table = value; }
        }
    
        /// <summary>
        /// This method is called by the MMC snap to populate the
        // data for listview in the right pane, for the respective
        /// node item selected in the left pane.
        /// </summary>
        public override void OnShow() {
          IConsole2 console = Snapin.ResultViewConsole;
    
          IHeaderCtrl2 header = console as IHeaderCtrl2;
          OnShowHeader(header);
    
          IResultData rdata = console as IResultData;
          OnShowData(rdata);
    
          rdata.SetViewMode((int)ViewMode.Report);
        }
    
        /// <summary>
        /// This method is called by the OnShow() method to
        /// display header for the listview in the right pane,
        /// for the respective node item selected in the
        /// left pane.
        /// </summary>
        public virtual void OnShowHeader(IHeaderCtrl2 header) {
          try {
            if (Table != null) {
    
              foreach (DataColumn col in Table.Columns) {
                string name = col.ColumnName;
                int ord = col.Ordinal;
                header.InsertColumn(ord, name,
                       (int)ColumnHeaderFormat.LEFT, 140);
              }
            }
          }
          catch(COMException e) {
            System.Diagnostics.Debug.WriteLine(e.Message);
            throw e;
          }
          catch(Exception e) {
            System.Diagnostics.Debug.WriteLine(e.Message);
            throw e;
          }
        }
    
        /// <summary>
        /// This method is called by the OnShow() method to
        /// display data for the listview in the right pane,
        /// for the respective node item selected in the left pane.
        /// </summary>
        public virtual void OnShowData(IResultData ResultData) {
          if (Table != null) {
            int nRow = 1;
    
            RESULTDATAITEM rdi = new RESULTDATAITEM();
            foreach (DataRow row in Table.Rows) {
              row.ToString();
              rdi.mask=(uint)RDI.STR | (uint)RDI.IMAGE |
                       (uint)RDI.PARAM;
              rdi.nImage=-1; 
              rdi.str=  (IntPtr)(-1);
              rdi.nCol=0;
              rdi.lParam=m_iCookie|(nRow <<  16);
              ResultData.InsertItem(ref rdi);
              nRow++;
            }
          }
        }
    
        /// <summary>
        /// This method is called by the MMC snap to display each
        /// listview item's value in the right pane.
        /// </summary>
        public override void GetDisplayInfo(ref
               RESULTDATAITEM ResultDataItem) {
          bool bCallbase = true;
    
          if (Table != null) {
            int nRow = (ResultDataItem.lParam >> 16) - 1;
            int nCol = ResultDataItem.nCol;
    
            if ((ResultDataItem.mask & (uint)RDI.STR) > 0) {
              string data = DisplayName;
              if (nRow >= 0 && nRow < Table.Rows.Count && nCol >= 0
                  && nCol < Table.Columns.Count) {
                data = Table.Rows[nRow].ItemArray[nCol].ToString();
                bCallbase = false;
              }
    
              ResultDataItem.str =
                  Marshal.StringToCoTaskMemUni(data);
            }
          }
    
                if ((ResultDataItem.mask & (uint)RDI.IMAGE) > 0) {
                    int offset = 1;
                    if (IsUSeSmallIcons())
                        offset = 0;
    
                    ResultDataItem.nImage = (Cookie << 16)
                                          + offset;
                }
    
          if (bCallbase)
            base.GetDisplayInfo(ref ResultDataItem);
        }
    
        /// <summary>
        /// This method creates the datatable with appropriate
        /// data which serves as the datasource for the
        /// listview displayed in the right pane, for the
        /// respective node item selected in the left pane.
        /// </summary>
        public void CreateDataTableStructure() {
          DataTable dataTable = new DataTable();
          DataColumn dataColumn = new DataColumn();
          dataColumn.DataType =
              System.Type.GetType("System.String");
          dataColumn.ColumnName = "Name";
          dataColumn.ReadOnly = true;
          dataColumn.Unique = true;
          // Add the Column to the DataColumnCollection.
          dataTable.Columns.Add(dataColumn);
    
          dataColumn = new DataColumn();
          dataColumn.DataType =
              System.Type.GetType("System.String");
          dataColumn.ColumnName = "Last Accessed";
          dataColumn.ReadOnly = true;
          dataColumn.Unique = false;
          // Add the Column to the DataColumnCollection.
          dataTable.Columns.Add(dataColumn);
    
          dataColumn = new DataColumn();
          dataColumn.DataType =
              System.Type.GetType("System.String");
          dataColumn.ColumnName = "Last Written";
          dataColumn.ReadOnly = true;
          dataColumn.Unique = false;
          // Add the Column to the DataColumnCollection.
          dataTable.Columns.Add(dataColumn);
    
          // Make the ID column the primary key column.
          DataColumn[] PrimaryKeyColumns = new DataColumn[1];
          PrimaryKeyColumns[0] = dataTable.Columns["Name"];
          dataTable.PrimaryKey = PrimaryKeyColumns;
          this.Table = dataTable;
        }
    
        public void FillDataTableValues() {
          DataRow dataRow;
          DirectoryInfo directoryInfo =
              new DirectoryInfo(this.Properties["NodePath"].
                                ToString());
    
          foreach(FileInfo fileInfo in
                  directoryInfo.GetFiles()) {
            if(!fileInfo.Name.ToString().EndsWith(".transfer") &&
               !fileInfo.Name.ToString().EndsWith(".config")) {
              dataRow = this.Table.NewRow();
              dataRow["Name"] = fileInfo.Name;
              dataRow["Last Accessed"] =
                  fileInfo.LastAccessTime.ToString();
              dataRow["Last Written"] =
                  fileInfo.LastWriteTime.ToString();
              this.Table.Rows.Add(dataRow);
            }
          }
        }
      }
    }
    
  • Add new windows form to the <MMCTest> project and name it <FormDirectoryProperty>. Replace the code of the form with the code below.
  • //
    //Code block for FormDirectoryProperty//
    //
    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    
    namespace MMCTest
      {
      /// <summary>
      /// This is a sample form which opens up when menu button
      /// "FileAct Properties" is clicked over the selected node.
      /// </summary>
      public class FormDirectoryProperty:
             System.Windows.Forms.Form {
        private System.ComponentModel.Container components=null;
        private Hashtable nodeProperties;
    
        public FormDirectoryProperty() {
          //
          // Required for Windows Form Designer support
          //
          InitializeComponent();
    
          //
          // TODO: Add any constructor code after
          // InitializeComponent call
          //
          this.Icon=null;
          this.Width=384;
          this.Height=440;
          this.MaximizeBox=false;
          this.MinimizeBox=false;
    
          this.Text="Directory Properties";
    
          this.ShowInTaskbar=false;
          this.StartPosition=FormStartPosition.CenterParent;
          this.FormBorderStyle=FormBorderStyle.FixedDialog;
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing ) {
          if( disposing ) {
            if(components != null) {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          this.components = new System.ComponentModel.Container();
          this.Size = new System.Drawing.Size(300,300);
        }
        #endregion
    
        public Hashtable NodeProperties {
          set {
            nodeProperties=value;
          }
        }
    
        private void FormFileProperty_Load(object sender,
                                           System.EventArgs e) {
          FetchGeneralProperty();
        }
    
        private void FetchGeneralProperty() {
            MessageBox.Show(nodeProperties["NodePath"].ToString());
        }
    
      }
    }
    
  • Add a new windows form to the <MMCTest> project and name it <FormFileProperty>. Replace the code of the form with the code below.
  • //
    //Code block for FormFileProperty//
    //
    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    
    namespace MMCTest
    {
      /// <summary>
      /// This is a sample form which opens up when menu button
      /// "FileAct Properties" is clicked over the selected
      /// node's list/result item.
      /// </summary>
      public class FormFileProperty : System.Windows.Forms.Form {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components=null;
        private Hashtable nodeProperties;
    
        public FormFileProperty () {
          //
          // Required for Windows Form Designer support
          //
          InitializeComponent();
    
          //
          // TODO: Add any constructor code after
          // InitializeComponent call
          //
          this.Icon=null;
          this.Width=384;
          this.Height=440;
          this.MaximizeBox=false;
          this.MinimizeBox=false;
    
          this.Text="File Properties";
    
          this.ShowInTaskbar=false;
          this.StartPosition=FormStartPosition.CenterParent;
          this.FormBorderStyle=FormBorderStyle.FixedDialog;
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing ) {
          if( disposing ) {
            if(components != null) {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          this.components = new System.ComponentModel.Container();
          this.Size = new System.Drawing.Size(300,300);
        }
        #endregion
    
        public Hashtable NodeProperties {
          set {
            nodeProperties=value;
          }
        }
    
        private void FormFileProperty_Load(object sender,
                                           System.EventArgs e) {
          FetchGeneralProperty();
        }
    
        private void FetchGeneralProperty() {
            MessageBox.Show(nodeProperties["NodePath"].ToString()+
                 "\\"+nodeProperties["NodeResultName"].ToString());
        }
    
      }
    }
    
  • Add a new .cs file into the <MMCTest> project and name it <FileActSnapinElement.cs>. Replace the code of the class file with the code below,
  • //
    //Code block for FileActSnapinElement.cs
    //
    using System;
    using System.IO;
    using System.Data;
    using System.Drawing;
    using System.Collections;
    using System.Configuration;
    using System.Runtime.InteropServices;
    using MMCTest;
    using Ironring.Management.MMC;
    
    
    namespace MMCTest {
      /// <summary>
      /// This is the class which uses the DirecotryNode created
      /// above to populate it on to the MMC.
      /// </summary>
      public class FileActSnapinElement {
        public FileActSnapinElement() {
        }
        public void CreateDirectoryNode(SnapinBase snapinBase,
                                        string parentDirectory,
                                        BaseNode parentNode) {
          DirectoryInfo directoryInfo=new DirectoryInfo(
                        parentDirectory);
    
          //Create DirectoryNode with all the default properties
          // set
          DirectoryNode directoryNode=new
                                      DirectoryNode(snapinBase);
          directoryNode.DisplayName=directoryInfo.Name;
          directoryNode.Properties.Add("NodePath",
                   directoryInfo.Parent.FullName + "\\" +
                   directoryInfo.Name);
          directoryNode.Properties.Add("NodeResultName","");
          directoryNode.Properties.Add("EventTarget","");
          directoryNode.CreateDataTableStructure();
          directoryNode.FillDataTableValues();
          parentNode.AddChild(directoryNode);
    
          //Add Menu and EventHandler for Menu for DirectoryNode
          MenuItem topMenuItemFileActProperties=
                   new MenuItem("FileAct Properties",
                                "FileAct Properties for selected
                                 the item",
                                 new MenuCommandHandler(
                                   OnMenuFileActPropertiesClick));
          directoryNode.AddTopMenuItem(
                   topMenuItemFileActProperties);
          MenuItem topMenuItemRefresh=new MenuItem("Refresh",
                   "Refresh the contents",
                   new MenuCommandHandler(OnMenuRefreshClick));
          directoryNode.AddTopMenuItem(topMenuItemRefresh);
    
          //Add other Event Handlers for DirectoryNode
          directoryNode.OnSelectScopeEvent+=
              new NodeNotificationHandler(OnSelectScopeEvent);
          directoryNode.OnSelectResultEvent+=
              new NodeNotificationHandler(OnSelectResultEvent);
    
          foreach(DirectoryInfo subDirectoryInfo in
                  directoryInfo.GetDirectories()) {
            CreateDirectoryNode(snapinBase,
                                subDirectoryInfo.Parent.FullName +
                                "\\" +
                                subDirectoryInfo.Name,
                                directoryNode);
          }
        }
    
        //*******************************************************//
        //Event Handlers
        //Handles events generated by nodes and the result pane
        //
        //*******************************************************//
    
        //*******************************************************//
        //MMC Event Handlers
        //*******************************************************//
        /// <summary>
        /// This method is called when the node element is
        /// selected.
        /// </summary>
        protected void OnSelectScopeEvent(object sender,
                                          NodeEventArgs args) {
          DirectoryNode directoryNode=(DirectoryNode) sender;
          directoryNode.Properties["EventTarget"]="Node";
        }
    
        /// <summary>
        /// This method is called when the node's list/result item
        /// is selected.
        /// </summary>
        protected void OnSelectResultEvent(object sender,
                                           NodeEventArgs args) {
          DirectoryNode directoryNode=(DirectoryNode) sender;
          directoryNode.Properties["EventTarget"]="NodeResult";
        }
    
        //*******************************************************//
        //Menu Event Handlers
        //*******************************************************//
        /// <summary>
        /// This method is called when menu item
        /// "FileAct Properties" is clicked.
        /// </summary>
        public void OnMenuFileActPropertiesClick(object sender,
                                                 BaseNode arg) {
          DirectoryNode directoryNode=(DirectoryNode)arg;
          uint pItemID;
          IConsole2 console=directoryNode.Snapin.ResultViewConsole;
          IResultData resultData=console as IResultData;
          RESULTDATAITEM resultDataItem=new RESULTDATAITEM();
    
          try {
            if(directoryNode.Properties["EventTarget"].ToString().
               Equals("Node")) {
              FormDirectoryProperty formDirectoryProperty=new
                  FormDirectoryProperty();
              formDirectoryProperty.NodeProperties=
                  directoryNode.Properties;
              formDirectoryProperty.ShowDialog();
            }
            else {
              for(int loopCounter=0; loopCounter<directoryNode.
                  Table.Rows.Count; loopCounter++) {
                resultData.FindItemByLParam(directoryNode.Cookie |
                    (loopCounter+1 << 16), out pItemID);
                resultDataItem.nCol=0;
                resultDataItem.mask=(uint)RDI.STATE |
                    (uint)RDI.PARAM;
                resultDataItem.itemID=(int)pItemID;
                resultData.GetItem(ref resultDataItem);
                if(resultDataItem.nState==3) {
                  directoryNode.Properties["NodeResultName"]=
                      directoryNode.Table.Rows[loopCounter][0];
                  break;
                }
              }
    
              FormFileProperty formFileProperty=new
                  FormFileProperty();
              formFileProperty.NodeProperties=
                  directoryNode.Properties;
              formFileProperty.ShowDialog();
            }
          }
          catch(Exception ex) {
            throw ex;
          }
        }
    
        /// <summary>
        /// This method is called when menu item "Refresh" is
        /// clicked.
        /// </summary>
        public void OnMenuRefreshClick(object sender,
                                       BaseNode arg) {
          string selectedFileName=null;
          DirectoryNode directoryNode=(DirectoryNode)arg;
          uint pItemID;
          IConsole2 console=directoryNode.Snapin.
                    ResultViewConsole;
          IResultData resultData=console as IResultData;
          RESULTDATAITEM resultDataItem=new RESULTDATAITEM();
    
          try {
            if(!directoryNode.Properties["EventTarget"].ToString().
               Equals("Node")) {
              for(int loopCounter=0; loopCounter<directoryNode.
                  Table.Rows.Count; loopCounter++) {
                resultData.FindItemByLParam(directoryNode.Cookie |
                    (loopCounter+1 << 16), out pItemID);
                resultDataItem.nCol=0;
                resultDataItem.mask=(uint)RDI.STATE |
                    (uint)RDI.PARAM;
                resultDataItem.itemID=(int)pItemID;
                resultData.GetItem(ref resultDataItem);
                if(resultDataItem.nState==3) {
                  selectedFileName=directoryNode.Table.
                      Rows[loopCounter][0].ToString();
                  break;
                }
              }
            }
    
            resultData.DeleteAllRsltItems();
            directoryNode.Table.Rows.Clear();
            directoryNode.Table.AcceptChanges();
            directoryNode.FillDataTableValues();
            directoryNode.OnShowData(resultData);
    
            if(!directoryNode.Properties["EventTarget"].ToString().
               Equals("Node")) {
              for(int loopCounter=0; loopCounter<directoryNode.
                  Table.Rows.Count; loopCounter++) {
                if(directoryNode.Table.Rows[loopCounter][0].
                   ToString().Equals(selectedFileName))
                {
                  resultData.FindItemByLParam(directoryNode.Cookie
                      | (loopCounter+1 << 16), out pItemID);
                  resultDataItem.mask=(uint)RDI.STATE;
                  resultDataItem.itemID=(int)pItemID;
                  resultDataItem.nState=3;
                  resultData.SetItem(ref resultDataItem);
                  break;
                }
              }
            }
          }
          catch(Exception ex) {
            throw ex;
          }
        }
    
      }
    }
    
  • Open the <TestSnapin.cs> file in the <MMCTest> project.
  • Add the following piece of code at the end of the <TestSnapin> constructor.
  • FileActSnapinElement fileActSnapinElement=new
        FileActSnapinElement();
    fileActSnapinElement.CreateDirectoryNode(this,
                                             @"C:\FileActDemo",
                                             rootnode);
    
  • Build the solution.
  • Execute the project to see the addition of the new node just created.

Points of Interest

There is lot more work to be done to the Framework to include functionalities to display help, to incorporate multiselection option, task pads, and so forth. You can join the team at ironringsoftware.com to incorporate more functionalities to the framework and help the product to be more efficient.

Downloads

Download demo file - 355 Kb


Comments

  • cheap clarisonic can set right your incrustation

    Posted by iouwanzi on 06/06/2013 02:40am

    [url=http://www.miaclarisonicaustralia.org/]clarisonic mia 2[/url] Elle devait examiner un individu ghd IV Styler avant vers le bas les avantages de l’utilisation de lisseur ghd pas cher dans Vous pouvez aussi le plus souvent de prêt-à-utiliser de l’huile durcit à intégrer les huiles végétales avec de l’huile de sésame, l’huile d’olive et de noix de coco.ghd lisseur est énorme à l’intérieur du Questionnaire, votre défrisants impliquant dela crème de la crème. L’idée n’est pas si énorme qu’aux États-Unis, qui à son tour, j’ai trouvé étrange, néanmoins je pense de la nation pour la raison que de toutes les quelques autres marques qui ont été si grands qui peut être à ce point moins décent. [url=http://www.miaclarisonicaustralia.org/]clarisonic mia 2[/url] ghd pas cher peut être une marque japonaise de qui vend le fer à lisser en céramique et même des produits qui comprennent un sèche-cheveux, bonne prise en charge ainsi que des brosses. Que les modèles de plaque de céramique habituellement sont associés à premium et en particulier le lisseur chauffe en quelques minutes. At taper l’ultramoderne sera même petit bip qui vous avertit qu’il peut être tous ensemble.Superb confortable ! [url=http://www.australiaclarisonic.com/]clarisonic australia[/url] Victoria Secret 2012, la dernière conférence de maillots de bain sur la belle Miranda Kerr trésor et sexy top model Candice Swanepoel lors de la sélection se tailler un style de grands ghd lisseur cheveux de milliers de féminité sexy. Mannequin ange sexy pour Victoria Secret 2012, la dernière Maillots de bain pour la publicité,

    Reply
  • CHI Nano Keramisk Fladjern

    Posted by motherdhmm on 05/30/2013 11:07am

    [url=http://www.blog.cheapbeatsbydre.co.nz/]beats by dre nz[/url] Men det er vigtigt at notere sig at varmepladerne inden i dit ghd glattejern er samme størrelse som de keramiske plader udvendigt. Så jo større glattejern, jo større varmeplader. Dette har man gjort for at sikre sig at alle ghd glattejern har den helt rigtige og helt jævne fordeling af varmen. På den måde sikre ghd sig nemlig at deres glattejern glatter dit hår ordentligt første gang og glatter det hår du arbejder med helt lige og jævnt. [url=http://www.blog.cheapbeatsbydre.co.nz/beats-by-dre-headphones]beats by dre headphones[/url] Den vigtigste plot er baseret på historien om Askepot tilpasning. Klædt op inde i udsmykkede palads, venter Askepot for Prince invitation, men prins var en gruppe smuk dame omgivet Efter Askepot ikke anderledes med menigheden ikke vist megen interesse. Slog tolv midnat, Askepot smykker tøj er i den hurtigt falder fra kroppen så hurtigt som muligt, skal hun finde en vej ud af dilemmaet. GHD hår stikker hendes flugt til ovenpå Værelset, desperate øjne rørte på bordet smykkeskrin, viser en antydning af et smil på hans ansigt. Final igen spillede Askepot charme selvtillid, fuld Dronning Fan børn, hun Shoulin Slipper nedenunder og gik lige igennem prinsen fra et forsøg på at strejke op en samtale. [url=http://www.blog.cheapbeatsbydre.co.nz/monster-headphone]monster beats headphone[/url] inde i flere situationer er sted med hinanden låse til få producerer de følgende tilbud straks.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • With the average hard drive now averaging one terabyte in size, the fallout from the explosion of user-created data has become an overwhelming volume of potential evidence that law-enforcement and corporate investigators spend countless hours examining. Join Us and SANS' Rob Lee for our 45-minute webinar, A Triage and Collection Strategy for Time-Sensitive Investigations, will demonstrate how to: Identify the folders and files that often contain key insights Reduce the time spent sifting through content by …

Most Popular Programming Stories

More for Developers

RSS Feeds