Code Optimization

Interesting things about software development and code optimization

MS SQL Batch or Bulk UPDATE and all around EF

Dear friends,


Thank you for comming and here I will show you how to make a huge bulk UPDATE in database from your C# code using Entity Framework.

My issue was about calculation prices for +50K products and then updating these product prices all at once.

Before this optimization SQL Update took more than 60 seconds ( using different approaches and of course you even should not think to do it with EF update/save method at all). After implementation of this approach we get less than 10 seconds for updating +50K products (of course it depends on hosting and environment you use). So what is that?


Table-Valued Parameters

yes, may be you have heard about it but have not understand it enough to use or just have not believed that it would really help you.


So everything is really easy - you create table, put all data you need for your update - it is +50K rows and pass it to your stored procedure that knows how to use it, here is an example:

- create table and columns

                            DataTable tblUpdate = new DataTable();
                            tblUpdate.Columns.Add("Id", typeof(int));               
                            tblUpdate.Columns.Add("DeliveryDateId", typeof(int));   
                            tblUpdate.Columns.Add("OldPrice", typeof(decimal));     
                            tblUpdate.Columns.Add("Price", typeof(decimal));        
                            tblUpdate.Columns.Add("ProductCost", typeof(decimal));  
                            tblUpdate.Columns.Add("AdditionalShippingCharge", typeof(decimal)); 
                            tblUpdate.Columns.Add("DisableBuyButton", typeof(bool));
                            tblUpdate.Columns.Add("Published", typeof(bool));       
                            tblUpdate.Columns.Add("AdminComment", typeof(string));  
                            tblUpdate.Columns.Add("UpdatedOnUtc", typeof(DateTime));

- add rows

...
                            object[] row = new object[10];                            
                            ...
                            ...
                            tblUpdate.Rows.Add(row);
                            ...

- now it is time to push it to SQL

                            var dataSettings = Core.Data.DataSettingsManager.LoadSettings();

                            using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(dataSettings.DataConnectionString))
                            {
                                conn.Open();
                                
                                //check if table-valued type is already exists
                                using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(
@"IF TYPE_ID(N'TargetUDT') IS NULL CREATE TYPE [TargetUDT] AS TABLE
(
Id int not null,
DeliveryDateId int not null,
OldPrice decimal(18,4) not null,
Price decimal(18,4) not null,
ProductCost decimal(18,4) not null,
AdditionalShippingCharge decimal(18,4) not null,
DisableBuyButton bit not null,
Published bit not null,
AdminComment nvarchar(max) null,
UpdatedOnUtc datetime not null
);", conn))
                                {
                                    cmd.CommandType = CommandType.Text;
                                    cmd.ExecuteNonQuery();
                                }

//create or update stored procedure using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand( @"CREATE OR ALTER PROCEDURE usp_UpdateAllProdPrices (@tvpUpdateProducts [TargetUDT] READONLY) AS BEGIN UPDATE dbo.Product SET Product.DeliveryDateId = ec.DeliveryDateId, Product.OldPrice = ec.OldPrice, Product.Price = ec.Price, Product.ProductCost = ec.ProductCost, Product.AdditionalShippingCharge = ec.AdditionalShippingCharge, Product.DisableBuyButton = ec.DisableBuyButton, Product.Published = ec.Published, Product.AdminComment = ec.AdminComment, Product.UpdatedOnUtc = ec.UpdatedOnUtc FROM @tvpUpdateProducts AS ec INNER JOIN dbo.Product ON dbo.Product.Id = ec.Id END", conn)) { cmd.CommandType = CommandType.Text; cmd.ExecuteNonQuery(); } //run the stored procedure and pass the all data as table-valued parameter using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand( @"usp_UpdateAllProdPrices", conn)) { System.Data.SqlClient.SqlParameter tvpParam = cmd.Parameters.AddWithValue("@tvpUpdateProducts", tblUpdate); tvpParam.SqlDbType = SqlDbType.Structured; tvpParam.TypeName = "[TargetUDT]"; cmd.CommandType = System.Data.CommandType.StoredProcedure; cmd.ExecuteNonQuery(); } conn.Close(); }


That's it guys enjoy your super-fast bulk update :)




Thank you and see you :)


1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



Top 1 Anti-Spam Contact Form

The Best Anti-Spam Contact Form for Your Website 


Hello friends,

today I'm going to share my experience with implementing the best, in my opinion, anti-spam mechanism for web contact form.

There is well known problem - when you have a contact form on your website then you will get a lot of spam submitted via the form action url on your website and this is very annoying as for me. So I started thinking on how to do it in a way so I would get no spam at all or as less as possible at least.

First thing that came in my mind was that we would need a dynamic and random form action url for the form submission that will return HTTP 404 not found in case user would not pass human-like verification with a captcha or would try to guess the url.

As I work with C#.NET + MVC I started creating such solution with ASP.NET MVC and actually here is what I came up to.

First thing we need is to register our website for google reCAPTCHA v2, get public and secret keys and add reCAPTCHA to an our contact form. Note that in our case we need to render reCAPTCHA by hand and here is the Contact View html:


@section head
{
    <script src="https://www.google.com/recaptcha/api.js?onload=renderRecaptcha&render=explicit" async defer></script>
}

...

    @using (Html.BeginForm("", "", FormMethod.Post, new { id="contactForm" }))
    {
        @Html.AntiForgeryToken()

        ...

        <div id="ReCaptchContainer"></div>

        ...
        
        <input type="submit" value="Send" />
    }

...

@section scripts
{
    <script>
        var your_site_key = '.....-....';
        var canProceed = false;

        var reCaptchaCallback = function (response) {
            //lets go to server, validate a token and return a random url if succeed
            $.ajax({
                method: "POST",
                url: "/Contact/IsReCaptchValid",
                cache: false,
                data: {
                    gRecaptchaResponse: response
                }
            }).done(function (html) {
                if (html != "none") {
                    $("#contactForm").attr("action", html);
                    canProceed = true;
                    $("#submit").removeClass("disabled");
                    $("#submit").addClass("btn-success");
                }
            });
        };

        var renderRecaptcha = function () {
            //lets render our captcha
            grecaptcha.render('ReCaptchContainer', {
                'sitekey': your_site_key,
                'callback': reCaptchaCallback
            });
        };

        $(document).ready(function () {
            $("input[type='submit']").on("click", function (e) {

                ...

                if (canProceed != true) {
                    //CAPTCHA has not been validated yet
                    e.stopPropagation();
                    return false;
                }
            });
        });
    </script>
}

Here we load google api javascript file, run captcha rendering and attach a handler for validation response that we will use to send validation token to our back-end, validate it and return a new dynamic random URL for our <form> to submit data to.

Here is the server side controller action for reCAPTCHA validation:

        public ActionResult IsReCaptchValid(string gRecaptchaResponse)
        { //check referrer url to see if this request came from our own website
            if (Request.UrlReferrer == null || string.IsNullOrEmpty(Request.UrlReferrer.AbsolutePath) ||
                     !(Request.UrlReferrer.ToString().ToLowerInvariant().StartsWith(Extensions.Extensions.DomainName + "/contact") ||
                     Request.UrlReferrer.ToString().ToLowerInvariant().StartsWith(Extensions.Extensions.DomainName2 + "/contact")))
            {
                return HttpNotFound("Resource was not found");
            }
            string result = "none";
            var captchaResponse = gRecaptchaResponse;
            
            var apiUrl = "https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}";
            var requestUri = string.Format(apiUrl, secretKey, captchaResponse);
            var request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(requestUri);
            using (System.Net.WebResponse response = request.GetResponse())
            {
                using (System.IO.StreamReader stream = new System.IO.StreamReader(response.GetResponseStream()))
                {
                    JObject jResponse = JObject.Parse(stream.ReadToEnd());
                    var isSuccess = jResponse.Value<bool>("success");
                    if (isSuccess)
                    { //store token in session to re-validate later
                        Session["g-recaptcha-response"] = gRecaptchaResponse; //generate random url
                        result = "/Contact/" + 
                            ((char)rnd.Next(0x61, 0x7b)) + "" + //random char a-z
                            ((char)rnd.Next(0x61, 0x7b)) + "" +
                            ((char)rnd.Next(0x61, 0x7b)) + "" +
                            ((char)rnd.Next(0x61, 0x7b)) + "" +
                            ((char)rnd.Next(0x61, 0x7b)) + "" +
                            ((char)rnd.Next(0x61, 0x7b)) + "" +
                            ((char)rnd.Next(0x61, 0x7b)) + "" +
                            ((char)rnd.Next(0x61, 0x7b)) + "" ; //store the random url to validate later
                        Session["contactFormAction"] = result;
                    }
                }
            }
            return Content(result);
        }

As you may guessed this will validate google reCAPTCHA token and generate a random url like /Contact/edvbbgrq

Next step will be to accept POST request with all the data, validate and process it.
To be able to accept random urls like /Contact/edvbbgrq in one controller and one action you will have to define some routes, so lets define them now in our RouteConfig.cs:

            //route to accept /Contact/Contact get request and return our contact form/view
            routes.MapRoute(
                name: "Contact1",
                url: "Contact/Contact",
                defaults: new { controller = "Contact", action = "Contact" }
                ); //route to accept /Contact/IsReCaptchValid request and return our random urls
            routes.MapRoute(
                name: "Contact2",
                url: "Contact/IsReCaptchValid",
                defaults: new { controller = "Contact", action = "IsReCaptchValid" }
                ); //route to accept our random urls and submit contact requests
            routes.MapRoute(
                name: "CContact",
                url: "Contact/{*slug}",
                defaults: new { controller = "Contact", action = "CContact", slug = System.Web.Http.RouteParameter.Optional }
                );

And actually final step is implementing our POST action to accept random-url submit requests:

        //to return view Contact in Get and POSTback requests
        public ActionResult CContact(string slug = null)
        {
            return View("Contact");
        }
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult CContact(string slug, string name, string subject, string message, string email)
        { //check if this request is from our own website
            if (Request.UrlReferrer == null || string.IsNullOrEmpty(Request.UrlReferrer.AbsolutePath) ||
                     !(Request.UrlReferrer.ToString().ToLowerInvariant().StartsWith(Extensions.Extensions.DomainName + "/contact") ||
                     Request.UrlReferrer.ToString().ToLowerInvariant().StartsWith(Extensions.Extensions.DomainName2 + "/contact")))
            {
                return HttpNotFound("Resource was not found");
            }
            //get previously stored random url
            string view = Session["contactFormAction"] as string;
            if (string.IsNullOrEmpty(view))
            {
                return HttpNotFound("Resource was not found");
            }
            view = view.Replace("/Contact/", string.Empty); //get random part from route to compare
            if(RouteData.GetRequiredString("slug") != view)
                return HttpNotFound("Resource was not found"); //just in case let's check the token one more time
            var captchaResponse = Request.Form["g-recaptcha-response"];
            if((string)Session["g-recaptcha-response"]!= captchaResponse)
            {
                return HttpNotFound("Resource was not found");
            }

            ... //do whatever you need to process request ...
            ViewBag.Message = "Thank you, your request has been submitted.";

            return View("Contact");
        }

That's it. Now you have dynamic action form url and this url is generated after human-validation only so it will be impossible or almost impossible at least  for spammers to send spam requests.

Thank you and see you :)



1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



C#.NET and Cross-Platform application

Today I'm going to share my experience with c#.net and cross-platform desktop application.

I did write a simple and small windows desktop application under Visual Studio 2017 Community Edition and was wondering if I could run it on Linux Ubuntu and Mac.

The application was just one form and a few combo boxes and buttons app and used Newtonsoft.JSON and web communication. So nothing platform-dependent (except windows forms and controls itself ;) ) and I was almost sure it should work on linux and mac.




First thing I did remember was Mono: https://www.mono-project.com/ and another thing was Gtk#.

I did start with Gtk# and did play a few hours with it. Then I just ported my code to the standard Windows Form Application project and framework .NET Framework 7 just to find out how it would go :)


So I started trying it on Ubuntu. To run simple Windows Forms EXE application on Ubuntu you need mono:

sudo apt-get --assume-yes install mono-runtime

Now I tried to run my exe:

mono MyApp.exe

And I got the following error:

Could not load signature of System.Windows.Forms.Control:GetAccessibilityObjectById due to: Could not load file or assembly or one of its dependencies. assembly:Accessibility, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a type:<unknown type> member:<none>
Unhandled Exception:
System.TypeLoadException: Could not load type 'MyApp.Form1' from assembly 'MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

"Hmm, what does it mean?" As mono should already have all this System.*.dll and Microsoft.*.dll libraries I just deleted everything except EXE and Newtonsoft.Json.dll and tried one more time and I got another exception:

Unhandled Exception:
System.IO.FileNotFoundException: Could not load file or assembly or one of its dependencies.
File name: 'System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
I did google a little bit and found some posts about mono and that mono-complete had much more libraries needed to run .Net.
So I installed mono-complete:

sudo apt-get --assume-yes install mono-complete
And tried to run my EXE and what do you think? Sure - not so easy ;), here is another exception I got:

Unhandled Exception:
System.TypeInitializationException: The type initializer for 'System.Windows.Forms.XplatUI' threw an exception. ---> System.TypeInitializationException: The type initializer for 'System.Windows.Forms.X11DesktopColors' threw an exception. ---> System.TypeInitializationException: The type initializer for 'System.Console' threw an exception. ---> System.TypeInitializationException: The type initializer for 'System.ConsoleDriver' threw an exception. ---> System.Exception: Magic number is wrong: 542
  at System.TermInfoReader.ReadHeader (System.Byte[] buffer, System.Int32& position) [0x0002b] in <8f2c484307284b51944a1a13a14c0266>:0 
  at System.TermInfoReader..ctor (System.String term, System.String filename) [0x00065] in <8f2c484307284b51944a1a13a14c0266>:0 
  at System.TermInfoDriver..ctor (System.String term) [0x00058] in <8f2c484307284b51944a1a13a14c0266>:0 
  at System.ConsoleDriver.CreateTermInfoDriver (System.String term) [0x00000] in <8f2c484307284b51944a1a13a14c0266>:0 
  at System.ConsoleDriver..cctor () [0x00062] in <8f2c484307284b51944a1a13a14c0266>:0 
   --- End of inner exception stack trace ---
  at System.Console.SetupStreams (System.Text.Encoding inputEncoding, System.Text.Encoding outputEncoding) [0x0000a] in <8f2c484307284b51944a1a13a14c0266>:0 
  at System.Console..cctor () [0x000a8] in <8f2c484307284b51944a1a13a14c0266>:0 
   --- End of inner exception stack trace ---
  at System.Windows.Forms.X11DesktopColors..cctor () [0x001bb] in <d5b72d15d4f7424c8a1538e3f19ec2e3>:0 
   --- End of inner exception stack trace ---
  at System.Windows.Forms.XplatUIX11..ctor () [0x0007c] in <d5b72d15d4f7424c8a1538e3f19ec2e3>:0 
  at System.Windows.Forms.XplatUIX11.GetInstance () [0x0001c] in <d5b72d15d4f7424c8a1538e3f19ec2e3>:0 
  at System.Windows.Forms.XplatUI..cctor () [0x0007d] in <d5b72d15d4f7424c8a1538e3f19ec2e3>:0 
   --- End of inner exception stack trace ---
  at System.Windows.Forms.Application.EnableVisualStyles () [0x00006] in <d5b72d15d4f7424c8a1538e3f19ec2e3>:0 
  at MyApp.Program.Main () [0x00000] in <33f4886a9603454889cff03ba442909e>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: System.TypeInitializationException: The type initializer for 'System.Windows.Forms.XplatUI' threw an exception. ---> System.TypeInitializationException: The type initializer for 'System.Windows.Forms.X11DesktopColors' threw an exception. ---> System.TypeInitializationException: The type initializer for 'System.Console' threw an exception. ---> System.TypeInitializationException: The type initializer for 'System.ConsoleDriver' threw an exception. ---> System.Exception: Magic number is wrong: 542
  at System.TermInfoReader.ReadHeader (System.Byte[] buffer, System.Int32& position) [0x0002b] in <8f2c484307284b51944a1a13a14c0266>:0 
  at System.TermInfoReader..ctor (System.String term, System.String filename) [0x00065] in <8f2c484307284b51944a1a13a14c0266>:0 
  at System.TermInfoDriver..ctor (System.String term) [0x00058] in <8f2c484307284b51944a1a13a14c0266>:0 
  at System.ConsoleDriver.CreateTermInfoDriver (System.String term) [0x00000] in <8f2c484307284b51944a1a13a14c0266>:0 
  at System.ConsoleDriver..cctor () [0x00062] in <8f2c484307284b51944a1a13a14c0266>:0 
   --- End of inner exception stack trace ---
  at System.Console.SetupStreams (System.Text.Encoding inputEncoding, System.Text.Encoding outputEncoding) [0x0000a] in <8f2c484307284b51944a1a13a14c0266>:0 
  at System.Console..cctor () [0x000a8] in <8f2c484307284b51944a1a13a14c0266>:0 
   --- End of inner exception stack trace ---
  at System.Windows.Forms.X11DesktopColors..cctor () [0x001bb] in <d5b72d15d4f7424c8a1538e3f19ec2e3>:0 
   --- End of inner exception stack trace ---
  at System.Windows.Forms.XplatUIX11..ctor () [0x0007c] in <d5b72d15d4f7424c8a1538e3f19ec2e3>:0 
  at System.Windows.Forms.XplatUIX11.GetInstance () [0x0001c] in <d5b72d15d4f7424c8a1538e3f19ec2e3>:0 
  at System.Windows.Forms.XplatUI..cctor () [0x0007d] in <d5b72d15d4f7424c8a1538e3f19ec2e3>:0 
   --- End of inner exception stack trace ---
  at System.Windows.Forms.Application.EnableVisualStyles () [0x00006] in <d5b72d15d4f7424c8a1538e3f19ec2e3>:0 
  at MyApp.Program.Main () [0x00000] in <33f4886a9603454889cff03ba442909e>:0 
"God! What are you even talking about?" - I did google a little bit more and decided to try one suggestion about some additional libraries that might be required to run .NET application, here you are:

sudo apt-get --assume-yes install libappindicator0.1-cil-dev
sudo apt-get --assume-yes install libgtk2.0-cil
sudo apt-get --assume-yes install libmono-posix4.0-cil

some of the libraries were already installed but just in case I write them here anyway.

"Lets run" I thought and tried again. "Wow! It works". Cool!

Sometime it gave me a error even my application ran successfully, something like:

Failed to load module "canberra-gtk-module"

so I did find out that it required one more library:

sudo apt-get install libcanberra-gtk-module libcanberra-gtk3-module


Finally I came to the following - you need to install some libraries and mono itself firstly:

sudo apt-get update
sudo apt-get --assume-yes install mono-runtime
sudo apt-get --assume-yes install mono-complete

sudo apt --assume-yes install libappindicator0.1-cil-dev
sudo apt --assume-yes install libgtk2.0-cil
sudo apt --assume-yes install libmono-posix4.0-cil

After that I was able to run my EXE application from command line (make sure your Terminal is pointed to the EXE folder) like that:

mono MyApp.EXE


And I was really impressed when it brought up windows form with buttons combos etc.

Even more it did communicate good via internet and JSON was working as well :) 

and this is for EXE compiled for .Net Framework 7





Then I did start trying similar things on Mac mini with Mac OS X 10.13 but unfortunately with no luck :(

I did try a few cases and was trying to resolve some issues, missed libraries, etc but unfortunately 

I came up to that that it gave just exception stack trace with errors :(


Not sure if I will continue trying to find out a way to run it under Mac but I any success I will let you know ASAP ;)


Thank you


1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



Get stack trace of frozen processes especially for asp.net application pools

There are so many times you need to get a place where your frozen process stuck aren't?

Especially if this is a production server or remote environment. So what to do?


I have faced this problem myself and created a small tool that gets stack trace from process by its name.

We will need the following instruments:

- Microsoft.Diagnostics.Runtime.dll

- System.Management.dll


And some code to find a process and get its stack trace.

        private string CatchStacktrace(string domainName)
        {
            int pid = -1;
            var procs = System.Diagnostics.Process.GetProcessesByName("w3wp");

            var proc = procs.FirstOrDefault(p => GetProcessOwner(p.Id).StartsWith(domainName));
            if (proc == null)
                return string.Format("User Name not found: {0}", domainName);

            pid = proc.Id;

            if (pid < 1)
                return string.Format("Process w3wp.exe not found: {0}", domainName);

            StringBuilder sb = new StringBuilder();
            sb.AppendLine(domainName);
            sb.AppendLine(string.Empty);

            using (var tdata = DataTarget.AttachToProcess(pid, 3000))
            {
                // Dump CLR info
                var clrVersion = tdata.ClrVersions.First();
                var dacInfo = clrVersion.DacInfo;

                sb.AppendLine("# CLR Info");
                sb.AppendLine(string.Format("Version:       {0}", clrVersion.Version));
                sb.AppendLine(string.Format("Filesize:      {0:X}", dacInfo.FileSize));
                sb.AppendLine(string.Format("Timestamp:     {0:X}", dacInfo.TimeStamp));
                sb.AppendLine(string.Format("Dac file:      {0}", dacInfo.FileName));

                sb.AppendLine(string.Empty);

                var runtime = clrVersion.CreateRuntime();
                var appDomain = runtime.AppDomains.First();

                sb.AppendLine(string.Format("# Runtime Info"));
                sb.AppendLine(string.Format("AppDomain:     {0}", appDomain.Name));
                sb.AppendLine(string.Format("Address:       {0}", appDomain.Address));
                sb.AppendLine(string.Format("Configuration: {0}", appDomain.ConfigurationFile));
                sb.AppendLine(string.Format("Directory:     {0}", appDomain.ApplicationBase));

                sb.AppendLine(string.Empty);

                // Dump thread info
                sb.AppendLine("## Threads");
                sb.AppendLine(string.Format("Thread count:  {0}", runtime.Threads.Count));
                sb.AppendLine(string.Empty);
                foreach (var thread in runtime.Threads)
                {
                    sb.AppendLine(string.Format("### Thread     {0}", thread.OSThreadId));
                    sb.AppendLine(string.Format("Thread type:   {0}",
                                            thread.IsBackground ? "Background"
                                          : thread.IsGC ? "GC"
                                          : "Foreground"));
                    var blocks = thread.BlockingObjects;
                    if (blocks != null)
                    {
                        foreach(var block in blocks)
                        {
                            sb.AppendLine(string.Format("Blocked by:  {0}   reason: {1}", block.ToString(), block.Reason.ToString()));
                        }
                    }

                    sb.AppendLine(string.Empty);
                    sb.AppendLine("Stack trace:");
                    foreach (var stackFrame in thread.EnumerateStackTrace())
                    {
                        sb.AppendLine(string.Format("* {0}", stackFrame.DisplayString));
                    }

                    sb.AppendLine(string.Empty);
                    sb.AppendLine(string.Empty);
                }
            }

            return sb.ToString();
        }

        string[] argList = new string[] { string.Empty, string.Empty };
        ManagementObjectCollection processList = null;
        ManagementObjectSearcher searcher = null;
        string query = "Select * From Win32_Process Where ProcessID = ";
        public string GetProcessOwner(int processId)
        {
            searcher = new ManagementObjectSearcher(query + processId);
            processList = searcher.Get();

            foreach (ManagementObject obj in processList)
            {
                argList[0] = string.Empty;
                argList[1] = string.Empty;
                int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList));
                if (returnVal == 0)
                {
                    return argList[0];
                }
            }

            return "NO OWNER";
        }


As you know asp.net applications all have w3wp process name and run under its own user name usually with the same name as website name. So to find w3wp process we will pass its username like "ok.unsode.com" to the CatchStacktrace method.

If appropriate w3wp process has been found then you will get something like that:



ok.unsode.com


# CLR Info

Version:       v4.7.2650.00

Filesize:      9E8000

Timestamp:     5AB1C520

Dac file:      mscordacwks_Amd64_Amd64_4.7.2650.00.dll


# Runtime Info

AppDomain:     DefaultDomain

Address:       2017397101184

Configuration: w3wp.exe.config

Directory:     c:\windows\system32\inetsrv\


## Threads

Thread count:  85


### Thread     8824

Thread type:   Background


Stack trace:



### Thread     7484

Thread type:   Background


Stack trace:

* DebuggerU2MCatchHandlerFrame



### Thread     9036

Thread type:   Background


Stack trace:



### Thread     7744

Thread type:   Background


Stack trace:



### Thread     13420

Thread type:   Background


Stack trace:



### Thread     6336

Thread type:   Background


Stack trace:

* System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].Insert(System.__Canon, System.__Canon, Boolean)

* MrCMS.Indexing.Management.GetLuceneIndexSearcher.Get(System.String)

* MrCMS.Indexing.Querying.Searcher`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].Search(Lucene.Net.Search.Query, Int32, System.Nullable`1<Int32>, Lucene.Net.Search.Filter, Lucene.Net.Search.Sort)

* MrCMS.Web.Apps.Ecommerce.Services.Products.ProductSearchIndexService.SearchProducts(MrCMS.Web.Apps.Ecommerce.Models.ProductSearchQuery)

* MrCMS.Web.Apps.Ecommerce.Controllers.ProductSearchController.ProductsIndexSearch()

* DynamicClass.lambda_method(System.Runtime.CompilerServices.Closure, System.Web.Mvc.ControllerBase, System.Object[])

* System.Web.Mvc.ReflectedActionDescriptor.Execute(System.Web.Mvc.ControllerContext, System.Collections.Generic.IDictionary`2<System.String,System.Object>)

* System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(System.Web.Mvc.ControllerContext, System.Web.Mvc.ActionDescriptor, System.Collections.Generic.IDictionary`2<System.String,System.Object>)

* System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(System.IAsyncResult, ActionInvocation)

* System.Web.Mvc.Async.AsyncResultWrapper+WrappedAsyncResult`2[[System.__Canon, mscorlib],[System.Web.Mvc.Async.AsyncControllerActionInvoker+ActionInvocation, System.Web.Mvc]].CallEndDelegate(System.IAsyncResult)

* System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(System.IAsyncResult)

* System.Web.Mvc.Async.AsyncControllerActionInvoker+AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d()

* System.Web.Mvc.Async.AsyncControllerActionInvoker+AsyncInvocationWithFilters+<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()

* System.Web.Mvc.Async.AsyncControllerActionInvoker+AsyncInvocationWithFilters+<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()

* System.Web.Mvc.Async.AsyncControllerActionInvoker+AsyncInvocationWithFilters+<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()

* System.Web.Mvc.Async.AsyncControllerActionInvoker+AsyncInvocationWithFilters+<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()

* System.Web.Mvc.Async.AsyncControllerActionInvoker+AsyncInvocationWithFilters+<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()

* System.Web.Mvc.Async.AsyncControllerActionInvoker+AsyncInvocationWithFilters+<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()

* System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(System.IAsyncResult)

* System.Web.Mvc.Async.AsyncControllerActionInvoker+<>c__DisplayClass21+<>c__DisplayClass2b.<BeginInvokeAction>b__1c()

* System.Web.Mvc.Async.AsyncControllerActionInvoker+<>c__DisplayClass21.<BeginInvokeAction>b__1e(System.IAsyncResult)

* System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(System.IAsyncResult)

* System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(System.IAsyncResult, ExecuteCoreState)

* System.Web.Mvc.Async.AsyncResultWrapper+WrappedAsyncVoid`1[[System.Web.Mvc.Controller+ExecuteCoreState, System.Web.Mvc]].CallEndDelegate(System.IAsyncResult)

* System.Web.Mvc.Controller.EndExecuteCore(System.IAsyncResult)

* System.Web.Mvc.Async.AsyncResultWrapper+WrappedAsyncVoid`1[[System.__Canon, mscorlib]].CallEndDelegate(System.IAsyncResult)

* System.Web.Mvc.Controller.EndExecute(System.IAsyncResult)

* System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(System.IAsyncResult, ProcessRequestState)

* System.Web.Mvc.Async.AsyncResultWrapper+WrappedAsyncVoid`1[[System.Web.Mvc.MvcHandler+ProcessRequestState, System.Web.Mvc]].CallEndDelegate(System.IAsyncResult)

* System.Web.Mvc.MvcHandler.EndProcessRequest(System.IAsyncResult)

* System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerWrapper+<>c__DisplayClass4.<Wrap>b__3()

* System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerWrapper.Wrap[[System.__Canon, mscorlib]](System.Func`1<System.__Canon>)

* System.Web.HttpServerUtility.ExecuteInternal(System.Web.IHttpHandler, System.IO.TextWriter, Boolean, Boolean, System.Web.VirtualPath, System.Web.VirtualPath, System.String, System.Exception, System.String)

* System.Web.HttpServerUtility.Execute(System.Web.IHttpHandler, System.IO.TextWriter, Boolean, Boolean)

* System.Web.HttpServerUtility.Execute(System.Web.IHttpHandler, System.IO.TextWriter, Boolean)

* System.Web.Mvc.Html.ChildActionExtensions.ActionHelper(System.Web.Mvc.HtmlHelper, System.String, System.String, System.Web.Routing.RouteValueDictionary, System.IO.TextWriter)

* System.Web.Mvc.Html.ChildActionExtensions.RenderAction(System.Web.Mvc.HtmlHelper, System.String, System.String)

* ASP._Page_Apps_Core_Views_Shared__BaseLayout_cshtml.Execute()

* System.Web.WebPages.WebPageBase.ExecutePageHierarchy()

* System.Web.Mvc.WebViewPage.ExecutePageHierarchy()

* System.Web.WebPages.WebPageBase.ExecutePageHierarchy(System.Web.WebPages.WebPageContext, System.IO.TextWriter, System.Web.WebPages.WebPageRenderingBase)

* System.Web.WebPages.WebPageBase+<>c__DisplayClass3.<RenderPageCore>b__2(System.IO.TextWriter)

* System.Web.WebPages.WebPageBase.Write(System.Web.WebPages.HelperResult)

* System.Web.WebPages.WebPageBase.RenderSurrounding(System.String, System.Action`1<System.IO.TextWriter>)

* System.Web.WebPages.WebPageBase.PopContext()

* System.Web.Mvc.ViewResultBase.ExecuteResult(System.Web.Mvc.ControllerContext)

* System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(System.Collections.Generic.IList`1<System.Web.Mvc.IResultFilter>, Int32, System.Web.Mvc.ResultExecutingContext, System.Web.Mvc.ControllerContext, System.Web.Mvc.ActionResult)

* System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(System.Collections.Generic.IList`1<System.Web.Mvc.IResultFilter>, Int32, System.Web.Mvc.ResultExecutingContext, System.Web.Mvc.ControllerContext, System.Web.Mvc.ActionResult)

* System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(System.Collections.Generic.IList`1<System.Web.Mvc.IResultFilter>, Int32, System.Web.Mvc.ResultExecutingContext, System.Web.Mvc.ControllerContext, System.Web.Mvc.ActionResult)

* System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(System.Collections.Generic.IList`1<System.Web.Mvc.IResultFilter>, Int32, System.Web.Mvc.ResultExecutingContext, System.Web.Mvc.ControllerContext, System.Web.Mvc.ActionResult)

* System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(System.Collections.Generic.IList`1<System.Web.Mvc.IResultFilter>, Int32, System.Web.Mvc.ResultExecutingContext, System.Web.Mvc.ControllerContext, System.Web.Mvc.ActionResult)

* System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(System.Collections.Generic.IList`1<System.Web.Mvc.IResultFilter>, Int32, System.Web.Mvc.ResultExecutingContext, System.Web.Mvc.ControllerContext, System.Web.Mvc.ActionResult)

* System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(System.Web.Mvc.ControllerContext, System.Collections.Generic.IList`1<System.Web.Mvc.IResultFilter>, System.Web.Mvc.ActionResult)

* System.Web.Mvc.Async.AsyncControllerActionInvoker+<>c__DisplayClass21.<BeginInvokeAction>b__1e(System.IAsyncResult)

* System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(System.IAsyncResult)

* System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(System.IAsyncResult, ExecuteCoreState)

* System.Web.Mvc.Async.AsyncResultWrapper+WrappedAsyncVoid`1[[System.Web.Mvc.Controller+ExecuteCoreState, System.Web.Mvc]].CallEndDelegate(System.IAsyncResult)

* System.Web.Mvc.Controller.EndExecuteCore(System.IAsyncResult)

* System.Web.Mvc.Async.AsyncResultWrapper+WrappedAsyncVoid`1[[System.__Canon, mscorlib]].CallEndDelegate(System.IAsyncResult)

* System.Web.Mvc.Controller.EndExecute(System.IAsyncResult)

* System.Web.Mvc.Async.AsyncResultWrapper+WrappedAsyncResultBase`1[[System.Web.Mvc.Async.AsyncVoid, System.Web.Mvc]].Begin(System.AsyncCallback, System.Object, Int32)

* System.Web.Mvc.Controller.BeginExecute(System.Web.Routing.RequestContext, System.AsyncCallback, System.Object)

* MrCMS.Website.Routing.MrCMSStandardRouteHandler.Handle(System.Web.Routing.RequestContext)

* MrCMS.Website.Routing.MrCMSHttpHandler.ProcessRequest(System.Web.Routing.RequestContext)

* System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()

* System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep)

* System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)

* System.Web.HttpApplication+PipelineStepManager.ResumeSteps(System.Exception)

* System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext, System.AsyncCallback)

* System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest, System.Web.HttpContext)

* System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)

* System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)

* DomainNeutralILStubClass.IL_STUB_ReversePInvoke(Int64, Int64, Int64, Int32)

* InlinedCallFrame

* InlinedCallFrame

* DomainNeutralILStubClass.IL_STUB_PInvoke(IntPtr, System.Web.RequestNotificationStatus ByRef)

* System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)

* System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)

* DomainNeutralILStubClass.IL_STUB_ReversePInvoke(Int64, Int64, Int64, Int32)

* ContextTransitionFrame



### Thread     9976

Thread type:   Background


Stack trace:



### Thread     11760

Thread type:   Background


Stack trace:



### Thread     6112

Thread type:   Background


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     16772

Thread type:   Background


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     8280

Thread type:   Background


Stack trace:



### Thread     12476

Thread type:   Background


Stack trace:

* System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].Remove(System.__Canon)

* MrCMS.Indexing.Management.GetLuceneIndexSearcher.Reset(System.String)

* MrCMS.Indexing.Management.IndexManager`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].<Optimise>b__35_0()

* MrCMS.Indexing.Management.IndexResult.GetResult(System.Action)

* MrCMS.Tasks.OptimiseIndexesController.Execute(System.String)

* DynamicClass.lambda_method(System.Runtime.CompilerServices.Closure, System.Web.Mvc.ControllerBase, System.Object[])

* System.Web.Mvc.ReflectedActionDescriptor.Execute(System.Web.Mvc.ControllerContext, System.Collections.Generic.IDictionary`2<System.String,System.Object>)

* System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(System.Web.Mvc.ControllerContext, System.Web.Mvc.ActionDescriptor, System.Collections.Generic.IDictionary`2<System.String,System.Object>)

* System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(System.IAsyncResult, ActionInvocation)

* System.Web.Mvc.Async.AsyncResultWrapper+WrappedAsyncResult`2[[System.__Canon, mscorlib],[System.Web.Mvc.Async.AsyncControllerActionInvoker+ActionInvocation, System.Web.Mvc]].CallEndDelegate(System.IAsyncResult)

* System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(System.IAsyncResult)

* System.Web.Mvc.Async.AsyncControllerActionInvoker+AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d()

* System.Web.Mvc.Async.AsyncControllerActionInvoker+AsyncInvocationWithFilters+<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()

* System.Web.Mvc.Async.AsyncControllerActionInvoker+AsyncInvocationWithFilters+<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()

* System.Web.Mvc.Async.AsyncControllerActionInvoker+AsyncInvocationWithFilters+<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()

* System.Web.Mvc.Async.AsyncControllerActionInvoker+AsyncInvocationWithFilters+<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()

* System.Web.Mvc.Async.AsyncControllerActionInvoker+AsyncInvocationWithFilters+<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()

* System.Web.Mvc.Async.AsyncControllerActionInvoker+AsyncInvocationWithFilters+<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()

* System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(System.IAsyncResult)

* System.Web.Mvc.Async.AsyncControllerActionInvoker+<>c__DisplayClass21+<>c__DisplayClass2b.<BeginInvokeAction>b__1c()

* System.Web.Mvc.Async.AsyncControllerActionInvoker+<>c__DisplayClass21.<BeginInvokeAction>b__1e(System.IAsyncResult)

* System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(System.IAsyncResult)

* System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(System.IAsyncResult, ExecuteCoreState)

* System.Web.Mvc.Async.AsyncResultWrapper+WrappedAsyncVoid`1[[System.Web.Mvc.Controller+ExecuteCoreState, System.Web.Mvc]].CallEndDelegate(System.IAsyncResult)

* System.Web.Mvc.Controller.EndExecuteCore(System.IAsyncResult)

* System.Web.Mvc.Async.AsyncResultWrapper+WrappedAsyncVoid`1[[System.__Canon, mscorlib]].CallEndDelegate(System.IAsyncResult)

* System.Web.Mvc.Controller.EndExecute(System.IAsyncResult)

* System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(System.IAsyncResult, ProcessRequestState)

* System.Web.Mvc.Async.AsyncResultWrapper+WrappedAsyncVoid`1[[System.Web.Mvc.MvcHandler+ProcessRequestState, System.Web.Mvc]].CallEndDelegate(System.IAsyncResult)

* System.Web.Mvc.MvcHandler.EndProcessRequest(System.IAsyncResult)

* System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()

* System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep)

* System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)

* System.Web.HttpApplication+PipelineStepManager.ResumeSteps(System.Exception)

* System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext, System.AsyncCallback)

* System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest, System.Web.HttpContext)

* System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)

* System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)

* DomainNeutralILStubClass.IL_STUB_ReversePInvoke(Int64, Int64, Int64, Int32)

* InlinedCallFrame

* InlinedCallFrame

* DomainNeutralILStubClass.IL_STUB_PInvoke(IntPtr, System.Web.RequestNotificationStatus ByRef)

* System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr, IntPtr, IntPtr, Int32)

* System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr, IntPtr, IntPtr, Int32)

* DomainNeutralILStubClass.IL_STUB_ReversePInvoke(Int64, Int64, Int64, Int32)

* ContextTransitionFrame



### Thread     10172

Thread type:   Background


Stack trace:



### Thread     14028

Thread type:   Background


Stack trace:



### Thread     10924

Thread type:   Background


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     0

Thread type:   Foreground


Stack trace:



### Thread     8412

Thread type:   Background


Stack trace:





Hope it will help you and makes your life much easier :) You can easily change it to debug any process.


Thank you


1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



Blockchain, Bitcoin and C#

Do you need to work with blockchain and bitcoin?

There is a library or even two of them to help you. NBitcoin and QBitNinja will help you.


If you need to track your address for income transactions, for example to check if anyone has paid you for your service or goods.

First thing you need to install those NuGet packages.

Then you need your private key hex bytes and when you get it all then just a few lines of code will provide you with all data you need:


Key key = new Key(new byte[] { /*your private key hex bytes*/ });
var addr = key.PubKey.Hash.GetAddress(Network.Main);
var client = new QBitNinjaClient(Network.Main);
var rbalance = client.GetBalance(addr, true).Result;


After that the rblanace will contain Operations property that will list all operations for your address.

Just go over all items in the rbalance.Operations and find everything you need to confirm or decline your user operation.


Thank you


1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



C#, .NET, x32/x64 Assembler and cross-platform code

Hello my dear friends.


Today we will look into such popular thing like cross-platform code, and such powerful thing like assembler. Of course, we will use C#.NET for this all as usually  :)

To make a cross-platform code we have to be aware of two main things:

- method call conventions 

- system API

We need different platform dependent system APIs to allocate and free executing memory and we need universal code to avoid method call convention problems.

To call system dependent APIs we need to understand what OS we are running under, here is code how we can do it:

 

private enum Platform

{

Windows,

Linux,

Mac

}

private static Platform RunningPlatform()

{

switch (Environment.OSVersion.Platform)

{

case PlatformID.Unix: // Well, there are chances MacOSX is reported as Unix instead of MacOSX. // Instead of platform check, we'll do a feature checks (Mac specific root folders) if (Directory.Exists("/Applications")

& Directory.Exists("/System")

& Directory.Exists("/Users") & Directory.Exists("/Volumes")) return Platform.Mac; else return Platform.Linux; case PlatformID.MacOSX: return Platform.Mac; default: return Platform.Windows;

}

}

Now we are going to declare PInvokes for linux and windows and implement logic to allocate and free memory with regards to OS we are running under (linux pinvokes were taken from the Mono source code):

#region Windows

[Flags]

private enum AllocationTypes : uint

{

Commit = 0x1000, Reserve = 0x2000,

Reset = 0x80000, LargePages = 0x20000000,

Physical = 0x400000, TopDown = 0x100000,

WriteWatch = 0x200000

}

[Flags]

private enum MemoryProtections : uint

{

Execute = 0x10, ExecuteRead = 0x20,

ExecuteReadWrite = 0x40, ExecuteWriteCopy = 0x80,

NoAccess = 0x01, ReadOnly = 0x02,

ReadWrite = 0x04, WriteCopy = 0x08,

GuartModifierflag = 0x100, NoCacheModifierflag = 0x200,

WriteCombineModifierflag = 0x400

}

[Flags]

private enum FreeTypes : uint

{

Decommit = 0x4000, Release = 0x8000

}

[DllImport("kernel32.dll", SetLastError = true)]

private static extern IntPtr VirtualAlloc(

IntPtr lpAddress,

UIntPtr dwSize,

AllocationTypes flAllocationType,

MemoryProtections flProtect);

 

[DllImport("kernel32")]

[return: MarshalAs(UnmanagedType.Bool)]

private static extern bool VirtualFree(

IntPtr lpAddress,

uint dwSize,

FreeTypes flFreeType);

#endregion

#region Unix

[AttributeUsage(

AttributeTargets.Class |

AttributeTargets.Delegate |

AttributeTargets.Enum |

AttributeTargets.Field |

AttributeTargets.Struct)]

private class MapAttribute : Attribute

{

private string nativeType;

private string suppressFlags;

public MapAttribute()

{

}

public MapAttribute(string nativeType)

{

this.nativeType = nativeType;

}

public string NativeType

{

get { return nativeType; }

}

public string SuppressFlags

{

get { return suppressFlags; }

set { suppressFlags = value; }

}

}

private const string MPH = "MonoPosixHelper";

private const string LIBC = "msvcrt";

[Map]

[Flags]

private enum MmapProts : int

{

PROT_READ = 0x1, // Page can be read.

PROT_WRITE = 0x2, // Page can be written.

PROT_EXEC = 0x4, // Page can be executed.

PROT_NONE = 0x0, // Page can not be accessed.

PROT_GROWSDOWN = 0x01000000, // Extend change to start of

// growsdown vma (mprotect only).

PROT_GROWSUP = 0x02000000, // Extend change to start of

// growsup vma (mprotect only).

}

[Map]

[Flags]

private enum MmapFlags : int

{

MAP_SHARED = 0x01, // Share changes.

MAP_PRIVATE = 0x02, // Changes are private.

MAP_TYPE = 0x0f, // Mask for type of mapping.

MAP_FIXED = 0x10, // Interpret addr exactly.

MAP_FILE = 0,

MAP_ANONYMOUS = 0x20, // Don't use a file.

MAP_ANON = MAP_ANONYMOUS,

// These are Linux-specific.

MAP_GROWSDOWN = 0x00100, // Stack-like segment.

MAP_DENYWRITE = 0x00800, // ETXTBSY

MAP_EXECUTABLE = 0x01000, // Mark it as an executable.

MAP_LOCKED = 0x02000, // Lock the mapping.

MAP_NORESERVE = 0x04000, // Don't check for reservations.

MAP_POPULATE = 0x08000, // Populate (prefault) pagetables.

MAP_NONBLOCK = 0x10000, // Do not block on IO.

}

[DllImport(MPH, SetLastError = true,

EntryPoint = "Mono_Posix_Syscall_mmap")]

private static extern IntPtr mmap(IntPtr start, ulong length,

MmapProts prot, MmapFlags flags, int fd, long offset);

[DllImport(MPH, SetLastError = true,

EntryPoint = "Mono_Posix_Syscall_munmap")]

public static extern int munmap(IntPtr start, ulong length);

[DllImport(MPH, SetLastError = true,

EntryPoint = "Mono_Posix_Syscall_mprotect")]

private static extern int mprotect(IntPtr start, ulong len, MmapProts prot);


[DllImport(MPH, CallingConvention = CallingConvention.Cdecl,

SetLastError = true, EntryPoint = "Mono_Posix_Stdlib_malloc")] private static extern IntPtr malloc(ulong size);

[DllImport(LIBC, CallingConvention = CallingConvention.Cdecl)] public static extern void free(IntPtr ptr);

#endregion


[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]

public unsafe delegate void asmFunc();

public static IntPtr VirtualAlloc(uint size)

{

IntPtr ptr = IntPtr.Zero;

if (RunningPlatform() == Platform.Windows)

{

ptr = VirtualAlloc(

IntPtr.Zero,

new UIntPtr(size),

AllocationTypes.Commit | AllocationTypes.Reserve,

MemoryProtections.ExecuteReadWrite);

}

else

{

Console.WriteLine("Linux memory allocation...");

ptr = mmap(IntPtr.Zero, 4096, MmapProts.PROT_EXEC | MmapProts.PROT_READ | MmapProts.PROT_WRITE, MmapFlags.MAP_ANONYMOUS | MmapFlags.MAP_PRIVATE, 0, 0);

Console.WriteLine("memory ptr: " + ptr.ToInt64());

}

return ptr;

}


public static void VirtualFree(IntPtr ptr, uint size)

{

if (RunningPlatform() == Platform.Windows)

{

VirtualFree(ptr, size, FreeTypes.Release);

}

else

{

Console.WriteLine("Free memory ptr: " + ptr.ToInt64());

int r = munmap(ptr, size);

Console.WriteLine("memory free status: " + r);

}

}


Ok, we have methods to allocate and free memory and now, we need some predefined assembly code and template to avoid any calling convention problems. To do it we will declare our methods and delegates as parameter-less and will pass parameters as declared bytes:

 

byte[] codeArray = new byte[]

{

0xE8, // call next code after data

0x00,

0x00,

0x00,

0x00,

//

//data will go here

//


0x5B, // pop e/rbx - now e/rbx looks into data address

0xFF, // inc dword [e/rbx]

0x03,

(byte)(IntPtr.Size > 4 ? 0x48 : 0x90),

0xFF, // inc e/rbx

0xC3,

(byte)(IntPtr.Size > 4 ? 0x48 : 0x90),

0xFF, // inc e/rbx

0xC3,

(byte)(IntPtr.Size > 4 ? 0x48 : 0x90),

0xFF, // inc e/rbx

0xC3,

(byte)(IntPtr.Size > 4 ? 0x48 : 0x90),

0xFF, // inc e/rbx

0xC3,

(byte)(IntPtr.Size > 4 ? 0x48 : 0x90), // dec d/qword [rbx]

0xFF,

0x0B,


0xC3 // retn - return from your method

};

byte[] dataArray = new byte[]

{

0xFF, //parameter Int32

0x00,

0x00,

0x00,

0x00, //parameter Int64

0x00,

0x00,

0x00,

0x00,

0x00,

0x00,

0x00

};


Console.WriteLine("Ptr size: " + IntPtr.Size);

//allocate memory for our asm method

IntPtr pp = Native.VirtualAlloc((uint)(codeArray.Length + dataArray.Length));

unsafe

{

IntPtr p = pp;

int n = 0;

byte* bptr = (byte*)p;

Marshal.Copy(codeArray, 0, p, 4);

p += 1;

//write offset to the next code line

Marshal.WriteInt32(p, dataArray.Length);

p += 4;

//copy data

Marshal.Copy(dataArray, 0, p, dataArray.Length);

p += dataArray.Length;

//copy rest of the code

Marshal.Copy(codeArray, 5, p, codeArray.Length - 5);

bptr[n] = bptr[n];

n = 0;

}

Native.asmFunc asmFunc = (Native.asmFunc)System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer(pp, typeof(Native.asmFunc));

Console.WriteLine("in param int32 = " + BitConverter.ToInt32(dataArray, 0));

Console.WriteLine("in param int64 = " + BitConverter.ToInt64(dataArray, sizeof(Int32)));

Console.WriteLine("call asm method...");

asmFunc();

Console.WriteLine("exit asm method");

As our methods are parameter-less a system will not use stack and we will not have to care about stack. To get address of our first parameter we will use well-known technic, such as call addr and pop reg, that moves to our next processor instruction and pops back an address, this address will be the address of our first parameter.

To pass back any parameters from our assembly method we will use the same address to put them before return back.

//copy params back to array

Marshal.Copy(pp + 5, dataArray, 0, dataArray.Length);

Console.WriteLine("out param int32 = " + BitConverter.ToInt32(dataArray, 0));

Console.WriteLine("out param int64 = " + BitConverter.ToInt64(dataArray, sizeof(Int32)));

//free allocated memory

Native.VirtualFree(pp, (uint)(codeArray.Length + dataArray.Length));

GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);

Console.WriteLine("any key to exit");

Console.ReadLine();


Now run it and test it. Remember that running this code, or any assembly code, under visual studio may cause error and exception, so always test your code out of any debugger.


I did test this code under Windows 10 64 bit and compiling in x32 and x64 modes, and Linux Ubuntu 14.04 64 bit mode.


Comments are welcome.


Thank you all,

See you later :)


1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



C#.Net - Perspective Image Transform

Hello,


Today, I'm going to share one interesting thing that everyone may need - perspective image transformation.

Its 2D transformation that makes image look like in perspective view like 3D but without any 3D:


So, the main thing there is math. We take an image, specify four points and math will do the trick.

First step is to create and calculate matrices from the new four points:

//original points

Point p1 = new Point(0, 0);

Point p2 = new Point(width, 0);

Point p3 = new Point(width, height);

Point p4 = new Point(0, height);

//create matrix

A = Matrix3x3.Homogenous(p1, p2, p3, p4);

//new points

Point n1 = points[0];

Point n2 = points[1];

Point n3 = points[2];

Point n4 = points[3];

B = Matrix3x3.Homogenous(n1, n2, n3, n4);

A.Inverse();

C = B.MultMat(A);

C.Inverse();

Second step is to go through each pixel on your image and calculate new pixel:

Point ptDest = new Point(0, 0);

PointF ptOriginF = new Point(0, 0);

int iOrigX = 0;

Color pix = new Color();

for (int x = 0; x < width; ++x)

{

for (int y = 0; y < height; ++y)

{

ptDest.X = x;

ptDest.Y = y;

ptOriginF = C.Update(ptDest);

if (ptOriginF.X >= -5 && ptOriginF.X < width && ptOriginF.Y >= -5 && ptOriginF.Y < height)

{


iOrigX = (int)ptOriginF.X; // round to lowest integer

int iOrigY = (int)ptOriginF.Y; // round to lowest integer

double dx = ptOriginF.X - iOrigX;

double dy = ptOriginF.Y - iOrigY;

Point ptOrigin = new Point(iOrigX, iOrigY);

if (dx != 0.0f || dy != 0.0)

{

Color pix1 = Color.FromArgb(0, 255, 255, 255);

Color pix2 = Color.FromArgb(0, 255, 255, 255);

Color pix3 = Color.FromArgb(0, 255, 255, 255);

Color pix4 = Color.FromArgb(0, 255, 255, 255);

//

// Correct square's direction

//

int idx = (dx >= 0.0) ? 1 : -1;

int idy = (dy >= 0.0) ? 1 : -1;


dx = Math.Abs(dx);

dy = Math.Abs(dy);

//

// Get pixels of square

//

if (ptOrigin.X >= 0 && ptOrigin.X < width && ptOrigin.Y >= 0 && ptOrigin.Y < height)

pix1 = src.GetPixel(ptOrigin.X, ptOrigin.Y);

if (ptOrigin.X + idx >= 0 && ptOrigin.X + idx < width && ptOrigin.Y >= 0 && ptOrigin.Y < height)

pix2 = src.GetPixel(ptOrigin.X + idx, ptOrigin.Y);

if (ptOrigin.X >= 0 && ptOrigin.X < width && ptOrigin.Y + idy >= 0 && ptOrigin.Y + idy < height)

pix3 = src.GetPixel(ptOrigin.X, ptOrigin.Y + idy);

if (ptOrigin.X + idx >= 0 && ptOrigin.X + idx < width && ptOrigin.Y + idy >= 0 && ptOrigin.Y + idy < height)

pix4 = src.GetPixel(ptOrigin.X + idx, ptOrigin.Y + idy);

//

// Use bilinear interpolation

//

double r = pix1.R + (pix2.R - pix1.R) * dx + (pix3.R - pix1.R) * dy + (pix1.R - pix2.R - pix3.R + pix4.R) * dx * dy;

double g = pix1.G + (pix2.G - pix1.G) * dx + (pix3.G - pix1.G) * dy + (pix1.G - pix2.G - pix3.G + pix4.G) * dx * dy;

double b = pix1.B + (pix2.B - pix1.B) * dx + (pix3.B - pix1.B) * dy + (pix1.B - pix2.B - pix3.B + pix4.B) * dx * dy;

double a = pix1.A + (pix2.A - pix1.A) * dx + (pix3.A - pix1.A) * dy + (pix1.A - pix2.A - pix3.A + pix4.A) * dx * dy;

pix = Color.FromArgb((byte)a, (byte)r, (byte)g, (byte)b);

}

else

{

pix = src.GetPixel(ptOrigin.X, ptOrigin.Y);

}

dst.SetPixel(ptDest.X, ptDest.Y, pix);

}

}

}

So this is bilinear interpolation is the main thing to transform your image.


Thank you.

PS

will extend this and provide source code if you will request.

PPS

    public class Matrix3x3
    {
        double [,] m_val = new double [3,3];

        public Matrix3x3()
        {
        }
        public Matrix3x3(Point p1, Point p2, Point p3)
        {
            m_val = new double[3, 3];
            m_val[0, 0] = p1.X;
            m_val[0, 1] = p2.X;
            m_val[0, 2] = p3.X;

            m_val[1, 0] = p1.Y;
            m_val[1, 1] = p2.Y;
            m_val[1, 2] = p3.Y;

            m_val[2, 0] = 1.0;
            m_val[2, 1] = 1.0;
            m_val[2, 2] = 1.0;
        }

        public double Determinant()
        {
            double result = 0;
            result = m_val[0, 0] * (m_val[1, 1] * m_val[2, 2] - m_val[1, 2] * m_val[2, 1]);
            result-= m_val[0, 1] * (m_val[1, 0] * m_val[2, 2] - m_val[1, 2] * m_val[2, 0]);
            result+= m_val[0, 2] * (m_val[1, 0] * m_val[2, 1] - m_val[1, 1] * m_val[2, 0]);

            return result;
        }
        public double a(int i, int j)
        {
            return m_val[i-1, j-1];
        }

        public void Inverse()
        {
            double a11 = a(2, 2) * a(3, 3) - a(2, 3) * a(3, 2);
            double a12 = a(2, 1) * a(3, 3) - a(2, 3) * a(3, 1);
            double a13 = a(2, 1) * a(3, 2) - a(2, 2) * a(3, 1);

            double a21 = a(1, 2) * a(3, 3) - a(1, 3) * a(3, 2);
            double a22 = a(1, 1) * a(3, 3) - a(1, 3) * a(3, 1);
            double a23 = a(1, 1) * a(3, 2) - a(1, 2) * a(3, 1);

            double a31 = a(1, 2) * a(2, 3) - a(1, 3) * a(2, 2);
            double a32 = a(1, 1) * a(2, 3) - a(1, 3) * a(2, 1);
            double a33 = a(1, 1) * a(2, 2) - a(1, 2) * a(2, 1);

            double od = 1.0/Determinant();

            m_val[0, 0] = od * a11;
            m_val[0, 1] = -od * a21;
            m_val[0, 2] = od * a31;

            m_val[1, 0] = -od * a12;
            m_val[1, 1] = od * a22;
            m_val[1, 2] = -od * a32;

            m_val[2, 0] = od * a13;
            m_val[2, 1] = -od * a23;
            m_val[2, 2] = od * a33;
        }

        public void MultByVec(double [] vector)
        {
            for (int row = 0; row < 3; ++row)
            {
                m_val[row, 0] *= vector[0];
                m_val[row, 1] *= vector[1];
                m_val[row, 2] *= vector[2];
            }
        }
        public PointD Update(PointD vector)
        {
            double x = a(1, 1) * vector.X + a(1, 2) * vector.Y + a(1, 3) * 1.0;
            double y = a(2, 1) * vector.X + a(2, 2) * vector.Y + a(2, 3) * 1.0;
            double z = a(3, 1) * vector.X + a(3, 2) * vector.Y + a(3, 3) * 1.0;
            //
            PointD result = new PointD();
            result.X = (x / z);
            result.Y = (y / z);
            return result;
        }

        public Matrix3x3 MultMat(Matrix3x3 B)
        {
            Matrix3x3 result = new Matrix3x3();

            result.m_val[0, 0] = a(1, 1) * B.a(1, 1) + a(1, 2) * B.a(2, 1) + a(1, 3) * B.a(3, 1);
            result.m_val[0, 1] = a(1, 1) * B.a(1, 2) + a(1, 2) * B.a(2, 2) + a(1, 3) * B.a(3, 2);
            result.m_val[0, 2] = a(1, 1) * B.a(1, 3) + a(1, 2) * B.a(2, 3) + a(1, 3) * B.a(3, 3);

            result.m_val[1, 0] = a(2, 1) * B.a(1, 1) + a(2, 2) * B.a(2, 1) + a(2, 3) * B.a(3, 1);
            result.m_val[1, 1] = a(2, 1) * B.a(1, 2) + a(2, 2) * B.a(2, 2) + a(2, 3) * B.a(3, 2);
            result.m_val[1, 2] = a(2, 1) * B.a(1, 3) + a(2, 2) * B.a(2, 3) + a(2, 3) * B.a(3, 3);

            result.m_val[2, 0] = a(3, 1) * B.a(1, 1) + a(3, 2) * B.a(2, 1) + a(3, 3) * B.a(3, 1);
            result.m_val[2, 1] = a(3, 1) * B.a(1, 2) + a(3, 2) * B.a(2, 2) + a(3, 3) * B.a(3, 2);
            result.m_val[2, 2] = a(3, 1) * B.a(1, 3) + a(3, 2) * B.a(2, 3) + a(3, 3) * B.a(3, 3);

            return result;
        }

        public static Matrix3x3 Homogenous(Point p1, Point p2, Point p3, Point p4)
        {
            Matrix3x3 Major = new Matrix3x3(p1, p2, p3);
            Matrix3x3 Minor1 = new Matrix3x3(p4, p2, p3);
            Matrix3x3 Minor2 = new Matrix3x3(p1, p4, p3);
            Matrix3x3 Minor3 = new Matrix3x3(p1, p2, p4);
            double MajorD = Major.Determinant();
            double Minor1D = Minor1.Determinant();
            double Minor2D = Minor2.Determinant();
            double Minor3D = Minor3.Determinant();

            double[] coeff = new double[3];
            coeff[0] = Minor1D / MajorD;
            coeff[1] = Minor2D / MajorD;
            coeff[2] = Minor3D / MajorD;
            //
            Major.MultByVec(coeff);

            return Major;
        }
    }





1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



Microsoft Expression Encoder - How to use and without installation

Hello friends,


Today I will share my experience with the Microsoft Expression Encoder 4 free version.

Download it and install from the link above, add references to the libraries:


- Microsoft.Expression.Encoder.dll

- Microsoft.Expression.Encoder.Api2.dll

- Microsoft.Expression.Encoder.Types.dll

- Microsoft.Expression.Encoder.Utilities.dll


So the minimum code you need to implement to be able to preview and capture video and audio and list devices is the following:

video.Clear();

audio.Clear();

foreach (var dev in EncoderDevices.FindDevices(EncoderDeviceType.Video))

{

video.Add(new ComboboxItem() { Text = dev.Name, Value = dev })

}


foreach (var dev in EncoderDevices.FindDevices(EncoderDeviceType.Audio))

{

audio.Add(new ComboboxItem() { Text = dev.Name, Value = dev });

}

try

{

if (ljob == null)

{

ljob = new LiveJob();

source = ljob.AddDeviceSource((EncoderDevice)((ComboboxItem)cbVideoDevice.SelectedItem).Value,

(EncoderDevice)((ComboboxItem)cbAudioDevice.SelectedItem).Value);

source.PickBestVideoFormat(videoSize, 400000); //in 100 nanoseconds = 40 ms = 25 frames per seconds

source.SetTransportMode(TransportMode.FastForward);


ljob.OutputFormat.VideoProfile = new Microsoft.Expression.Encoder.Profiles.AdvancedVC1VideoProfile() { };

ljob.OutputFormat.VideoProfile.Size = videoSize;

ljob.OutputFormat.VideoProfile.FrameRate = 25;

ljob.OutputFormat.AudioProfile = new Microsoft.Expression.Encoder.Profiles.WmaAudioProfile() { };

ljob.OutputFormat.AudioProfile.Codec = Microsoft.Expression.Encoder.Profiles.AudioCodec.Wma;

}

source.PreviewWindow = new PreviewWindow(new System.Runtime.InteropServices.HandleRef(capForm.Panel, ca pForm.Panel.Handle));

ljob.ActivateSource(source);

}

catch (Microsoft.Expression.Encoder.SystemErrorException ex)

{

if (ex.ErrorCode == -2126905299)

{

MessageBox.Show("Device in use by another application.", "Test EE 4");

}

}

and to start capture:

ljob.PublishFormats.Add(new FileArchivePublishFormat(System.IO.Path.GetFullPath(filePath + fileName)));

ljob.StartEncoding();


Another important thing is to avoid using the installation package of the Microsoft Expression Encoder but just use those four Dlls.

If you will try to run your app on another PC you will get error that Expression Encoder has no license key or something. So to avoid this you have to cases:


- bring the install package and install it on every PC where is your app

- make some changes into registry


I will show you what changes should we make to be able to use it on every PC without installation of Microsoft Expression Encoder, here is the code:

private void TellExpressionEncoderWhereItIs()

{

try

{

var key = "SOFTWARE\\Microsoft\\Expression\\Encoder\\4.0";

 

using (var registryKey = Registry.LocalMachine.OpenSubKey(key))

{

if (registryKey == null)

{

using (var newKey = Registry.LocalMachine.CreateSubKey(key))

{

CheckInstallKey(newKey);

}

}

}

key = "SOFTWARE\\Microsoft\\Expression\\Encoder\\eaa89a7c-d288-4a52-9b68-54930f18ffb7";


using (var registryKey = Registry.LocalMachine.OpenSubKey(key))

{

if (registryKey == null)

{

using (var newKey = Registry.LocalMachine.CreateSubKey(key))

{

CheckInstallKey(newKey);

}

}

}

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

private void CheckInstallKey(RegistryKey registryKey)

{

var path = "c:\\Program Files\\Microsoft Expression\\Encoder 4\\";

var installKey = "InstallDir";

if (registryKey != null)

{

string text = registryKey.GetValue(installKey) as string;

if (string.IsNullOrEmpty(text))

{

registryKey.SetValue(installKey, path);

}

}

path = "4.0.4276.0";

installKey = "Version";

if (registryKey != null)

{

string text = registryKey.GetValue(installKey) as string;

if (string.IsNullOrEmpty(text))

{

registryKey.SetValue(installKey, path);

}

}

path = "c:\\Program Files\\Microsoft Expression\\Encoder 4\\Encoder.exe";

installKey = "Encoder";

if (registryKey != null)

{

string text = registryKey.GetValue(installKey) as string;

if (string.IsNullOrEmpty(text))

{

registryKey.SetValue(installKey, path);

}

}

path = "c:\\Program Files\\Microsoft Expression\\Encoder 4\\Encoder.exe";

installKey = "InstallPath";

if (registryKey != null)

{

string text = registryKey.GetValue(installKey) as string;

if (string.IsNullOrEmpty(text))

{

registryKey.SetValue(installKey, path);

}

}

}


Also, you will be able to select screen as a video device and capture your screen.


Thank you and let me know if you have questions or better idea :)


1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



DataGridView and huge amount of data rows

Hello my friends,

Did you have a need to populate the DataGridView control with a lot of data? I'm sure you did have.

If you have a huge amount of rows, like 10 000 and more, you will see a huge problem in performance.

To avoid performance leak - you need to set proper value into the RowHeadersWidthSizeMode property.

So the best way is to disable auto resizing during data binding:

dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing;

you actually can set EnableResizing but avoid to use the DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders

The AutoSizeToAllHeaders is most time consumable parameter.

In addition would be better to set the RowHeadersVisible to false

dataGridView1.RowHeadersVisible = false;

Now you can bind data source, and enable it all or set what you want it to be 


Thank you, see you next time.


1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y



C#.NET and unmanaged static C++ library

Hi friends,

Today I'm going to share my experience with c++ static libraries.


Static library differs from dynamic library by that, that parts of static library code will be included into caller code.

For example, I have an exe and my exe code calls a function from a static library. It means that this static library function's code will be included into my exe and I will not need any library to be with the exe.


But with C# such things are going to be more tricky, because of C#.NET is managed code and static library is unmanaged code and thus could not be linked and included.

So we need another way to do it. As you know we can use PInvoke to be able to access exported dll functions, and this is going to help us a lot.

First step is to create a Dll C++ project and link a static library to this Dll, our dll project is going to be something like a wrapper, and add some export method so we would be able to invoke them from C#.NET code.

Here is how to do it:

extern "C" __declspec(dllexport) int InitializeLib2(int type, const char *data, BOOL useFlag)

{

return ::InitializeLib(type, data, useFlag);

}

so we have declared our InitializeLib2 function for export and to be used via PInvoke from C# code, inside of this InitializeLib2 function we have a call to a static library InitializeLib function  and just pass parameters from our method.

Now we build it and get a Dll file that can be pinvoked from our C# code.

Here is how to do it:

[DllImport("MyWrapper.dll", CallingConvention = CallingConvention.Cdecl)]

public static extern int InitializeLib2(int zero, ref byte str, bool b);

and here how to call this method:

byte[] str = ASCIIEncoding.ASCII.GetBytes("my string data" + ((char)0).ToString());

int a = InitializeLib2(0, ref str[0], false);

so we pass an integer value, I like to pass strings as byte array and last parameter is boolean value.


Thats all. At the end of this you will have MyWrapper.dll and managed exe file.

Thank you, and good luck :)


1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y