September 2009 - Posts
What is Thread safety?
Thread safety is making sure that shared data (Global/static) of a program is modified by only one thread at a time without any deadlock, starvation, race condition so that program behaves correctly when its methods are called from multiple threads.
What is thread safe class library?
A class library consists of classes with some other stuff. Each class has one or more methods which can be called form different threads concurrently. A class library is called thread safe if every class of it is tread-safe. To be a class thread-safe it has to behave correctly when its methods are called from multiple threads.
To make a class library thread safe, you have to ensure the following two things for every class:
-
Make sure that shared data (Global/static) is not modified by more than one thread concurrently.
-
Ensure that there is no possibility of deadlock, Inconsistency, starvation, race condition.
Implementation Strategy 1(synchronized mechanism):
To implement requirement 1, every concurrent thread has to use some synchronized mechanism like locking when they are executing critical section of code. To ensure requirement 2, you have to make the design carefully. Implementation in this way still has problem because you have to ensure that there is no possibility of deadlock, Inconsistency, starvation, race condition.
Implementation Strategy 2(TLS):
If shared data (Global/static) doesn't need to be share between threads, you can use this strategy. In this strategy you don’t need to worry about deadlock, starvation, race condition. Thread-local storage (TLS) is a concurrent design pattern which ensures shared data (Global/static) are allocated such that there is one instance of shared data (Global/static) per thread.
Using System.Threading namespace one can use TLS to store data that is unique to each thread in multi-threaded applications. According to MSDN the common language runtime allocates a multi-slot data store array to each process when it is created. Thread’s local storage is unique per thread and one’s thread local storage is not available to other threads. Multiple threads can use same named slot (TLS) to store their data without any conflict. Use the AllocateNamedDataSlot method to allocate a named data slot. A static variable tagged with ThreadStaticAttribute is not shared between threads .Thread static members has per-thread storage rather than per AppDomain like normal static members. Thread-relative static fields provide much better performance than data slots, and enable compile-time type checking.
Uniform Naming Convention (UNC): According to wiki, UNC specifies a common syntax to describe the location of a network resource, such as a shared file, directory, or printer in Windows OS.
In client-server development, we can send a server path to its clients as UNC path. Therefore, those clients can access resources from the server. The UNC syntax for Windows systems has the generic form: \\ComputerName\SharedFolder\Resource. However, the safe side is using IP instead of computer name like \\IP\SharedFolder\Resource. Here we are going to see how we can convert a local path (say d:\razan\\x.zip') to its UNC-name ( say '\\192.168.1.56 \razan\x.zip').
Why cannot we use string concatenation to do so?
The shared folder or drive can be shared as something other than the folder name/drive letter. Moreover, it is possible to have one-to-many mapping between local paths and UNC paths.
To implement this functionality, I have written the following class named UNCHelper.
1: class UNCHelper
2: {
3: public static string ConvertLocalFilePathsToUNCPath(string fileName, string sharedFolderpath)
4: {
5: string strPath = fileName.Substring(sharedFolderpath.Length);
6: string sharedFolderPathInUNC = ConvertLocalFolderPathToIPBasedUNCPath(sharedFolderpath);
7: string networkPath = sharedFolderPathInUNC + strPath;
8: return networkPath;
9: }
10:
11: public static string ConvertLocalFolderPathToIPBasedUNCPath(string localFolderName)
12: {
13: string ipBasedUNCPath = string.Empty;
14:
15: ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher("SELECT Name FROM Win32_share WHERE path ='" +
localFolderName.Replace("\\", "\\\\") + "'");
16: ManagementObjectCollection managementObjectCollection = managementObjectSearcher.Get();
17: if (managementObjectCollection.Count != 0)
18: {
19: foreach (ManagementObject item in managementObjectCollection)
20: {
21: String ComputerName = ReturnMachineIP().ToString();// use Dns.GetHostName(); for computername instead of IP
22: ipBasedUNCPath = item["Name"] as String;
23: ipBasedUNCPath = "\\\\" + ComputerName + "\\" + ipBasedUNCPath;
24: return ipBasedUNCPath;
25: }
26: }
27: return ipBasedUNCPath;
28: }
29:
30: private static IPAddress ReturnMachineIP()
31: {
32: String hostName = Dns.GetHostName();
33: IPHostEntry ipEntry = Dns.GetHostEntry(hostName);
34: IPAddress[] addr = ipEntry.AddressList;
35: IPAddress ipV4 = null;
36: foreach (IPAddress item in addr)
37: {
38: if (item.AddressFamily == AddressFamily.InterNetwork)
39: {
40: ipV4 = item;
41: break;
42: }
43:
44: }
45: if (ipV4 == null)
46: {
47: throw new ApplicationException("You have no IP of Version 4.Server can not run witout it");
48: }
49: return ipV4;
50: }
51: }
ManagementObjectSearcher is the class that is commonly used to query disk drives, network adapters, processes, shared folder and many more management objects on a system. To test the code you can use the following line:
1: Console.WriteLine( UNCHelper.ConvertLocalFilePathsToUNCPath("F:\\clustershare\\ razan_3.evp","F:\\clustershare"));
Here clustershare is the shared folder name. It has been tested in Windows XP and Windows Vista.
Hope this will save some of your time.
The Random class defined in the .NET Framework provides functionality to generate pseudo-random number. According to MSDN, the current implementation of the Random class is based on Donald E. Knuth's subtractive random number generator algorithm. The random number generation starts from a seed value. If the same seed is used repeatedly, the same series of numbers is generated. One way to produce different sequences is to make the seed value time-dependent, thereby producing a different series with each new instance of Random.
However, current implementation does not provide the following two functionalities.
-
Picking random numbers from a given set of numbers: For example, you want random number from the given set of numbers. You have a set of numbers like (2, 4, 13, and 21).You would like to pick one number at a time at random from the list.
-
Picking random numbers from a range of numbers with no repetition: Current implementation return random numbers within a range with some duplicate number. For example, you want random number from a range of numbers like (4 to 21). You would like to pick one number at a time at random from that range without any repetition or duplicate
However, these two requirements are easy to implement by using the Random class of the .NET Framework. I needed these two functionalities for one of my project, so I wrote a class to implement these two features. I think that this is a trivial work but I am posting it because it can save some of your time. To implement these two functionalities following class named RandomNumberFromAGivenSetOfNumbers is written.
1: class RandomNumberFromAGivenSetOfNumbers
2: {
3: List<int> _setOfNumbers = new List<int>();
4:
5: public List<int> SetOfNumbers
6: {
7: get { return _setOfNumbers; }
8: set { _setOfNumbers = value; }
9: }
10: Random _random = new Random();
11:
12: public RandomNumberFromAGivenSetOfNumbers()
13: {
14:
15: }
16: public RandomNumberFromAGivenSetOfNumbers(int min, int max)
17: {
18: for (int i = min; i <= max; i++)
19: {
20: _setOfNumbers.Add(i);
21: }
22: }
23:
24: public int Next()
25: {
26: if (_setOfNumbers.Count > 0)
27: {
28: int nextNumberIndex = _random.Next(_setOfNumbers.Count);
29: int val = _setOfNumbers[nextNumberIndex];
30: _setOfNumbers.RemoveAt(nextNumberIndex);
31: return val;
32: }
33: return -1;
34: }
35: }
The used code for testing these two features is in the following
1: static void Main(string[] args)
2: {
3: Console.WriteLine("Picking random numbers from a range of numbers with no repetition(Range is 0-24)");
4: Console.WriteLine();
5: RandomNumberFromAGivenSetOfNumbers rdm = new RandomNumberFromAGivenSetOfNumbers(0, 24);
6: string str = string.Empty;
7: for (int i = 0; i < 25; i++)
8: {
9: str += rdm.Next().ToString() + " ";
10: }
11: Console.WriteLine(str);
12: Console.WriteLine();
13: Console.WriteLine();
14:
15:
16: Console.WriteLine("Picking random numbers from a given set of numbers( 2, 4, 13, and 21)");
17: Console.WriteLine();
18: RandomNumberFromAGivenSetOfNumbers rdm1 = new RandomNumberFromAGivenSetOfNumbers();
19: rdm1.SetOfNumbers.Add(2);
20: rdm1.SetOfNumbers.Add(4);
21: rdm1.SetOfNumbers.Add(13);
22: rdm1.SetOfNumbers.Add(21);
23: string str1 = string.Empty;
24: for (int i = 0; i < 4; i++)
25: {
26: str1 += rdm1.Next().ToString() + " ";
27: }
28: Console.WriteLine(str1);
29:
30: Console.ReadLine();
31: }
The output of the program is in the following:
You can download the sample code from here. This is a very trivial work, but I hope this will save some of your time.
In client server development, we need this feature in many situations including:
-
When client starts before server, it should periodically check whether server is UP or not. As soon as it gets server is up, it will connect with it to do its own business.
-
Sometimes network between server and client can be broken and to reestablish this you can use reachability testing.
This technique can be used in WCF, .net remoting and socket programming. I have used this technique in several applications. Here testing reach ability is done by asynchronous socket programming with timeout for better performance. You can call isServerUp method at certain inteval according to your requirement. The following method checks whether server is reachable or not. If the server is reachable, It indicates that the network and server is ok and we can start doing business with server
1: public static bool isServerUp(string ip, int port, int timout)
2: {
3: IPAddress validIP;
4: if (IPAddress.TryParse(ip, out validIP))
5: {
6: IPEndPoint remoteEndPoint = new IPEndPoint(validIP, port);
7: bool fg = TimeOutSocket.Connect(remoteEndPoint, timout);
8: return fg;
9: }
10: else
11: {
12: return false;
13: }
14:
15: }
You will notice that neither of the two classes, System.Net.Sockets.TcpClient nor System.Net.Sockets.Socket has a timeout to connect a socket. I mean a timeout you can set. .NET Sockets do not provide a Connect Timeout when calling the Connect or BeginConnectmethod while establishing a Synchronous or Asynchronous socket connection. Instead, connect is forced to wait a very long time before an Exception is thrown if the server it tried to connect to is not listening or if there is any network error. The default timeout is 20 - 30 seconds. There is an option in socket library named SocketOptionName.SendTimeout, which is used for timeouts on Send data not initial connects. To get this functionality, I have implemented the following class named TimeOutSocket.
1: class TimeOutSocket
2: {
3: private static bool IsConnectionSuccessful = false;
4: private static Exception socketexception;
5: private static ManualResetEvent TimeoutObject = new ManualResetEvent(false);
6:
7:
8: public static bool Connect(IPEndPoint remoteEndPoint, int timeoutMSec)
9: {
10: TimeoutObject.Reset();
11: socketexception = null;
12:
13: string serverip = Convert.ToString(remoteEndPoint.Address);
14: int serverport = remoteEndPoint.Port;
15: TcpClient tcpclient = new TcpClient();
16:
17: tcpclient.BeginConnect(serverip, serverport, new AsyncCallback(CallBackMethod), tcpclient);
18:
19: if (TimeoutObject.WaitOne(timeoutMSec, false))
20: {
21: if (IsConnectionSuccessful)
22: {
23: tcpclient.Close();
24: return true;
25: }
26: else
27: {
28: tcpclient.Close();
29: return false;
30: }
31: }
32: else
33: {
34: tcpclient.Close();
35: return false;
36: }
37: }
38: private static void CallBackMethod(IAsyncResult asyncresult)
39: {
40: try
41: {
42: IsConnectionSuccessful = false;
43: TcpClient tcpclient = asyncresult.AsyncState as TcpClient;
44:
45: if (tcpclient.Client != null)
46: {
47: tcpclient.EndConnect(asyncresult);
48: IsConnectionSuccessful = true;
49: }
50: }
51: catch (Exception ex)
52: {
53: IsConnectionSuccessful = false;
54: socketexception = ex;
55: }
56: finally
57: {
58: TimeoutObject.Set();
59: }
60: }
61: }
Here ManualResetEvent plays the main role to implement this. It has a method WaitOne which has an overload WaitOne(TimeSpan,Boolean). According to MSDN, aitOne(TimeSpan, Boolean) blocks the current thread until the current instance receives a signal, using a TimeSpan to measure the time interval and specifying whether to exit the synchronization domain before the wait.
So in the main thread, we call TimeoutObject.WaitOne(timeoutMSec, false) to block the main thread until timeout or till the signal has been got using TimeoutObject.Set(). When waitone faces timeout, then it returns timeout exception. Otherwise socket is successfully connected or it faced any network error.
Here BeginConnect of tcpclient is used because this method does not block. After calling BeginConnect, we wait using waitone. If BeginConnect does not complete operation within timeout, then waitone will signal and TimeoutException is returned. IfBeginConnect does complete operation within timeout, then it will signal ManualResetEvent using TimeoutObject.Set() from theCallBackMethod which we passed as delegate in BeginInvoke that references the CallBackMethod to invoke when the operation is complete.
Thanks for reading this write up. I hope that this write up will be helpful for some people. If you guys have any questions, I would love to answer.
When we write client server or peer to peer application, a frequent task is to find the first IP4 address of local machine. A machine has multiple types of addresses besides IP4 and IP6. For this reason, we will first get the address list of the machine then will loop through all the addresses to check whether there is an IP4 address. If found then we will return the first address. Otherwise will return null.
Now the question is how we will detect IP4 address Type. There is an Enumeration named AddressFamily under System.Net.Sockets namespace which specifies the addressing type. The members of AddressFamily Enumeration are in the following:
| Member name | Description |
| Unknown | Unknown address family. |
| Unspecified | Unspecified address family. |
| Unix | Unix local to host address. |
| InterNetwork | Address for IP version 4. |
| ImpLink | ARPANET IMP address. |
| Pup | Address for PUP protocols. |
| Chaos | Address for MIT CHAOS protocols. |
| NS | Address for Xerox NS protocols. |
| Ipx | IPX or SPX address. |
| Iso | Address for ISO protocols. |
| Osi | Address for OSI protocols. |
| Ecma | European Computer Manufacturers Association (ECMA) address. |
| DataKit | Address for Datakit protocols. |
| Ccitt | Addresses for CCITT protocols, such as X.25. |
| Sna | IBM SNA address. |
| DecNet | DECnet address. |
| DataLink | Direct data-link interface address. |
| Lat | LAT address. |
| HyperChannel | NSC Hyperchannel address. |
| AppleTalk | AppleTalk address. |
| NetBios | NetBios address. |
| VoiceView | VoiceView address. |
| FireFox | FireFox address. |
| Banyan | Banyan address. |
| Atm | Native ATM services address. |
| InterNetworkV6 | Address for IP version 6. |
| Cluster | Address for Microsoft cluster products. |
| Ieee12844 | IEEE 1284.4 workgroup address. |
| Irda | IrDA address. |
| NetworkDesigners | Address for Network Designers OSI gateway-enabled protocols. |
| Max | MAX address. |
(The table is stolen from MSDN website)
The member InterNetwork of AddressFamily Enumeration indicates Address for IP version 4.Here the member InterNetwork of AddressFamily Enumeration is used to check whether this is a IP4 address or not. The routine to find the first IP4 Address of the Host (local) machine is in the following:
1: private static IPAddress ReturnMachineIP()
2: {
3: String hostName = Dns.GetHostName();
4: IPHostEntry ipEntry = Dns.GetHostEntry(hostName);
5: IPAddress[] addr = ipEntry.AddressList;
6: IPAddress ipV4 = null;
7: foreach (IPAddress item in addr)
8: {
9: if (item.AddressFamily == AddressFamily.InterNetwork)
10: {
11: ipV4 = item;
12: break;
13: }
14:
15: }
16: if (ipV4 == null)
17: {
18: throw new ApplicationException("You have no IP of Version 4.Server can not run witout it");
19: }
20: return ipV4;
21: }
Hope this will save some of your time.
We can make a deep copy of a WPF object using XamlWriter and XamlReader. Here the XamlWriter.Save is used to serialize the contents of a WPF object into xaml string. XamlReader.Load is used to parse XAML string into a WPF object. To make deep copy of an wpf UIelement , you can use the following method.
1: public UIElement DeepCopy(UIElement element)
2: {
3: string shapestring = XamlWriter.Save(element);
4: StringReader stringReader = new StringReader(shapestring);
5: XmlTextReader xmlTextReader = new XmlTextReader(stringReader);
6: UIElement DeepCopyobject = (UIElement)XamlReader.Load(xmlTextReader);
7: return DeepCopyobject;
8: }
If you would like to make deep copy of WPF objects without XamlWriter, you have to use reflection .For that you have to navigate recursively inside the type to get all Dependency Properties and Dependency Objects as well as plain .net properties.
I love the WPF’s ability to completely restyle a standard control. Each WPF Control has a default Control Template that contains the visual tree of that control to define how it displays itself and its contents. We can change the structure and appearance of a control by modifying the ControlTemplate of that control. We can override the default control template to make it appear exactly as we want. It will only replace the visual tree of the control not the behavior of the control.
In a touch screen application, we usually make bigger size control than the control size of traditional application. Here a custom control template has been made for radio button to use it in touch screen application. Here i did not use any good looking gradient. By using good-looking gradient, you can make this control look stunning.
The used XAML for Radio Button Control Template is in the following
1: <Style TargetType="{x:Type RadioButton}" >
2: <Setter Property="Template">
3: <Setter.Value>
4: <ControlTemplate TargetType="{x:Type RadioButton}">
5: <BulletDecorator Background="Transparent">
6: <BulletDecorator.Bullet>
7: <StackPanel Orientation="Horizontal" >
8: <Grid Width="40" Height="40">
9: <Ellipse Name="MainEllipse" Width="40" Height="40">
10: <Ellipse.Fill>
11: <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
12: <GradientStop Color="#FFC8C8C8" Offset="0"/>
13: <GradientStop Color="#FFF7F7F7" Offset="0.991"/>
14: </LinearGradientBrush>
15: </Ellipse.Fill>
16: </Ellipse>
17: <Ellipse Margin="10,10,10,10" Fill="#C0C0C0" Width="Auto" Height="Auto">
18: </Ellipse>
19: <Ellipse x:Name="Selected" Margin="10,10,10,10" Width="Auto" Height="Auto" >
20: <Ellipse.Fill>
21: <SolidColorBrush Color="Navy" />
22: </Ellipse.Fill>
23: </Ellipse>
24: </Grid>
25: <ContentPresenter Margin="5,0,0,0" VerticalAlignment="Center"/>
26: </StackPanel>
27: </BulletDecorator.Bullet>
28: </BulletDecorator>
29: <ControlTemplate.Triggers>
30: <Trigger Property="IsMouseOver"
31: Value="true">
32: <Setter TargetName="MainEllipse" Property="Fill"
33: Value="LightBlue"/>
34: </Trigger>
35: <Trigger Property="IsChecked" Value="false">
36: <Setter TargetName="Selected" Property="Visibility" Value="Collapsed"/>
37: </Trigger>
38: </ControlTemplate.Triggers>
39: </ControlTemplate>
40: </Setter.Value>
41: </Setter>
42: </Style>
Stack panel is used to stack the visual and the content horizontally. Here we used three ellipses to define the visual. First Ellipse defines the outer elliptical shape. Second one is inner ellipse when radio button is not selected. Third one is also inner ellipse when radio button is selected.
When creating a Control Template, we need to specify the type of object that this template is intended for. The type is simply the same type as the style TargetType="{x:Type RadioButton}.Two triggers are used, one is fired when the radio button is checked and it changes the inner ellipse so that it looks like selected. Another one is mouseover, but in touch screen application, Mouse over has no effect. Content Presenter in the Control Template displays the contents of a Content Control.
You can download the sample code from here. Hope this will save some of your time.
IPv4 address has two basic parts: the network part and the host part. As we know, if network potions of two IPs are same, they are in the same network. By performing and operation between subnet mask and IP address, we can get the network portion of an IP. By this way, we have found the network portions of two IPs. Then just check whether the network portions are equal or not. For this the following code is written:
1: private static bool CheckWhetherInSameNetwork(string firstIP, string subNet, string secondIP )
2: {
3: uint subnetmaskInInt = ConvertIPToUint(subNet);
4: uint firstIPInInt = ConvertIPToUint(firstIP);
5: uint secondIPInInt = ConvertIPToUint(secondIP);
6: uint networkPortionofFirstIP = firstIPInInt & subnetmaskInInt;
7: uint networkPortionofSecondIP = secondIPInInt & subnetmaskInInt;
8: if (networkPortionofFirstIP == networkPortionofSecondIP)
9: return true;
10: else
11: return false;
12: }
13:
14: static public uint ConvertIPToUint(string ipAddress)
15: {
16: System.Net.IPAddress iPAddress = System.Net.IPAddress.Parse(ipAddress);
17: byte[] byteIP = iPAddress.GetAddressBytes();
18: uint ipInUint = (uint)byteIP[3] << 24;
19: ipInUint += (uint)byteIP[2] << 16;
20: ipInUint += (uint)byteIP[1] << 8;
21: ipInUint += (uint)byteIP[0];
22: return ipInUint;
23: }
Hope this will save some of your time.
IP4 addresses are categorized into 5 classes. For the first three classes we have predefined subnet mask. So if we can detect the class of an IP address , we can determine the corresponding subnet mask. The address ranges used for each class are given in the following table (Taken from wiki):
| Class | Leading bits | Start | End | CIDR suffix | Default subnet mask |
| Class A | 0 | 0.0.0.0 | 127.255.255.255 | /8 | 255.0.0.0 |
| Class B | 10 | 128.0.0.0 | 191.255.255.255 | /16 | 255.255.0.0 |
| Class C | 110 | 192.0.0.0 | 223.255.255.255 | /24 | 255.255.255.0 |
| Class D | 1110 | 224.0.0.0 | 239.255.255.255 | /4 | not defined |
| Class E | 1111 | 240.0.0.0 | 255.255.255.255 | /4 | not defined |
To implement so, a class named IPClassTester has been written. The class has two methods: ReturnSubnetmask, ReturnFirtsOctet. The first one takes an IP address and return its corresponding subnet mask. For this it first extracts the first octet of the IP address using the method named ReturnFirtsOctet and then checks the first octet value with the IP4 class information and returns the corresponding subnet mask on match.
1: class IPClassTester
2: {
3: static public string ReturnSubnetmask(String ipaddress)
4: {
5: uint firstOctet = ReturnFirtsOctet(ipaddress);
6: if (firstOctet >= 0 && firstOctet <= 127)
7: return "255.0.0.0";
8: else if (firstOctet >= 128 && firstOctet <= 191)
9: return "255.255.0.0";
10: else if (firstOctet >= 192 && firstOctet <= 223)
11: return "255.255.255.0";
12: else return "0.0.0.0";
13: }
14:
15: static public uint ReturnFirtsOctet(string ipAddress)
16: {
17: System.Net.IPAddress iPAddress = System.Net.IPAddress.Parse(ipAddress);
18: byte[] byteIP = iPAddress.GetAddressBytes();
19: uint ipInUint = (uint)byteIP[0];
20: return ipInUint;
21: }
22: }
Hope this will save some of your time.
According to Wiki, the term IP (Internet Protocol) address spoofing refers to the creation of IP packets with a forged (spoofed) source IP address with the purpose of concealing the identity of the sender or impersonating another computing system. For one of my project, I needed IP spoofing. According to a requirement, I need to commutate with a device over crossover cable for configuring it. But the problem is , when device boots up , it gets an arbitrary IP when it is operating over crossover connection as it cannot contract with DHCP Server. My PC is in a different network from the device. So i cannot communicate with that device thru socket programming. But one thing I can do, i can search the device using some proprietary protocol and find its information like its IP.
As I can get the IP of device, if I change the pc IP according to Device IP so that they are in the same network then I will be able to communicate with the device and configure it. AddIPAddress Function of iphlpapi.dll can be used to add a specified IPv4 address to the specified adapter and DeleteIPAddress function can be used to delete an IP address previously added using AddIPAddress. So using these two functions you can do IP spoofing .Your real IP4 address will be changed for a very short time when you are sending the packet. Another thing to note, a network interface can hold multiple IIP address and holds it in a IP table.
The code that is used is in the following:
1: [DllImport("iphlpapi.dll", SetLastError = true)]
2: static extern UInt32 AddIPAddress(UInt32 Address, UInt32 IpMask, int IfIndex, out IntPtr NTEContext, out IntPtr NTEInstance);
3:
4: [DllImport("iphlpapi.dll", SetLastError = true)]
5: static extern UInt32 DeleteIPAddress(IntPtr NTEContext);
6:
7: static IntPtr ptrNteContext = new IntPtr(0);
8:
9: public static UInt32 AddIPAddressToInterface(string ipAddress, string subnetMask, int ifIndex)
10: {
11: System.Net.IPAddress ipAdd = System.Net.IPAddress.Parse(ipAddress);
12: System.Net.IPAddress subNet = System.Net.IPAddress.Parse(subnetMask);
13: unsafe
14: {
15: int nteContext = 0;
16: int nteInstance = 0;
17: ptrNteContext = new IntPtr(nteContext);
18: IntPtr ptrNteInstance = new IntPtr(nteInstance);
19: return AddIPAddress(IpAddressToUInt32(ipAdd), IpAddressToUInt32(subNet), ifIndex, out ptrNteContext, out ptrNteInstance);
20: }
21: }
22:
23: public static void DeletePreviouslyAddedIP()
24: {
25: DeleteIPAddress(ptrNteContext);
26: }
More Posts
Next page »