Project Lancet

Project Lancet which will be a .NET Assembly Level Editor is started ...


More ...










Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

How to protect an assembly from decompiling

When I was newbie in .NET, it was a shocked for me to learn that .NET assemblies can be decompile. But today I know that this is a normal situation for a language which is compiling to an intermediate language. As we know that, after compiling a .NET project the output will be in MSIL (Microsoft Intermediate Language). And during the application lifecycle this codes will be compiled to Native Codes by the JIT (Just-In-Time Compiler) when they first used and cached in that computer for the future usages. Anyway this is another subject for us how JIT works, but here the problem is our assemblies are in MSIL format which has about 229 opcodes and all these opcodes has a standard working procedure. So if we know these opcodes and how they are working, we can produce the .NET codes by reverse engineering. This is simply what decompilers do. But why there are no stable decompilers for the native exes? The answer is simple, because there are no metadata for the native exes. In the .NET I can say that, metadata of that assembly is really very important to resolve the Type and Member structures of that assembly. Anyway there are a lot of decompilers for the .NET which can decompile codes as same as with the original codes. Xenocode Fox Decompiler and Reflector are the most know ones.
Below is an example which shows us what a decompiler can do.

Original Code Decompiled Code
private void btnRun_Click(object sender, EventArgs e)
{
    Stopwatch watch = new Stopwatch();
   
    int iteration = 0;
    if (!int.TryParse(txtNumIteration.Text, out iteration))
        iteration = 10000000;
    int value = 0;
    if (!int.TryParse(txtNumParam.Text, out value))
        value = 50;
    IExample ex = null;
    int caseCount;
    switch (cmbCases.SelectedIndex)
    {
        case 0:
            caseCount = 5;
            ex = new Example5();
            break;
        case 1:
            caseCount = 10;
            ex = new Example10();
            break;
        case 2:
            caseCount = 20;
            ex = new Example20();
            break;
        case 3:
            caseCount = 50;
            ex = new Example50();
            break;
        default:
            caseCount = 99;
            ex = new Example99();
            break;
    }
    int r = 0;
    watch.Start();
    for (int i = 0; i < iteration; i++)
    {
        r = ex.GetSwitchResult(value);
    }
    watch.Stop();
    long swResult = watch.ElapsedMilliseconds;
    watch.Start();
    for (int i = 0; i < iteration; i++)
    {
        r = ex.GetIfResult(value);
    }
    watch.Stop();
    AppendItem(iteration, caseCount, value, swResult, watch.ElapsedMilliseconds);
}
private void btnRun_Click (object sender, EventArgs e)
{
     int caseCount;
     Stopwatch watch = new Stopwatch();
     int iteration = 0;
     if (!int.TryParse(txtNumIteration.Text, out iteration))
     {
          iteration = 10000000;
     }
     int value = 0;
     if (!int.TryParse(txtNumParam.Text, out value))
     {
          value = 50;
     }
     IExample ex = null;
     switch (cmbCases.SelectedIndex)
     {
          case 0:
          {
               caseCount = 5;
               ex = new Example5();
               break;
          }
          case 1:
          {
               caseCount = 10;
               ex = new Example10();
               break;
          }
          case 2:
          {
               caseCount = 20;
               ex = new Example20();
               break;
          }
          case 3:
          {
               caseCount = 50;
               ex = new Example50();
               break;
          }
          default:
          {
               caseCount = 99;
               ex = new Example99();
               break;
          }
     }
     int r = 0;
     watch.Start();
     for(int i = 0; i < iteration < i++)
     {
          r = ex.GetSwitchResult(value);
     }
     watch.Stop();
     long swResult = watch.ElapsedMilliseconds;
     watch.Start();
     for (int i = 0;i < iteration; i++)
     {
          r = ex.GetIfResult(value);
     }
     watch.Stop();
     AppendItem(iteration, caseCount, value, swResult, watch.ElapsedMilliseconds);
}
Decompiled code was generated by using Xenocode Fox



As you see here, the output is nearly as same as the original code when we decompile the assembly with Xenocode Fox.

So the question is how we can protect our assemblies from decompiling. Actually the answers is simple, except we don’t make our .net assemblies native, we cannot. By one way or other decompilers can decompile our codes back to the source codes. But against the decompilers there are Obfuscators which helps us to protect our codes from decompiling. If we have to explain what an obfuscator do, simply, Obfuscators changes the names of our Types and Members (properties, methods, fields, events etc.) to unreadable or unmeaning full names in the metadata of our assembly. By this way when someone decompiles our codes they can only see the unmeaning full class and member names which is really hard to understand the code. Generally we make the type and member names as understandable. For example if we write a class which indicates a User’s information, we will probably make the class name as User. So after decompiling the person who decompiles the code, sees this User class and he/she understands that this class is for the user information. So if we change the name of this class to an understandable name (for ex: xbc3453vbgf345) then it will be really hard to understand what this class is for. Except from changing the type and member names some obfuscators also can make .net assemblies as native, or some of them can injects useless codes to our methods which cause our methods hard to understand.

There are a lot of Obfuscators like Xenocode PostBuild, CodeVeil, Salamander etc. I’m using PostBuild to obfuscate my codes and I can say that it is really enough to protect my assemblies. Not only changing the type and member names but also we can make our assemblies Native by using PostBuild, or we can allow it to injects some codes which protects our methods to be decompiled (by injecting some untargeted branches) etc. etc. Making our assemblies as native will stops cares about decompiling. Code injection will obstruct Reflector and Fox to decompile that methods. PostBuild also can make our assemblies smaller by compressing and removing unused metadata by dead code elimination. This will increase our assemblies’ performance. Anyway you can check PostBuild by downloading its trial version. More About Xenocode Postbuild | Download PostBuild Evaluation

As conclusion, I can say that using a good obfuscator is enough to protect our codes. There is no need to care about decompilers. Even I develop a decompiler, I still continue to develop my other projects by using .NET and I have no care about this.

Currently rated 5.0 by 3 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Power of Switch Comparing with If-Else

Switch vs IfMost of the people know that switch works like if-else blocks. The only difference between the switch and if-else is its being for the many conditional states, and also writing switch is more simple than if-else block. This knowledge is really a big mistake because switch has a different algorithm and working-procedure comparing to if-else block. To demonstrate this, I wrote a simple example which indicates the performance differences between switch and if-else in many different situations. Download the source codes of this demonstration example and than let's speak about it a little bit more. 

First let me explain the details of this Example. In the example, there are three arguments, which we are using in our tests.
These arguments are as follows;

# of iterations: Indicates that how many times we are testing the same situation. We cannot understand the difference of time by only one test because of the CPU's speed. CPU will do the switch or if-else operations in a very short time. So to understand the real difference, we need to do the same test again and again. Then we have to check the time difference in total.
Parameter (Search Value): In the example, there is an if-else or a switch block which is searching from 1 - [# of cases]. Here the Parameter will indicates that in which case or else-if block our value is in. If you give the parameter a value of 1, this means that first case or first if block will return true. If you give a 99, this means that the 99th case or else-if block will return true. Actually this is the number of how many if-else conditions will be checked.
# of cases: This number indicates the total number of the conditions, which means how many cases or if-else block we have.

After giving these arguments; if you click to the Run Test button, it will make a test by using the given arguments and add a line to the results, which indicates properties and results of the test.

The above picture is showing the results of my 7 tests. Now let's speak about these tests and than let me explain why the result is this way.
In the tests 1, 2 and 3 the arguments of the tests are same. The only difference is the Search Value which I try to select from the beginning, from the middle and finally from the end of the conditional block. As we see in the column for the switch, it does not matter what we are searching for. The time is nearly the same for each test (88, 86, 87). But for the if-else block, the time will dramatically increase according to the Search value. If we are searching for a number which is at the bottom of the if-else block, it takes too long; and if we select a number which is from the beginning of if-else block, it takes less time. But even for the smaller and for the bigger numbers, switch is always faster than if-else block.

To talk about other tests, we only change the # of case. This means the only difference is the number of the total conditional operations. But again the results show us that the switch is faster than if-else block, and number of conditions it is very important for the if-else block but not very important for the switch.

As I say at the beginning, most of the people think that switch works same as if-else block but this test shows us it is not true. So how does switch work?

Switch has a very simple but good algorithm. When we write a switch, it will automatically loads the first case's value, then calculates the index number of the target case block, and adds an array of addresses of case block in the IL. For example:

public void GetSwitchResults(int value)
{
    switch (vaue)
    {
        case 1:
            return 1;
        case 2:
            return 2;
        case 3:
            return 3;
        case 4:
            return 4;
        case 5:
            return 5;
        default:
            return int.MinValue;
    }
}
.method public hidebysig newslot 
virtual final instance int32 
GetSwitchResult(int32 valuecil managed
{
     // Code Size: 63 byte(s)
     .maxstack 2
     .locals init (
          int32 num1,
          int32 num2)
     L_0000: nop 
     L_0001: ldarg.1 
     L_0002: stloc.1 
     L_0003: ldloc.1 
     L_0004: ldc.i4.1 // loads the first cases value (1)
     L_0005: sub // calculation [our value - first value]
     L_0006: switch (L_0021,L_0025,L_0029,L_002D,L_0031)
     L_001f: br.s L_0035 // address of default case
     L_0021: ldc.i4.1 // case 1
     L_0022: stloc.0 
     L_0023: br.s L_003D
     L_0025: ldc.i4.2  // case 2
     L_0026: stloc.0 
     L_0027: br.s L_003D
     L_0029: ldc.i4.3 // case 3
     L_002a: stloc.0 
     L_002b: br.s L_003D
     L_002d: ldc.i4.4 // case 4
     L_002e: stloc.0 
     L_002f: br.s L_003D
     L_0031: ldc.i4.5 // case 5
     L_0032: stloc.0 
     L_0033: br.s L_003D
     L_0035: ldc.i4 -2147483648 // default case
     L_003a: stloc.0 
     L_003b: br.s L_003D
     L_003d: ldloc.0 
     L_003e: ret 
}
IL codes generated by Xenocode Fox 2007

The IL output of the left code above will look like as the right one. When compiling the code, switch puts a target for each case. And during runtime when we give a number to the switch, it checks the difference between the first case and our value, and the result indicates the index of the target case. So if the index is in one of the cases, it directly branches to the given case's address. Actually the calculation formula is [our value] - [first case's value], which returns us the index of our target case in the target cases array. You can see this in the IL. During the compile, compiler will generates the needed calculation codes just before the switch.

Let me explain it a little bit more with an example: Considering the code above, if we give a value 2, it will do the following action. 2 - 1 = 1. So second address (because of 0 based indexing) in the targets list is the starting address of our case block. So it directly goes to the L_0025 which the case 2:begins. Considering the value 3, the calculation will be like 3 - 1 = 2. So it goes to the third address in the target list, and so this address is L_0029(begins of the case 3).

There are 2 problems here. One of them is about the default case because although there are 5 cases and one default case (total 6), there are only 5 targets in the addresses array. And the second problem is what happens if the number does not fall between in any of the cases (for ex: 23, it does not exists in the cases list). For the first problem: If there is a default case in a switch, compiler will adds a br.s [TARGET] after the switch instruction which the TARGET indicates the starting address of the default case. If there is no default case, compiler will again add a br.s [TARGET] after the switch, but this time TARGET will indicates the ending address of switch.

For the second problem: After the calculation, if the result (index of the target case) is not a valid index for our target cases array, then switch does not do anything, so the next instruction (which br.s [TARGET] as we explain above) will execute and it will directly go to the default case if exists; otherwise it goes out of the switch. For example if the value is -1, then the calculation will be -1 - 1 = -2 which is not a valid index. So this value will directly go to the default case. It is also the same as for the value 6. After the calculation, the index will be 5 but our targets array has only 5 elements, so 5 is not a valid index for our switch again.

Now let's go into the switch deeper. As we see in these examples, there might be a subtract operation on the switch condition to make the first value as zero. So this means that switch condition must be an integral type, which can be int16, int32, int64, enum etc. You cannot use float or double values in the switch cases. For example, the following code will not compile:

switch (a) // a is float
{
     case 0.1f:
         break;
     case 0.2f:
         break;
}


Compiler won't compile the switches as how we write them. It may add some codes to the switch or may directly remove the switch and instead of it, it adds an if-else block to the IL. This will be done by the compiler automatically according to the number and values of the switch's cases and condition of the switch. Check the following examples:
Code After Compile
switch (a)
{
    case 1:
        break;
    case 3:
        break;
    case 4:
        break;
    case 5:
        break;
}
 switch (a)
{
    case 1:
        break;
    case 2:
        break;
    case 3:
        break;
    case 4:
        break;
    case 5:
        break;
}
Switch cases must increase one by one continuously. If one item could not be found (here case 2), compiler will add an empty case for that number. Because of the calculation each element indicates a target. So there must be a target for the case 2, otherwise switch algorithm will not work. But this doesn't mean that every time we use switch compiler fills the empty cases. In some situations, it can convert the switch to if - else block. Here it is not important for the compiler how we write the orders of the cases. It will first sorts the cases according to the case values, and then it will check the empty spaces.

Code After Compile
switch (a)
{
    case 5:
        break;
    case 24:
        break;
    case 28:
        break;
}
if (a == 5)
{

}else if (a == 24)
{

}else if (a == 28)
{

}
Here in this example, compiler must add too many cases to fill all the empty spaces but instead of adding cases, compiler will compile this code as if-else block.

What about char and string cases? Can we use them or not?
For the char cases, I can say that yes. Because chars can be converted to int, so compiler can use char types in the switches without doing anything.
For the string cases, I can say again yes but this not common. That’s to say, again compiler decide this. In some cases, it converts them to if - else block (especially if the number of cases is small, for ex- 3 cases). And in some cases it will compile them as switch cases. So how can it be? As I said before, switches need integral types as cases conditions, and string is not an integral type. So how can this take place?

For the strings, compiler adds a Dictionary<string, int> item to a Compiler Generated class in that assembly. Then it will add the string values as string into that dictionary as int KeyValuePair which string is the case value and int is the order of the case. And during the runtime it will first try to get the int value of that string from the dictionary, and then use that value in the switch.

Anyway using switches (for more conditional operations) in the .NET will be better than using if - else block. Of course, if the conditions are constant values and type of the value is one of the integral types or string.

Currently rated 4.4 by 7 people

  • Currently 4.428571/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Xenocode PostBuild - The application failed to initialize properly (0xc000007b)

In one of my public projects, I used Xenocode PostBuild to obfuscate my codes. PostBuild is a very popular and common Obfuscation Tool for the .NET assemblies. When I worked for the Xenocode, I saw that the developers of PostBuild are really very good at doing their jobs. Most of them had worked for the Microsoft before. So I can say that if you need an obfuscation tool, you can use Xenocode PostBuild obfuscation tool without thinking a second.

But after I obfuscated my binaries with Postbuild, I started to get an error as "The application failed to initialize properly (0xc0000077b)". Actually this error does not occur in all computers, it just occurs in computer which has .NET Framework 3.0. After working on this problem a little bit more, I finally solved the bug. The problem was because of the "Enable Output Compression" options in the Postbuild. By enabling this option, you will allow Postbuild to compress your assemblies and inject some codes to perform on-the-fly decompression. When I unchecked the Enable Output Compression option and re-obfuscate it, the problem is gone.

So the solution for this exception is simple. Just disable "Enable Output Compression" option and re-obfuscate your assemblies.
Also let me tell where this option is in the Postbuild. Go to the Optimize tab and it is there at the bottom of the page

!!! NOTE: Kenji, who is from Xenocode, wrotes a comment and said that this bug was fixed in the latest version of the Xenocode PostBuild. So if you are using a version newer than 5.2.6839, there won't be a problem. But if you got this error, then try to download the latest patch from the Xenocode, so you can obfuscate your assemblies with the compression option.


Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

What is the best way to declare static fields?

Today I wrote a simple application, which shows what the difference is between initializing a static field in the explicit static constructor and doing the same during the declaration time (inline). I know that even when we initialize our static fields inline, the compiler will add an implicit static constructor to that class and initialize static values in that method. But this example showed me that there is really a long time difference between initializing static fields inline and in explicit static constructor. Here are a screenshot from the example - in this example BeforeFieldInit means that the static fields are initialized inline and NotBeforeFieldInit means that static fields are initialized in the explicit static constructor:

Screen Capturing Example

Download Example Code

Declaring a static field and initializing its value in an explicit static constructor.

using System;

namespace
BeforeFieldInitExample
{
    public class
NotBeforeFieldInit
    {
        // here there is only decleration of the static field
        public static int
A;

        static
NotBeforeFieldInit()
        {
            // Initialization of A's values is here in the explicit static constructor
            A = 0;
        }
    }
}


Initializing a static fields value during the decleration (inline).

using System;

namespace
BeforeFieldInitExample
{
    public class
BeforeFieldInit
    {
        public static int
A = 0;
    }
}


These two code groups will work as the same and produce the same result. Actually when we compile the second code, the output will be as the same with the first code. I mean, during the compiling time the compiler will create an implicit static constructor for the BeforeFieldInit class and initialize the field's value in that method. So it will be the same with the first code.

But there is a small difference between these codes. The difference can only be seen by checking the IL codes of these types.

For the first example, IL code of the class NotBeforeFieldInit will be as follows:

.class public auto ansi NotBeforeFieldInitClass
            extends
object
{
    .
method public hidebysig specialname
            rtspecialname instance
            void .ctor() cil managed
    {
        // Code Size: 7 byte(s)
        .maxstack
8
        L_0000: ldarg.0
        L_0001: call instance
void object::.ctor()
        L_0006: ret
    }

    .
method private hidebysig specialname
            rtspecialname static
            void .cctor() cil managed
    {
        // Code Size: 22 byte(s)
        .maxstack
8
        L_0000: nop
        L_0001: ldc.i4.0
        L_0002: stsfld int32 BeforeFieldInitExample.NotBeforeFieldInitClass::A
        L_0007: ldc.r8 9
        L_0010: stsfld float64 BeforeFieldInitExample.NotBeforeFieldInitClass::B
        L_0015: ret
    }

    .field public static
int32 A
    .
field public static
float64 B
}


And for the second example, which the name of the class is BeforeFieldInit's IL code will be as runs:
.class public auto ansi
            beforefieldinit // here beforefieldinit mask is added
                BeforeFieldInitClass

        extends object
{
    .
method public hidebysig specialname
            rtspecialname instance
            void .ctor() cil managed
    {
       // Code Size: 7 byte(s)
        .maxstack
8
        L_0000: ldarg.0
        L_0001: call instance
void object::.ctor()
        L_0006: ret

    }

    .method private hidebysig specialname
            rtspecialname static
            void .cctor() cil managed
    {
        // Code Size: 21 byte(s)
        .maxstack
8
        L_0000: ldc.i4.0
        L_0001: stsfld int32 BeforeFieldInitExample.BeforeFieldInitClass::A
        L_0006: ldc.r8 9
        L_000f: stsfld float64 BeforeFieldInitExample.BeforeFieldInitClass::B
        L_0014: ret

     }

    .field public static int32 A
    .
field public static
float64 B
}

IL codes generated by Xenocode Fox 2007

As you see in the IL the only difference between these two codes is the second class's having the beforefieldinit flag. So what is this flag doing?

beforefieldinit flag tells to the JIT that this class's static fields are initialized inline. If a class has no beforefieldinit flag, then JIT compiler will automatically check whether explicit static constructor is called before. This means that whenever you want to try to access any static member of this class or try to create a new instance of this class, JIT will automatically calls the explicit static constructor. Therefore you will loose performance because whenever you try to access a static member, JIT also checks whether static constructor is invoked before. But in the second example if we add a beforefieldinit flag to our class, this means that our static members are initialized inline, so JIT does not need to check whether static constructor is invoked before. This is the main reason that causes performance difference between those two classes. When we wrote an explicit static constructor and initialize our fields' values, the compiler will not add beforefieldinit flag to that class. But if we initialize our static fields inline, then compiler will add an implicit static constructor and initialize our static fields there and also add the beforefieldinit flag to our class.

So always, try to use inline field initialization for the static fields if you can.

Currently rated 4.8 by 5 people

  • Currently 4.8/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

How to Capture Screenshot and Paste Any Image to the Screen

Screen Capturing ExampleFor a very long time ago (about 4 years...), in one of my projects, I needed to capture the screenshot which must have to support both full screen capturing and specific regional capturing.

Also I need to paste that captured image back to the screen programmatically. At that moment I solved my problem by using some WinApi methods in the user32.dll and gdi32.dll. Here I want to share that code with you. You can also download the example source codes.

To use this code;
Use CaptureScreen() method to capture whole screen;
Use CatureRegion(Region) to capture only the given region of the screen;
Use PasteToScreen(Bitmap, Region) method to paste any image to the given region on to the screen.

Download Source Codes and Demo Exe 

Here are the codes ...

public class NativeMethods
{
    ///
<summary>
   
///
Takes a screenshot of full screen
   
///
</summary>
   
/// <returns>Return the Bitmap of the Screen
</returns>
   
public static Bitmap
CaptureScreen()
    {
        return CaptureRegion(null
);
    }

    /// <summary>
    ///
Takes a Screen Shot of the given rectangle.
    ///
</summary>
    /// <param name="rct">Rectangle area which we try to get the screen shot.
</param>
    /// <returns>Return the Bitmap of the screen defined rectangle.
</returns>
    public static Bitmap CaptureRegion(Rectangle
rct)
    {
        return CaptureRegion(new Region
(rct));
    }

    /// <summary>
    ///
Takes a screen shot of the given region.
    ///
</summary>
    /// <param name="rgn">Region that which we try to get the picture of it.
</param>
    /// <returns>
Returns the Bitmap of the given region.
    ///
Bitmap Size will be equal to the GetBounds() of the Region.
    ///
Any other points that they are not in the region and
    /// which are in the Bounds will be as Color.Transparent.
</returns>
    public static Bitmap CaptureRegion(Region
rgn)
    {
        IntPtr
hSDc, hMDc;
        IntPtr
hBtm, hOldBtm;
        Size imgSize = Size
.Empty;
        int
xCoor = 0, yCoor = 0;
        if (rgn == null
)
        {
            hSDc = CreateDC("DISPLAY", string.Empty,string.Empty, string
.Empty);
            hMDc = CreateCompatibleDC(hSDc);
            imgSize = new Size
(GetDeviceCaps(hSDc, 8),
            GetDeviceCaps(hSDc, 10));

            GraphicsPath p = new GraphicsPath
();
            p.AddRectangle(new Rectangle
(0, 0, imgSize.Width, imgSize.Height));
            rgn = new Region
(p);
        }
        else
        {
            hSDc = GetDC(IntPtr
.Zero);
            SelectClipRgn(hSDc, rgn.GetHrgn(Graphics
.FromHdc(hSDc)));
            hMDc = CreateCompatibleDC(hSDc);

            RECT myBox = new RECT();
            GetClipBox(hSDc, ref
myBox);
            imgSize = new Size
(myBox.Width, myBox.Height);
            xCoor = myBox.left;
            yCoor = myBox.top;
        }

        hBtm = CreateCompatibleBitmap(hSDc,
                imgSize.Width, imgSize.Height);
        hOldBtm = SelectObject(hMDc, hBtm);
        BitBlt(hMDc, 0, 0, imgSize.Width, imgSize.Height,
                hSDc, xCoor, yCoor, RasterOperations
.SRCCOPY);
        hBtm = SelectObject(hMDc, hOldBtm);

        DeleteDC(hSDc);
        DeleteDC(hMDc);

        Bitmap bmp = Bitmap.FromHbitmap(hBtm);
        RectangleF rct = rgn.GetBounds(Graphics
.FromImage(bmp));
        RectangleF[] rcts = rgn.GetRegionScans(new Matrix
());
        for (int
i = 0; i < rcts.Length; i++)
        {
            rcts[i].X -= rct.X;
            rcts[i].Y -= rct.Y;
        }

        for (int x = 0; x < bmp.Width; x++)
        {
            for (int
y = 0; y < bmp.Height; y++)
            {
                bool isIn = IsInRectangles(rcts, (float)x, (float
)y);
                if
(!isIn)
                    bmp.SetPixel(x, y, Color
.Transparent);
            }
        }
        DeleteObject(hBtm);
        return
bmp;
    }

    /// <summary>
    ///
Checks that is in region.
    ///
</summary>
    public static bool IsInRegion(Region rgn, Point
pt)
    {
        RectangleF[] rcts = rgn.GetRegionScans(new Matrix
());
        return
IsInRectangles(rcts, pt);
    }

    public static bool IsInRectangles(RectangleF[] rcts, Point
pt)
    {
       return IsInRectangles(rcts, (float)pt.X, (float
)pt.Y);
    }

    /// <summary>
    ///
 Checks that is Point in Rectangles (Scans of Region).
    ///
</summary>
    public static bool IsInRectangles(RectangleF[] rcts, float x, float
y)
    {
        for (int
i = 0; i < rcts.Length; i++)
        {
            if
(rcts[i].Contains(x, y))
            {
                return true
;
            }
        }
        return false
;
    }

    public unsafe static void PasteToScreen(Bitmap bmp, Region rgn)
    {
        if (bmp == null || rgn == null
)
            return
;
        IntPtr hDc = GetDC(IntPtr
.Zero);
        Graphics g = Graphics
.FromHdc(hDc);
        RectangleF rctF = rgn.GetBounds(Graphics
.FromHdc(hDc));
        Rectangle rct = new Rectangle((int)rctF.X, (int)rctF.Y,
                                   (int)rctF.Width, (int
)rctF.Height);
        g.SetClip(rgn, CombineMode
.Replace);
        g.DrawImage((Image
)bmp, rct);
        DeleteDC(hDc);
        g.Dispose();
    }

    // NATIVE METHODS
    [DllImport("gdi32.dll"
)]
    public static extern int BitBlt(IntPtr srchDC, int srcX, int
srcY,
                        int srcW, int srcH, IntPtr desthDC, int destX,
                        int destY, RasterOperations
op);

    [DllImport("gdi32.dll", CharSet = CharSet
.Auto)]
    public static extern IntPtr CreateDC(string lpDriverName,
                        string
lpDeviceName,
                        string lpOutput, string
lpInitData);

    [DllImport("gdi32.dll", CharSet = CharSet
.Auto)]
    public static extern IntPtr CreateCompatibleDC(IntPtr
hDC);

    [DllImport("gdi32.dll"
)]
    public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr GetDC(IntPtr
hWnd);

    [DllImport("gdi32.dll", CharSet = CharSet
.Auto)]
    public static extern int GetClipBox(IntPtr hDC, ref RECT rectBox);    

    [DllImport("gdi32.dll", CharSet = CharSet
.Auto)]
    public static extern int SelectClipRgn(IntPtr hDC, IntPtr
hRgn);

    [
DllImport("gdi32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC,
                                           int nWidth, int nHeight);

    [DllImport("gdi32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SelectObject(IntPtr hDC, IntPtr
hObject);

    [DllImport("gdi32.dll", CharSet = CharSet
.Auto)]
    public static extern bool DeleteDC(IntPtr hDC);

    [DllImport("gdi32.dll", CharSet = CharSet
.Auto)]
    public static extern IntPtr DeleteObject(IntPtr
hObject);

    [
DllImport("user32.dll")]
    public static extern IntPtr SetTimer(IntPtr hWnd, int nIDEvent,
                                    int uElapse, TimerProc
lpTimerFunc);

    public delegate void TimerProc(IntPtr hWnd, int msg, IntPtr wParam,
                                      IntPtr
lParam);

    [DllImport("user32.dll"
)]
    public static extern bool KillTimer(IntPtr hwnd, int idEvent);


    public enum RasterOperations :
uint
    {
        SRCCOPY = 0x00CC0020,
        SRCPAINT = 0x00EE0086,
        SRCAND = 0x008800C6,
        SRCINVERT = 0x00660046,
        SRCERASE = 0x00440328,
        NOTSRCCOPY = 0x00330008,
        NOTSRCERASE = 0x001100A6,
        MERGECOPY = 0x00C000CA,
        MERGEPAINT = 0x00BB0226,
        PATCOPY = 0x00F00021,
        PATPAINT = 0x00FB0A09,
        PATINVERT = 0x005A0049,
        DSTINVERT = 0x00550009,
        BLACKNESS = 0x00000042,
        WHITENESS = 0x00FF0062
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct
RECT
    {
        public int
left;
        public int
top;
        public int
right;
        public int
bottom;

        public
int Width
        {
            get { return
right - left; }
        }

        public int
Height
        {
            get { return
bottom - top; }
        }
    }
}


Currently rated 4.4 by 8 people

  • Currently 4.375001/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

How to Find SQL Servers on a Network

Most of us developing our programs by using MSSQL Server, and it is a necessary for us to make SQL Server selectable in the Options Dialog. But here the problem is how we can find the SQL Servers in the network ?

There are two different way we can use for searching the network for the available Sql Servers.

1 - There is a class in the .NET Framework which name is SqlDataSourceEnumerator in the System.Data.Sql namespace. We can use that class, and get the sql servers easly:

DataTable sqls = SqlDataSourceEnumerator.Instance.GetDataSources();

In this method we can only get the Sql Server machines on a network. But in the second method we can also search the Terminal machines, server machines etc.

2 - We can use NetServerEnum function in the netapi32.dll. The following code demonstrates us how we can find SQL Servers in a network...

public class NativeMethods
{
    public const uint
ERROR_SUCCESS = 0;
    public const uint
ERROR_MORE_DATA = 234;
    

   
[
DllImport("netapi32.dll", EntryPoint = "NetServerEnum"
)]
    public static extern int
NetServerEnum(
            [MarshalAs(UnmanagedType
.LPWStr)]
            string
servername,
            int
level,
            out IntPtr
bufptr,
            int
prefmaxlen,
            ref int
entriesread,
            ref int
totalentries,
            SV_101_TYPES
servertype,
            [MarshalAs(UnmanagedType
.LPWStr)]
            string
domain,
            int resume_handle);
 
    

   
[DllImport("netapi32.dll", EntryPoint = "NetApiBufferFree"
)]
    public static extern int NetApiBufferFree(IntPtr buffer);

    [StructLayout(LayoutKind.Sequential)]
    public struct
SERVER_INFO_101
    {
        [MarshalAs(UnmanagedType
.U4)]
        public PLATFORM_ID
sv101_platform_id;
        [MarshalAs(UnmanagedType
.LPWStr)]
        public string
sv101_name;
        [MarshalAs(UnmanagedType
.U4)]
        public uint
sv101_version_major;
        [MarshalAs(UnmanagedType
.U4)]
        public uint
sv101_version_minor;
        [MarshalAs(UnmanagedType
.U4)]
        public SV_101_TYPES
sv101_type;
        [MarshalAs(UnmanagedType
.LPWStr)]
        public string
sv101_comment;
    }

    public enum SV_101_TYPES :
uint
    {
        SV_TYPE_WORKSTATION = 0x00000001,
        SV_TYPE_SERVER = 0x00000002,
        SV_TYPE_SQLSERVER = 0x00000004,
        SV_TYPE_DOMAIN_CTRL = 0x00000008,
        SV_TYPE_DOMAIN_BAKCTRL = 0x00000010,
        SV_TYPE_TIME_SOURCE = 0x00000020,
        SV_TYPE_AFP = 0x00000040,
        SV_TYPE_NOVELL = 0x00000080,
        SV_TYPE_DOMAIN_MEMBER = 0x00000100,
        SV_TYPE_PRINTQ_SERVER = 0x00000200,
        SV_TYPE_DIALIN_SERVER = 0x00000400,
        SV_TYPE_XENIX_SERVER = 0x00000800,
        SV_TYPE_SERVER_UNIX = 0x00000800,
        SV_TYPE_NT = 0x00001000,
        SV_TYPE_WFW = 0x00002000,
        SV_TYPE_SERVER_MFPN = 0x00004000,
        SV_TYPE_SERVER_NT = 0x00008000,
        SV_TYPE_POTENTIAL_BROWSER = 0x00010000,
        SV_TYPE_BACKUP_BROWSER = 0x00020000,
        SV_TYPE_MASTER_BROWSER = 0x00040000,
        SV_TYPE_DOMAIN_MASTER = 0x00080000,
        SV_TYPE_SERVER_OSF = 0x00100000,
        SV_TYPE_SERVER_VMS = 0x00200000,
        SV_TYPE_WINDOWS = 0x00400000,
        SV_TYPE_DFS = 0x00800000,
        SV_TYPE_CLUSTER_NT = 0x01000000,
        SV_TYPE_TERMINALSERVER = 0x02000000,
        SV_TYPE_CLUSTER_VS_NT = 0x04000000,
        SV_TYPE_DCE = 0x10000000,
        SV_TYPE_ALTERNATE_XPORT = 0x20000000,
        SV_TYPE_LOCAL_LIST_ONLY = 0x40000000,
        SV_TYPE_DOMAIN_ENUM = 0x80000000,
        SV_TYPE_ALL = 0xFFFFFFFF
    }

    public enum PLATFORM_ID :
uint
    {
        PLATFORM_ID_DOS = 300,
        PLATFORM_ID_OS2 = 400,
        PLATFORM_ID_NT = 500,
        PLATFORM_ID_OSF = 600,
        PLATFORM_ID_VMS = 700
    }
}


We can use the following native methods as follows;

public List<string> GetSqlServers()
{
    List<string> servers = new List<string>();
    int
readed = 0;
    int
total = 0;

    do
    {
        IntPtr
buffer;
        NativeMethods.SERVER_INFO_101
server;
        int retVal = NativeMethods.NetServerEnum(null, 101, out
buffer, -1,
                                ref readed, ref
total,
                                NativeMethods.SV_101_TYPES.SV_TYPE_SQLSERVER, null
, 0);

       
if
(retVal == NativeMethods.ERROR_SUCCESS ||
                    retVal == NativeMethods
.ERROR_MORE_DATA ||
                    readed > 0)
        {
            int
handle = buffer.ToInt32();
            for (int
i = 0; i < readed; i++)
            {
                server = (NativeMethods.SERVER_INFO_101)Marshal
.PtrToStructure(
                                    new IntPtr(handle),
                                    typeof(NativeMethods.SERVER_INFO_101
));

                handle += Marshal
.SizeOf(server);
                servers.Add(server.sv101_name);
            }
        }
        NativeMethods
.NetApiBufferFree(buffer);
    }
    while
(readed < total && readed != 0);

    return
servers;
}


In this example if you call the GetSqlServers method, this will return you the list of the SQL Servers on the network.

Not only for the SQL Servers also you can find any other group of computers by using NetServerEnum method. The SV_101_TYPES enumeration identifies the type of the computer, which you can search for. If you use another value of this enum in GetSqlServers method, you will get the computers list of that kind.

For example; if you are searching for Teminal Servers on the network, use SV_TYPE_TERMINALSERVER while calling NetServerEnum method in the GetSqlServers method. This will returns you the Terminal Servers on the network.

Currently rated 4.5 by 8 people

  • Currently 4.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5