Management task: Remote shutdown utility

I run a simple web server to serve as a storage medium for my mobile devices (I don’t like using dropbox or other online storage solutions because they don’t offer much space and they hogs up bandwidth unnecessarily). Before I go to sleep I usually shut down the server to save energy, but in order to do so, I have to have another computer turned on to perform remote access into the server and shut it down via command line. Occasionally, I would turn off my work computer before I remember that I want to shut down the server and I’m too lazy by then to turn on my work computer again.

That’s why I wanted an application that is capable of shutting down Windows on my behalf. The scenario is like this: because I can access FTP service from my phone, I will create a file, namely ‘shutdown’; when the server sees this file, it will delete the file and initiate shutdown. Quite simple.

To shut down, I use Windows management interface (System.Management namespace in C#)

        static void Shutdown()
        {
            ManagementBaseObject mboShutdown = null;
            ManagementClass mcWin32 = new ManagementClass("Win32_OperatingSystem");
            mcWin32.Get();

            // You can't shutdown without security privileges
            mcWin32.Scope.Options.EnablePrivileges = true;
            ManagementBaseObject mboShutdownParams =
                     mcWin32.GetMethodParameters("Win32Shutdown");

            // Flag 1 means we want to shut down the system. Use "2" to reboot.
            mboShutdownParams["Flags"] = "1";
            mboShutdownParams["Reserved"] = "0";
            foreach (ManagementObject manObj in mcWin32.GetInstances())
            {
                mboShutdown = manObj.InvokeMethod("Win32Shutdown",
                                               mboShutdownParams, null);
            }
        }

From here

And the rest is just a loop to check if the file exists

        /// 
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            while (true)
            {
                if (!System.IO.File.Exists("D:\Shutdown"))
                {
                    Thread.Sleep(500);
                }
                else
                {
                    System.IO.File.Delete("D:\Shutdown");
                    Shutdown();
                    return;
                }
            }
        }

That’s it, I run the application and it will wait until I create a file named ‘shutdown’ in D:, it will perform shutdown and quit

Here’s the sample code and binary

Fooling around with the Office Assistant

I seem to have a special bond with ancient stuff. I were doing Pascal when C++ and WinForm was at their prime. Now I’m toying with a discontinued Microsoft Office feature. I just can’t help it, I have to work with Office 2003 around the clock since the upper IT management takes about a decade to certify a new software as “compatible”. Well, working for a big corporation has its pros and cons and we all have to cope with them.

I don’t feel the Office assistant intrusive though, it certainly doesn’t get in your way if you turn it off, but oh well, only when you know how. (Which, sadly, is not the case for many computer users). And I don’t think we can just let the woman take it from us. Gdzie jest czcionka? 😉

When I was in 7th grade or something. I read an article on PCWorld Vietnam about how to manipulate the Office Assistant. I diligently typed the code (in VBA) character-by-character without even understanding them :P. Nevertheless, the result was really satisfying, I were able to make the cat  (Links, an office assistant character) jump through hoops (literally).

Okay, enough trivia! I don’t remember any function from back then so I’ll have to start over. I have done various applications inter-operating with Microsoft Office’s VBA before, so I guess it would be an easy task. I added the Microsoft Excel’s object library to my  C# project and search for “assistant”. Lucky me, something popped up.

Assistant class in object browser

As you may see, it’s a child of the application class so you’ll have to start an Office application first. I chose Excel because it’s the application I have been working with the most. For aesthetics reasons, I tried to hide the Application’s window but that will hide the assistant too :(.  Apart from that, thanks to the well-built COM interface, initialize and display the assistant is easy.

using Microsoft.Office.Interop.Excel;
...
ApplicationClass Test = new ApplicationClass();
Test.Assistant.On = true;
Test.Assistant.Visible = true;

In case you are wondering, ApplicationClass is used to control Excel. All the possible action of “Assistant” is neatly listed within an enum so I just have to convert those to text and list them for the user to choose. No button-to-button editing for each action required!

 foreach (string TypeName in Enum.GetNames(typeof(Microsoft.Office.Core.MsoAnimationType)))
 {
     listBox1.Items.Add(TypeName);
 }

Because you can only see the Office Assistant when the host Office application has focus, I made a timer so the assistant will do the same action over and over, so the user can switch to the relevant application.

        private void timer1_Tick(object sender, EventArgs e)
        {
            Microsoft.Office.Core.MsoAnimationType[] Temp = (Microsoft.Office.Core.MsoAnimationType[])Enum.GetValues(typeof(Microsoft.Office.Core.MsoAnimationType));
            if (listBox1.SelectedIndex >= 0)
            {
                Test.Assistant.Animation = Temp[listBox1.SelectedIndex];
                Test.Visible = true;
            }
        }

"Get techy" with Rocky :p

You can also make the assistant say stuff you want:

 private void button1_Click(object sender, EventArgs e)
 // I created a button and a TextBox
 // When you enter some text into the TextBox and click the button, the
 // assistant will make a speech balloon with the text in it
 {
   timer1.Enabled = false;
   MessageBox.Show("Switch to Excel after clicking OK");
   System.Threading.Thread.Sleep(2000);
   Microsoft.Office.Core.Balloon Speech = Test.Assistant.NewBalloon;
   Speech.Heading = "Test balloon";
   Speech.Text = textBox1.Text;

   Speech.Mode = Microsoft.Office.Core.MsoModeType.msoModeModal;
   Speech.Show();
   timer1.Enabled = true;
 }

Bark!

So if you are still stuck with Office 2003 and wanted to play around with it a bit, here’s the compiled application (requires .NET 2.0 and Microsoft Office 2003 installed) and for those who want the code, here it is.

Advanced C# splash screen

I once posted about how to make a splash screen with C#; yet it’s still a rectangle. While it’s true that you can replace my picture with something that have curvy edges, you’ll have aliased edges i.e. crooked and crude pixels around the edges.

Example of an aliased picture, the edges are not smooth and you can't see through the semitransparent parts

There’s a solution: alpha-blend the picture and you can see through the form; pixels with alpha value of neither 0 or 255 will be mixed appropriately with the background.

Alpha-blended picture. The edges are smoother and you can see through the form

To achieve this, you have to write your custom painting function with windows API, specifically this one

[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags);

Which can be a daunting task. Luckily we have someone from Visual C# kicks did the hard work and released the source for public use! But that’s not the end of my story just yet. I wanted the splash screen to fades in and out. The timing part was easy, just a timer and several more lines of code and it’s done.

        enum Phases {
            FadeIn,
            Hold,
            FadeOut
        };
        Phases CurrentPhase = Phases.FadeIn;
        int FadeInStep = 0;
        const int FadeInLast = 20;
        int HoldStep = 0;
        const int HoldLast = 80;
        int FadeOutStep = 20;
        const int FadeOutLast = 0;
        const int OpacityMultiplier = 5;

        private void timerFade_Tick(object sender, EventArgs e)
        {
            if (CurrentPhase == Phases.FadeIn)
            {
                if (FadeInStep < FadeInLast)
                {
                    FadeInStep++;
                    this.Opacity = (OpacityMultiplier * FadeInStep) / 100.0;
                }
                else
                    CurrentPhase = Phases.Hold;
            }
            else if (CurrentPhase == Phases.Hold)
            {
                if (HoldStep < HoldLast)
                {
                    HoldStep++;
                    this.UpdateFormDisplay(this.BackgroundImage);
                }
                else
                    CurrentPhase = Phases.FadeOut;
            }
            else if (CurrentPhase == Phases.FadeOut)
            {
                {
                    FadeOutStep--;
                    this.Opacity = (OpacityMultiplier * FadeOutStep) / 100.0;
                }
                else
                    this.Close();
            }

I have even altered the custom paint code to utilize the form’s transparency factor

                //Set up blending options
                API.BLENDFUNCTION blend = new API.BLENDFUNCTION();
                blend.BlendOp = API.AC_SRC_OVER;
                blend.BlendFlags = 0;
                blend.SourceConstantAlpha = (byte)(255 * this.Opacity);
                blend.AlphaFormat = API.AC_SRC_ALPHA;

                API.UpdateLayeredWindow(this.Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, this.BackColor.ToArgb(), ref blend, API.ULW_ALPHA);

But that didn’t work to my expectation! The form is fading in and out gradually but the alpha blending effect is lost.

Fugly!

After fiddling around, I figured out that the custom paint code somehow didn’t override all the necessary painting functions and the setter of this.Opacity call those functions every time it’s changed. Searching around the list of functions can be overridden I found nothing interesting

That function doesn't help...

So I created a new variable and leave the form’s default Opacity alone. After all, if I have adjusted transparency myself in the custom paint function, who needs .NET’s alpha-blend-incapable render? The code above becomes:

        double MyOpacity = 0;

            if (CurrentPhase == Phases.FadeIn)
            {
                if (FadeInStep < FadeInLast)
                {
                    FadeInStep++;
                    MyOpacity = (OpacityMultiplier * FadeInStep) / 100.0;
                    this.UpdateFormDisplay(this.BackgroundImage);
                }
                else
                    CurrentPhase = Phases.Hold;
            }
            else if (CurrentPhase == Phases.Hold)
            {
                if (HoldStep < HoldLast)                 {                     HoldStep++;                     this.UpdateFormDisplay(this.BackgroundImage);                 }                 else                     CurrentPhase = Phases.FadeOut;             }             else if (CurrentPhase == Phases.FadeOut)             {                 if (FadeOutStep > FadeOutLast)
                {
                    FadeOutStep--;
                    MyOpacity = (OpacityMultiplier * FadeOutStep) / 100.0;
                    this.UpdateFormDisplay(this.BackgroundImage);
                }
                else
                    this.Close();
            }
        }
                //Set up blending options
                API.BLENDFUNCTION blend = new API.BLENDFUNCTION();
                blend.BlendOp = API.AC_SRC_OVER;
                blend.BlendFlags = 0;
                blend.SourceConstantAlpha = (byte)(255 * MyOpacity);
                blend.AlphaFormat = API.AC_SRC_ALPHA;

                API.UpdateLayeredWindow(this.Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, this.BackColor.ToArgb(), ref blend, API.ULW_ALPHA);

And Voilà!

Alpha blended splash against my blog in the background, you can see through the semi-transparent form

You can get the project, source code and complied binary here.

Report @ localhost

I was developing an automated report maker. Its mission is to collect data from various sources (MSSQL, Excel and Access) to create a summary of the numbers. Things hit a few bumps along the way but finally after 2 days, the collecting phase (the one I thought was hard) is complete.

On to the “easy” part…

C# is such a great environment that they could have offered you with two report solution: the standard report control that comes with the framework and Business Object’s Crystal Report. I was looking for something that could accept parameters, use that for some SQL queries and display the result with a couple groupings.

Crystal report as overtly complex for the purpose, heh, and adding parameter to the query is not that easy as it depends on the project’s datasource.

The report control is even worse. I vividly recall from the last time I worked with such reports they have three tabs in the designer for me to edit data, layout and preview the result. But to my surprise, I can’t even find the preview command anywhere after I created a report in a Winform application. Not on the toolbar, not in the menu, nowhere to be found!

After a little twiddling around, I found another kind of project dedicated to report: the report wizard from the Business Intelligence studio (I happen to have SQL Server Express installed on the development machine). Exactly what I’m looking for! I just paste in the query, choose the groupings and voilà! Report to print! And they have three tabs…

I thought to myself it was all Microsoft stuff, and maybe the report viewer back from the winform project could view this, so I copied it over, point the control to the report, and execute it.

“Data source not found” is all I get.

It turned out that the world isn’t all pink like Microsoft thought (see the “just rename your file and it’ll work, we are Microsoft!” article). The business intelligence’s report is to be and only to be deployed on a report server, which is really not convenience for me since my version of SQL is Express and does not include the report server :(. From a winform application, the report viewer control will just ignore the queries you spent hours crafted in the .rdl report when you rename it to .rdlc (Because they name it report for different meanings on different tiers – A total solution on the server and a mere viewer on the client). They say you have to rebind the datasource. Easy for them to say when they aren’t binding a lot of queries together – by hand since Microsoft’s great data designer won’t allow you to create a new table with schema based on your queries, the situation is even worse for parameterized queries! =__=

Queries are naughty, so no rows for you!

I'm too lazy to parse that text (the same query run just fine from SSMS)

Folks on the ‘net have not been helpful this time. All they did was point back to the article, It’s surprising to see that something not impossible as viewing .rdl locally is impossible to do with what Microsoft allow you to use. (Yes, they allow you to preview the report locally just fine but they hid the damn report viewer!)

Who needs Microsoft when we have the Apache license? 😛

Somebody did it the hard way: they created a new parser and render the report from scratch. It have evolved for sometime: 0.5 from the like above to 4.0 latest. But still I does have limitations: some attributes are yet to be parsed and are ignored (for example, tables will not expand to accomodate the records) so the report may look a little off, but that could be fixed with a simple moving of parts. After all, this is open source software: if you wanted it to be better, dig in! 🙂

Anyways, it gets the job done. My reports are displaying expected numbers and passing parameters are painless. Cheers to the author!

RDL reports being viewed locally

Latest version of project RDL is available at FYIReporting’s homepage.

UPDATE: And don’t think you can just bind your data with the dataset designer, it won’t tell you anything when you choose the data set as the data source, but when you run it you get an ugly “not bind to an instance” error. In the end you’ll have to do things manually with Microsoft.
reportViewer1.LocalReport.DataSources.Clear();
reportViewer1.LocalReport.DataSources.Add(
                new ReportDataSource("Table name", new DataSetName.TableAdapter().GetData(Parameters))
);