Sunday, August 16, 2009

Marking ActiveX Controls as Safe

What is ActiveX Controls?
A control using ActiveX technologies. An ActiveX control can be automatically downloaded and executed by a Web browser. ActiveX is not a programming language, but rather a set of rules for how applications should share information. Programmers can develop ActiveX controls in a variety of languages, including C, C++, Visual Basic, and Java.

Creating a Simple COM Component
Lets create a simple com component that will extract existing DSN of client system using .NET.
1. Create a File->New->Project->ClassLibrary Project. Name it DSNComComponent.
2. A default class "Class1.vb" is added to your project file. Here in this project we are not using this class so its better to delete.
3. Add a Com Class to your project. Name it DSNComponent. Paste following code


_
Public Class DSNComponent
#Region "COM GUIDs"
' These GUIDs provide the COM identity for this class
' and its COM interfaces. If you change them, existing
' clients will no longer be able to access the class.
Public Const ClassId As String = "5162d4b1-7440-4fa3-b47f-12906475728b"
Public Const InterfaceId As String = "22dd7975-2554-4d49-bc82-b54ef0d2409f"
Public Const EventsId As String = "eb56f021-5c97-4e71-a2de-67d6acd2f703"
#End Region
' A creatable COM class must have a Public Sub New()
' with no parameters, otherwise, the class will not be
' registered in the COM registry and cannot be created
' via CreateObject.
Public Sub New()
MyBase.New()
End Sub
Public Function GetDSNLists() As String
Return OdbcHelper.GetDSNLists()
End Function
End Class


4. Add module to your project. Name it OdbcHelper. Paste following code

#Region "Imports"
Imports System.Text
Imports System
Imports System.Runtime.InteropServices
#End Region
Module OdbcHelper
#Region "Variable Declaration"
Private Const SQL_HANDLE_ENV As Short = 1
Private Const SQL_SUCCESS As Short = 0
Private Const DEFAULT_RESULT_SIZE As Short = 1024
Private Const SQL_FETCH_NEXT As UShort = 1
Private Const SQL_MAX_DSN_LENGTH As Short = 1024
Private Const SQL_ATTR_ODBC_VERSION As Integer = 200
Private Const SQL_OV_ODBC3 As Integer = 3
Private Const SQL_HANDLE_CON As Short = 2
Private Hwnd As IntPtr
#End Region
#Region "API Calls / Declarations"
_
Private Function SQLDataSources( _
ByVal henv As System.IntPtr, ByVal fDirection As UShort, _
ByVal szDSN As StringBuilder, ByVal cbDSNMax As Short, _
ByRef pcbDSN As Short, ByVal szDescription As StringBuilder, _
ByVal cbDescriptionMax As Short, ByRef pcbDescription As Short _
) As Short
End Function
_
Private Function SQLAllocHandle(ByVal hType As Short, ByVal inputHandle As IntPtr, ByRef outputHandle As IntPtr) As Short
End Function
_
Private Function SQLSetEnvAttr(ByVal henv As IntPtr, ByVal attribute As Integer, ByVal valuePtr As IntPtr, ByVal strLength As Integer) As Short
End Function
_
Private Function SQLFreeHandle(ByVal inStringLength As Short, ByVal hconn As IntPtr) As Short
End Function
#End Region
#Region "API Method Invoke"
Friend Function GetDSNLists() As String
Dim nRc = 0
Dim txt As String = String.Empty
Dim henv As IntPtr = IntPtr.Zero
Dim hconn As IntPtr = IntPtr.Zero
Dim nDSNLen As Short
Dim inString As StringBuilder = New StringBuilder(1024)
Dim outString As StringBuilder = New StringBuilder(1024)
Dim lenNeeded As Short
Dim Inc As Integer = 0
Try
If SQL_SUCCESS = SQLAllocHandle(SQL_HANDLE_ENV, henv, henv) Then
If SQL_SUCCESS = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, CType(SQL_OV_ODBC3, IntPtr), 0) Then
Do Until nRc <> SQL_SUCCESS
nRc = SQLDataSources(henv, SQL_FETCH_NEXT, inString, SQL_MAX_DSN_LENGTH, nDSNLen, outString, SQL_MAX_DSN_LENGTH, lenNeeded)
If nRc <> SQL_SUCCESS Then
Exit Do
End If
If Inc = 0 Then
txt = inString.ToString()
Else
txt = txt & "," & inString.ToString()
End If
Inc += 1
Loop
End If
End If
Catch ex As Exception
MsgBox(ex.Message)
txt = String.Empty
Finally
If Not (henv = IntPtr.Zero) Then
SQLFreeHandle(SQL_HANDLE_ENV, hconn)
End If
End Try
Return txt
End Function
#End Region
End Module


5. Compile your code. A file DSNComComponent.dll should be created in your bin directory.

Using COM Component on HTML Page
1. Create an empty HTML page. Add following code in your HTML file.


2. Open this html page in browser. You would be receiving an Error: Automation server can't create object.

3. Search Key HKEY_CLASSES_ROOT\CLSID\{5162D4B1-7440-4FA3-B47F-12906475728B} in your registry using regedit. Note that each COM component created in .NET application has different key value. This key value is available in your COM Class DSNComponent.vb.

4. Add two keys within {5162D4B1-7440-4FA3-B47F-12906475728B}
[HKEY_CLASSES_ROOT\CLSID\{5162D4B1-7440-4FA3-B47F-12906475728B}\Implemented Categories\{7DD95801-9882-11CF-9FA9-00AA006C42C4}]
[HKEY_CLASSES_ROOT\CLSID\{5162D4B1-7440-4FA3-B47F-12906475728B}\Implemented Categories\{7DD95802-9882-11CF-9FA9-00AA006C42C4}]
Key 7DD95801-9882-11CF-9FA9-00AA006C42C4 is used to mark controls that are safely scriptable.
Key 7DD95802-9882-11CF-9FA9-00AA006C42C4 is used to mark controls safely initializable from persistent data.



5. Browse your web page. Now DSN list would appear on your window.



Note: Don't use this method unless you have no other choice, and never use this method to mark as safe controls that aren't really safe.

Monitoring applications thru Trace Listners

What is Trace?
Trace provides an efficient logging and monitoring capabilities. Trace listners can used to write logs on console, text file or debugger output window.

Difference between Debug and Trace
Debug is used to write output in debug mode. Debug's write method will not work in release mode of application. Apart from it Trace works on both Debug as well Release mode of application.

Trace Listners
Trace Listners provide a mechanism for collecting and recording message that are sent. These messages are received by listners. The purpose of a listener is to collect, store, and route tracing messages.

Listner Types
  • A TextWriterTraceListener redirects output to an instance of the TextWriter class or to anything that is a Stream class. It can also write to the console or to a file, because these are Stream classes.
  • An EventLogTraceListener redirects output to an event log.
  • A DefaultTraceListener redirects output to an output window (VS.NET editor output window). This behavior is the default behavior for Debug and Trace messages, because DefaultTraceListener is automatically included in every Listeners collection and is the only listener automatically included.
  • A ConsoleTraceListener directs tracing or debugging output to either the standard output or the standard error stream.
  • A DelimitedListTraceListener directs tracing or debugging output to a text writer, such as a stream writer, or to a stream, such as a file stream. The trace output is in a delimited text format that uses the delimiter specified by the Delimiter property.
  • An XmlWriterTraceListener directs tracing or debugging output as XML-encoded data to a TextWriter or to a Stream, such as a FileStream .
An example using TextWriterTraceListener

Class: CustomTraceLog.CS

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Collections;
namespace CustomTraceLog
{
public sealed class CMTrace
{
public static void Path(string FileLocation)
{
string FileName = DateTime.Now.ToString("MMddyyyy") + ".txt";
string QualifiedPath=System.IO.Path.Combine(FileLocation, FileName);
Trace.Listeners.Clear();
Trace.Listeners.Add(new System.Diagnostics.TextWriterTraceListener(QualifiedPath));
}
public static void Close()
{
Trace.Close();
}
public static void Fail(string message)
{
Trace.Fail(message);
}
public static void Flush()
{
Trace.Flush();
}
public static void Indent()
{
Trace.Indent();
}
public static void Refresh()
{
Trace.Refresh();
}
public static void Unindent()
{
Trace.Unindent();
}
public static void Write(object value)
{
Trace.Write(value);
}
public static void Write(string message)
{
Trace.Write(message);
}
public static void Write(object value, string category)
{
Trace.Write(value,category);
}
public static void Write(string message, string category)
{
Trace.Write(message,category);
}
public static void WriteIf(bool condition, object value)
{
Trace.WriteIf(condition,value);
}
public static void WriteIf(bool condition, string message)
{
Trace.WriteIf(condition,message);
}
public static void WriteIf(bool condition, object value, string category)
{
Trace.WriteIf(condition,value,category);
}
public static void WriteIf(bool condition, string message, string category)
{
Trace.WriteIf(condition, message, category);
}
public static void WriteLine(object value)
{
Trace.WriteLine(value);
}
public static void WriteLine(string message)
{
Trace.WriteLine(message);
}
public static void WriteLine(object value, string category)
{
Trace.WriteLine(value,category);
}
public static void WriteLine(string message, string category)
{
Trace.WriteLine(message,category);
}
public static void WriteLineIf(bool condition, object value)
{
Trace.WriteLineIf(condition,value);
}
public static void WriteLineIf(bool condition, string message)
{
Trace.WriteLineIf(condition,message);
}
public static void WriteLineIf(bool condition, object value, string category)
{
Trace.WriteLineIf(condition,value,category );
}
public static void WriteLineIf(bool condition, string message, string category)
{
Trace.WriteLineIf(condition,message ,category );
}
public static void WriteException(Exception e)
{
StringBuilder sb = new StringBuilder();
sb.Append("***************** BEGIN EXCEPTION *****************");
sb.Append("Message: " + e.Message.ToString());
sb.Append("Stack Trace: " + e.StackTrace.ToString());
sb.Append("Source: " + e.Source.ToString());
IEnumerator Ie= e.Data.GetEnumerator();
while (Ie.MoveNext())
{
sb.Append("Data: " + e.Data[Ie.Current].ToString());
}
sb.Append("***************** END EXCEPTION *****************");
WriteLine(sb.ToString());
Flush();
Close();
}
public static void WriteLog(string strMessage)
{
StringBuilder sb = new StringBuilder();
sb.Append("***************** BEGIN LOG *****************");
sb.Append("Message: " + strMessage);
sb.Append("Time: " + DateTime.Now);
sb.Append("***************** END EXCEPTION *****************");
WriteLine(sb.ToString());
Flush();
Close();
}
}
}


Console Application: Program.CS

static void Main(string[] args)
{
int i = 10;
int j = 0;
CustomTraceLog.CMTrace.Path(@"C:\temp\");
CustomTraceLog.CMTrace.WriteLog("Application will now throw a zero divide exception");
try
{
int result = i / j;
}
catch (Exception ex)
{
CustomTraceLog.CMTrace.WriteException(ex);
}

}

Output Log File: C:\Temp\08162009.txt

***************** BEGIN LOG *****************
Message: Application will now throw a zero divide exception
Time: 16-08-2009 16:24:45
***************** END EXCEPTION *****************
***************** BEGIN EXCEPTION *****************

Message: Attempted to divide by zero.
Stack Trace: at ConsoleApplication1.Program.Main(String[] args) in C:\Users\Abhishek\Desktop\CM-TraceLog\ConsoleApplication1\Program.cs:line 17
Source: ConsoleApplication1
***************** END EXCEPTION *****************