Skip to content

The shortest code you need to draw vector graphics

This example shows the shortest code you need to draw vector graphics in PowerShell. However, this code demonstrates a problem rather than a solution. The .NET Framework wants you to inherit a Form class when you describe a picture, because you will need to be able to access protected properties and to respond to events. But since the CreateGraphics function is public, you can still do some hacking with an instance of a Form class. This code creates a window, draws an X on it, and leaves it visible for 5 seconds.

#Load the Windows Forms library.
[string]$WindowsFormsLibrary =
"System.Windows.Forms,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089"
[System.Reflection.Assembly]::Load($WindowsFormsLibrary)

#Load the Drawing library.
[string]$DrawingLibrary =
"System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
[System.Reflection.Assembly]::Load($DrawingLibrary)

#Create a window, and set its properties.
[System.Windows.Forms.Form]$f = New-Object System.Windows.Forms.Form
$f.Width = 500
$f.Height = 300

#Display the form.
$f.Show()
#Force a complete draw before we add any graphics.
$f.Refresh()

#Acquire the graphics interface.
[System.Drawing.Graphics]$g = $f.CreateGraphics()

#Draw anything you like here using GDI+.
$g.DrawLine([System.Drawing.Pens]::Black, 50, 20, 450, 250)
$g.DrawLine([System.Drawing.Pens]::Black, 450, 20, 50, 250)

#Dispose the graphics interface.
$g.Dispose()

#Wait for 5 seconds before closing it all down.
Start-Sleep -s 5
$f.Close()
$f.Dispose()

If we take the trouble to create a custom type based on the Form class, we can create form has double buffering enabled by definition, and is of correct size by definition. The size can be set from outside the form as shown above, but the DoubleBuffered property that controls double buffering could not. So by just replacing the predefined Form class with a custom extension, we are slightly closer to our goal.

#Load the Windows Forms library.
[string]$WindowsFormsLibrary =
"System.Windows.Forms,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089"
[System.Reflection.Assembly]::Load($WindowsFormsLibrary)

#Load the Drawing library.
[string]$DrawingLibrary =
"System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
[System.Reflection.Assembly]::Load($DrawingLibrary)

#Create a custom form with double buffering.
$Refs = @("System.Windows.Forms", "System.Drawing")
Add-Type -ReferencedAssemblies $Refs @'
public class MyGraphicsForm:System.Windows.Forms.Form
{
   private System.ComponentModel.IContainer components = null;

   protected override void Dispose(bool disposing)
   {
      if (disposing && (components != null))
      {
         components.Dispose();
      }
      base.Dispose(disposing);
   }

   private void InitializeComponent()
   {
      this.SuspendLayout();
      this.ClientSize = new System.Drawing.Size(500, 300);
      this.DoubleBuffered = true;
      this.Text = "My graphics form";
      this.ResumeLayout(false);

   }
}
'@

#Create our custom window.
[System.Windows.Forms.Form]$f = New-Object MyGraphicsForm

#Display the form.
$f.Show()
#Force a complete draw before we add any graphics.
$f.Refresh()

#Acquire the graphics interface.
[System.Drawing.Graphics]$g = $f.CreateGraphics()

#Draw anything you like here using GDI+.
$g.DrawLine([System.Drawing.Pens]::Black, 50, 20, 450, 250)
$g.DrawLine([System.Drawing.Pens]::Black, 450, 20, 50, 250)

#Dispose the graphics interface.
$g.Dispose()

#Wait for 5 seconds before closing it all down.
Start-Sleep -s 5
$f.Close()
$f.Dispose()

To be continued.

Categories: PowerShell.

Converting from JComments to Disqus

This is not a complete solution, but it is a good start. When you do an export from JComments that you intend to import to Disqus, a format change is required. This exe is designed to read one XML-file and write the data of that file in Disqus XML file.

Start from cmd.exe and pass a source file (must exist) and a destination file (will be overwritten) as arguments. Example:

jc2disqus.exe "c:\my_jc_file.xml" "c:\new_disqus_file.xml"

The program will ask you about a post link. Type something like this:

http://www.myblogg.com/?p=[ID]

Two escape codes are accepted. [ID] is replaced with the ID of the post and [CAT] is replaced with the parent ID of the post.

If you need to do adjustments, the Visual Basic source code can be found here.

Categories: General.

Tags: ,

Piping objects

If you want to create and run a ps1 script, make sure to give yourself the permission to execute scripts. If you are running a newer operating system, you must start PowerShell as an administrator the time that you grant yourself the right to run scripts.

When you type DIR, a list of DirectoryInfo and/or FileInfo objects are created and sent to the script host. Each object, no matter type, are displayed as strings, meaning that the directory name or file name is displayed. How ever, you can use the pipeline to access actual objects. I have some directories and a few files in my C root, so if I pipe the output from the DIR command to an iteration that displays the object’s type name, like so:

DIR C:\ | ForEach-Object { Write-Host $_.GetType().Name }

From that I will get the word DirectoryInfo for each directory and the word FileInfo for each file in my C root. These are the .NET classes that represent directories and files. Since the PowerShell pipeline actually is handling objects, you can use these objects by accessing the properties or calling the functions of each object. A simple task such as displaying the number of files in each directory, is a walk in the park, when the actual object you need to do this, already is in the pipeline.

DIR C:\ | ForEach-Object {
If ($_.GetType().Name -like "DirectoryInfo")
   {
      Write-Host $_.Name "(" $_.GetDirectories().Length
         " dirs and " $_.GetFiles().Length " files.)"
   }
}

The output for this, is the name of the directory and the number of child directories and files that it holds. I can see that my Windows folder holds 66 directories and 45 files.

Categories: PowerShell.

Tool for interplanetary space travel

If you are planning on doing some interplanetary space travel, this little calculator is what you need. It will tell you how much time you need to set aside for your trip, and how much time you’ll gain by using a faster ship. Only available in Swedish (because NASA aren’t planning any such trips in the near future, so I put my faith in ESA).

Download the tool from here (requires Windows XP SP3 or later).

Categories: Geeky.

Roliga timmen 2

Del 1 finns här, men om vi utökar tidsrymden med några år, har vi en period med fler riktigt roliga klipp.

1. Black Books – Drinking and smoking is fantastic

2. The end of the world (The Secret Policeman’s Ball)

3. Emo Philips: Religion

4. Fry and Laurie: Psychic spoon bender

5. Eddie Izzard: Cake or death?

6. South Park: Ms. Garrison explains evolution

7. Cleese and Atkinson: Beekeeping

8. Ricky Gervais: Golden Globes 2011 opening monologue

9. Monty Python driver med katolicismen: Growth and Learning

10. Dylan Moran: Women have no feelings

Mycket nöje!

Lite bonusklipp: Not the nine o’clock news: Grammophone

Categories: General.

Extension methods in Visual Basic

Extension methods is a well known concept in C#. The idea is that you can add methods to a type without inheritance, as described here.

Visual Basic doesn’t have any linguistic support for extension methods, but it can be done thanks to a method attribute. There are some rules for doing this. You must declare your sub or function in a standard module, not a class. You must have at least one parameter, and that parameter is the type you are extending. Any other parameters will be parameters in your function. Finally, your sub or function must have the System.Runtime.CompilerServices.Extension attribute.

So if you want to add a function that takes no parameters to the Integer type, you will have to define a function that takes one parameter, an Integer. If you want to add a function that takes one parameter, you will have to define a function that takes two parameter, the first must be an Integer and the second (who will serve as the first parameter in your function) can be of any type you like.

Public Function DoubleValue(ByVal I As Integer) As Integer
   Return I * 2
End Function

Remember, the code must be written in a standard module.

The last thing that you have to do, is to add the attribute.

<System.Runtime.CompilerServices.Extension()>
Public Function DoubleValue(ByVal I As Integer) As Integer
   Return I * 2
End Function

(The above code is VBx syntax. For older Visual Basic versions, add a blank followed by an underscore to the attribute line.)

Now you can call the DoubleValue function from any Integer, in this case 5:

Console.WriteLine(5.DoubleValue())

The output will of course be 10.

Categories: Visual Basic 10.

CP/M on a Commodore machine – online resources

To get started with CP/M, you will need a Commodore 128 with a disk drive or a computer that runs Vice (X128). The disks you need can be downloaded from here. The CP/M boot disk, the additional utilities, “more CP/M additional utilities”, the Assembler utilities and Microsoft Basic 80 (two disks).

If you run this on a physical machine, make sure to insert the boot disk, and to push in the “40/80 display” key on your computer, before turning it on. If you are running this from Vice emulator, start your machine by passing these arguments to the x128 executable (adjust the path if necessary):

x128.exe -80 -autostart "C:\cpm\zpmsys.d64"

This is a text only environment, but pseudo graphics can be used, and a graphics library is available as an add-on.

The basic usage of CP/M is described in the Commodore 128 user guide, chapter 11. If you know DOS, you will probably feel rather at home. You have the concepts of programs and arguments. DIR shows the available commands. The actual Commodore extensions consist of keyboard short cuts and are described in chapter 15 of the Commodore 128 user guide.

What I see as the biggest challenge, is inserting the correct disk. Let’s say that you want to read the content of a file. This requires the TYPE.COM file that is located on the additional utilities disk, so you must insert that disk to be able to run that command. To avoid frustration, use two disk drives – one for the CP/M disks, and one for your files.

To start Microsoft Basic, insert the correct disk and type MBASIC. Then, watch a movie or something. After a while, your Commodore 128 will say:

MBASIC-80 Rev. 5.21
[CP/M Version]
Copyright 1977-1981 (C) by Microsoft
Created: 28-Jul-81
34350 Bytes free
Ok

If you want to write programs, the MBASIC manual can be downloaded from here.

A five minute Turbo Pascal 3.0 demo on the Commodore 128:

Categories: Geeky.

Tags:

Simon’s Basic

I happened to find this website with some great downloads for the Commodore 64. Some compilers and some interpretators, like Simon’s Basic. Simon’s Basic extended the extremely frugal Commodore Basic 2.0 that was built in the C64. It sort of turned the C64 into a Commodore 128 by providing new sets of instructions for sound, graphics and input. The complete manual can be downloaded as a PDF from here.

The band Barcelona named an album Simon Basic as a tribute to this programming language.

Categories: Geeky.

Visual Basic: Importing namespaces

In C# you can use the using directive to import the classes in a given namespace to your current scope. If you want to use the classes in System.Data.SqlClient, you could refer to them using their full path, like so:

var r = new System.Data.SqlClient.SqlDataAdapter();

You can add namespaces to your scope by adding a using directive in the beginning of your source file. If you add this directive:

using System.Data.SqlClient;

You could then access the SqlDataAdapter class in your code, without typing the full path, like so:

var r = new SqlDataAdapter();

Visual Basic does not have the using directive, but it has a more powerful directive called Imports. Imports can import both classes and other namespaces. The code that creates a SqlDataAdapter in Visual Basic looks like this:

Dim R As New System.Data.SqlClient.SqlDataAdapter()

If you use the Imports directive to import System.Data in the beginning of your file, like so:

Imports System.Data

You can access both the namespaces (like SqlClient) and the classes in System.Data without providing the full path.

Dim R As New SqlClient.SqlDataAdapter()

If course, you can go on and import the SqlClient namespace to access the SqlDataAdapter class without specifying it’s full path, just as you can do in C#. So, the using directive in C# can import classes, but the Imports directive in VB imports both classes and namespaces.

Categories: Visual Basic 10.

A multithreaded sockets server, just a few lines of code

This small piece of Visual Basic code (VBx) shows how you can do a multithreaded sockets server in just a few lines of code. I write all of this code in a console application. The main module will only hold an implementation of the Main function. Like so:

Module Module1

    Sub Main()
      Dim L As New System.Net.Sockets.TcpListener(
         New System.Net.IPAddress({192, 168, 1, 100}), 80)
      L.Start()
      Dim ThreadCounter = 0
      Do
         ThreadCounter += 1
         Dim C = L.AcceptTcpClient()
         Dim S As New NetSession(C, ThreadCounter)
         Dim T As New Threading.Thread(AddressOf S.SessionLoop)
         Console.WriteLine("Starting thread " & ThreadCounter.ToString() & ".")
         T.Start()
      Loop
    End Sub

End Module

Note that I have hard coded my local IP address, and passed it as an argument to the TcpListener constructor, but there are easy ways collect this information using the .NET Framework. The variable C is a System.Net.Sockets.TcpClient, because that is what the AcceptTcpClient function returns. The ThreadCounter is just so that different connections will get a unique session identifier.

The rest of the code takes place in the NetSession class.

Public Class NetSession

   Private mC As System.Net.Sockets.TcpClient
   Private mS As System.Net.Sockets.NetworkStream
   Private mThreadCounter As Integer
   Private mIndex As String

   Public Sub New(ByVal C As System.Net.Sockets.TcpClient,
         ByVal ThreadCounter As Integer)
      Me.mC = C
      Me.mThreadCounter = ThreadCounter
      Me.mIndex = ""
   End Sub

   Public Sub SessionLoop()
      Me.mS = Me.mC.GetStream()
      Me.mC.LingerState.Enabled = False
      Me.WriteLine("Connected.")
      While Me.mC.Connected
         If Me.mS.DataAvailable Then
            Dim GotData As New System.Text.StringBuilder()
            While Me.mS.DataAvailable
               Dim bytes(Me.mC.ReceiveBufferSize - 1) As Byte
               Dim Len = Me.mS.Read(bytes, 0, Me.mC.ReceiveBufferSize)
               If Len > 0 Then
                  GotData.Append(System.Text.Encoding.UTF8.GetString(bytes, 0, Len))
               End If
            End While
            Dim D = GotData.ToString().Trim()
            If Not D = "" Then
               If Not Me.Handle(D) Then
                  Exit While
               End If
            End If
         End If
      End While
      Me.mS.Close()
      Me.mS.Dispose()
      Me.mC.Close()
      Console.WriteLine("Thread " & Me.mThreadCounter.ToString() & " is closing.")
   End Sub

   Private Sub WriteLine(ByVal T As String)
      Dim Bytes() As Byte = System.Text.Encoding.UTF8.GetBytes(T & ControlChars.CrLf)
      Me.mS.Write(Bytes, 0, Bytes.Count)
   End Sub

   Private Function Handle(ByVal D As String) As Boolean
      Console.WriteLine("Thread " & Me.mThreadCounter.ToString() & ": " & D)
      If D.ToLower() = "quit" Then
         Me.WriteLine("Bye.")
         Return False
      Else

         'Do parsing here! Return True no matter what.
         Me.WriteLine("Thanks!")

         Return True
      End If
   End Function

End Class

The constructor accepts the TCP client (representing the connected application) and the ThreadCounter variable. The SessionLoop function is the main loop for each thread.

The WriteLine function sends responses to the connected client application and the Handle function is the place where you implement your parsing (or invokes some existing parser). Note that the Handle function must return True, even if your parsing fails. Failed parsing should render in an error message to the client application, but the function should still return True. The returning of the value False, is a signal that the client disconnects.

When you run this code, you will get a warning from your Windows Firewall (I run a Swedish Windows 7 installation). Accept that this program can use your local network.

To make this program actually do something, start a sockets client, like PuTTY. Configure it like so:

Host IP: [Your local IP]
Port: 80
Encoding: UTF-8

Note that we use UTF-8 encoding to convert between byte arrays and strings in the source code, so the TCP client must also use UTF-8.

Since our server is multithreaded and have multiple connection awareness, you can connect more than one sockets client to your application.

Send Quit from your client application to quit.

Categories: Visual Basic 10.

Tags: