.Net ramblings
# Wednesday, May 14, 2014
Java convert array to CSV
I often use CSV for getting data in and out of mobile applications on .Net and Java.  here's a useful code snippet i use to convert an array of generic T objects into a CSV string in Java.  I use tab separated values and \n separated rows in this example.

Usage:
List<Car> cars= ... ; // whatever your array is
String CSV = GetCSV(cars);
public static String ColDelim = "\t", RowDelim = "\n";
 public static String CsvEscape(String s)
 {
     if(s == null)
         return "";
     // any tab characters in the content get stripped out. 
     // any line breaks get replaced with \r which will preserve the CSV structure and can be restored on the other side
     return s.replaceAll(ColDelim, " ").replaceAll("\r", "").replaceAll(RowDelim, "\r");
 }

 public static String CsvUnEscape(String s)
 {
     if(s == null)
         return "";
     return s.replaceAll("\r", "\r\n"); // colDelim is \n so restore any \r
                                         // characters to \r\n
 }
public static <T> String GetCSV(List<T> items)
 {    
     if(items.size() == 0)
         return "";
     StringWriter CSV = new StringWriter();
     
     // output the header row
     T first = items.get(0);
     Field[] fields = first.getClass().getDeclaredFields();
     int i=0;
     for (Field field : fields)                 
         CSV.write((i++ == 0 ? "" : ColDelim) + field.getName());
     CSV.write(RowDelim);
     
     // iterate through each item
     for(T item : items)
     {
         i=0;
         // output each row value
         for (Field field : fields)
         {
             try
             {
                 CSV.write((i == 0 ? "" : ColDelim) + Util.CsvEscape(field.get(item).toString()));
             } catch (IllegalAccessException e)
             {
                 e.printStackTrace();
             } catch (IllegalArgumentException e)
             {
                 e.printStackTrace();
             }
             i++;
         }
         CSV.write(RowDelim);            
     }        
     return CSV.toString();
 }

Wednesday, May 14, 2014 1:55:01 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  Java

# Thursday, January 02, 2014
Google Maps API v3 control for Asp.Net with client side infowindows
I found this opensource google maps v3 control for asp.net, download from nuget:
http://www.nuget.org/packages/Reimers.Google.Map
tutorials etc from the author: http://www.reimers.dk/

the one thing i couldn't work out was how to handle client-side info-window (pop ups) when you click on a map marker.  this control has good support for server side clicks but that isn't what i wanted because it is too slow for the user.  here is the code i put together to get this to work, assuming you have a 'Map' control on your web page called Map1:

private void AddPoint(string desc, double latitude, double longitude, int width, int height, string iconPath, bool HtmlDescription)
{
    Marker m = new Marker(Guid.NewGuid());
    m.Draggable = false;
    m.Icon = new Icon(new Uri(iconPath, UriKind.RelativeOrAbsolute));
    LatLng point = new LatLng();
    point.Latitude = latitude;
    point.Longitude = longitude;
    m.Point = point;
    m.Icon.Size = new Size(width, height);
    if(!HtmlDescription)    // use tooltip "Title"
        m.Title = desc;
    m.Clickable = true;
    m.Description =  desc;

    m.ClientSideHandlers.OnClick = String.Format(@"var infowindow = new google.maps.InfoWindow();
            infowindow.setContent('{0}');
            infowindow.open(reimers.map.Map1, reimers.map.Map1.overlays[{1}]);", desc.Replace("'", "\""), this.Map1.Overlays.Count);
 
    this.Map1.Overlays.Add(m);        
}

Thursday, January 02, 2014 3:22:35 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]  Asp.Net

# Thursday, June 28, 2012
Windows Phone 7 update 7.10.8773.98 released for O2 Ireland

A long awaited Windows Phone 7 update has finally been released on the O2 network in Ireland. The main feature i'm looking for is Wifi tethering, to use the phone as a wifi hotspot. My data package with O2 includes a few Gb every month and it's handy to be able to use this for remote access on a laptop etc. My old Nokia E52 used to have a built-in modem that i could just plug in to the laptop and dial up, this feature is sadly missing from the Windows Phone 7 operating system. Currently i have to pull out the sim card and swap it in to a USB modem to plut in to the laptop. I used to use a wifi tethering app on the E52 called Joiku Spot but it had a remarkably ability to drain a battery in an hour that would typically last 8 days. Since getting the Lumia 800 i have joined the rest of the world of smartphone users who must charge up their phone every day, one step forwards two steps backwards. Well, i usually get 2 days so not as bad as the iphone :)

the first update Zune told me about was 7.10.8112.7, then it went through the update process again and installed 7.10.8773.98. after the update my phone reports firmware version 1600.2487.8107.12070. Disappointingly there is no sign of the Internet Sharing feature in Settings. but wait, apparently i can turn the phone face down to silence an incoming call, whup-de-doo. false alarm, not even that feature is included with this update.

According to the nokia software update availability page, O2 Ireland are still waiting for approval for the Lumia 800. but according to their blog post yesterday if i have the Tango update i should have all the new features. i guess this isn't Tango then, false alarm, in the words of the great Mr Myagi "patience daniel son"...


Thursday, June 28, 2012 11:37:43 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  General

# Tuesday, April 24, 2012
Using XStandard dll on a Win 64-bit

I have a winforms app that ran into trouble with the XStandard XHTML component on a 64 bit system. I was registering the OCX file from code if it didn't register via the MSI. found this kb article useful, and then called the appropriate version of regsvr32.exe based on the platform.

try
{
    // attempt to load the control 
    this.pageEditor = new PageEditor();
}
catch (System.Runtime.InteropServices.COMException)
{
    // control loading failed
    string ocxPath = Path.Combine(Application.StartupPath, "Xstandard.ocx");
    try
    {
        // OCX is not registered, register it now using the Syswow64 version of regsvr32.exe if we are using a 64 bit system
        Process p = new Process();
        p.StartInfo.FileName = @"regsvr32.exe";
        p.StartInfo.WorkingDirectory = (IntPtr.Size == 8) ? @"%SystemRoot%\Syswow64" : @"%SystemRoot%\system32";  // IntPtr is size 8 on a 64 bit system
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.Arguments = String.Format("/s \"{0}\"", ocxPath);
        p.Start();
        p.Close();
        MessageBox.Show("Please restart... (OCX file registered)", "Restart");
        Application.Exit();
        return;
    }
    catch (Exception ex)
    {
        MessageBox.Show("Unable to register OCX file: " + ex.Message, "Error");
        Application.Exit();
        return;
    }
}

Tuesday, April 24, 2012 8:51:07 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  .Net Windows Forms

# Monday, January 16, 2012
.Net windows forms Multi-line ComboBox / text-wrapping
seems like the most basic requirement for a list control... but there we are.  use this as a replacement for the System.Windows.Forms.ComboBox.

using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Collections.Generic;

namespace HortLaptopApp
{
    class ComboBoxWrap : ComboBox
    {
        // ref http://stackoverflow.com/questions/1245530/unable-to-set-the-dropdownheight-of-combobox
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);

        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;        // x position of upper-left corner
            public int Top;         // y position of upper-left corner
            public int Right;       // x position of lower-right corner
            public int Bottom;      // y position of lower-right corner
        }

        public const int SWP_NOZORDER = 0x0004;
        public const int SWP_NOACTIVATE = 0x0010;
        public const int SWP_FRAMECHANGED = 0x0020;
        public const int SWP_NOOWNERZORDER = 0x0200;

        public const int WM_CTLCOLORLISTBOX = 0x0134;

        private int _hwndDropDown = 0;

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_CTLCOLORLISTBOX)
            {
                if (_hwndDropDown == 0)
                {
                    _hwndDropDown = m.LParam.ToInt32();

                    RECT r;
                    GetWindowRect((IntPtr)_hwndDropDown, out r);

                    //int newHeight = 0;
                   // for(int i=0; i<Items.Count && i < MaxDropDownItems; i++)
                    //    newHeight += this.GetItemHeight(i);

                    int total = 0;
                    for (int i = 0; i < this.Items.Count; i++)
                        total += this.GetItemHeight(i);
                    this.DropDownHeight = total + SystemInformation.BorderSize.Height * (this.Items.Count + 2);
           

                    SetWindowPos((IntPtr)_hwndDropDown, IntPtr.Zero,
                        r.Left,
                                 r.Top,
                                 DropDownWidth,
                                 DropDownHeight,
                                 SWP_FRAMECHANGED |
                                     SWP_NOACTIVATE |
                                     SWP_NOZORDER |
                                     SWP_NOOWNERZORDER);
                }
            }

            base.WndProc(ref m);
        }

        protected override void OnDropDownClosed(EventArgs e)
        {
            _hwndDropDown = 0;
            base.OnDropDownClosed(e);
        }

        public ComboBoxWrap() : base()
        {
            // add event handlers
            this.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawVariable;
            this.DrawItem += new DrawItemEventHandler(ComboBoxWrap_DrawItem);
            this.MeasureItem += new MeasureItemEventHandler(ComboBoxWrap_MeasureItem);
        }

        void ComboBoxWrap_MeasureItem(object sender, MeasureItemEventArgs e)
        {
            // set the height of the item, using MeasureString with the font and control width
            ComboBoxWrap ddl = (ComboBoxWrap)sender;
            string text = ddl.Items[e.Index].ToString();
            SizeF size = e.Graphics.MeasureString(text, this.Font, ddl.DropDownWidth); 
            e.ItemHeight = (int)Math.Ceiling(size.Height) + 1;  // plus one for the border
            e.ItemWidth = ddl.DropDownWidth;
            System.Diagnostics.Trace.WriteLine(String.Format("Height {0}, Text {1}", e.ItemHeight, text));
        }

        void ComboBoxWrap_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index < 0)
                return;

            // draw a lighter blue selected BG colour, the dark blue default has poor contrast with black text on a dark blue background
            if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
                e.Graphics.FillRectangle(Brushes.PowderBlue, e.Bounds);
            else
                e.Graphics.FillRectangle(Brushes.White, e.Bounds);
            
            // get the text of the item
            ComboBoxWrap ddl = (ComboBoxWrap)sender;
            string text = ddl.Items[e.Index].ToString();

            // don't dispose the brush afterwards
            Brush b = Brushes.Black;
            e.Graphics.DrawString(text, this.Font, b, e.Bounds, StringFormat.GenericDefault);
            
            // draw a light grey border line to separate the items
            Pen p = new Pen(Brushes.Gainsboro, 1);
            e.Graphics.DrawLine(p, new Point(e.Bounds.Left, e.Bounds.Bottom-1), new Point(e.Bounds.Right, e.Bounds.Bottom-1));
            p.Dispose();
            
            e.DrawFocusRectangle();
        }
    }
}


Monday, January 16, 2012 10:08:16 AM (GMT Standard Time, UTC+00:00)  #    Comments [1]  .Net Windows Forms

# Sunday, January 01, 2012
Locating the TypeGuessRows registry key on Windows 64-bit operating systems

Data truncated to 255 characters with Excel Jet/ODBC driver: http://support.microsoft.com/kb/189897

Solution: http://support.sas.com/kb/31/765.html
My Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Jet\4.0\Engines\Excel

Set to 0 to avoid the truncation problem!


Sunday, January 01, 2012 10:19:39 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]  .Net General | Database

# Wednesday, December 28, 2011
Excel interop with .Net / Server 2008
I'm using Asp.Net to open excel files and read the values cell by cell, normally i prefer to import Excel files as a datatable, but some documents don't fit the strict rows/columns format required for importing into a DataTable.  the code i'm using is based on this from dotnetperls.  worked fine for the most part on my dev PC but I had a few issues trying to get this to work on a 32bit version of excel on a 64 bit Windows 2008 server.
here's what i had to do to get it working:
  • disable macros (throwing exceptions opening the workbook), requires a reference to the Microsoft.Office.Core assembly:
    excelApp.AutomationSecurity = Microsoft.Office.Core.MsoAutomationSecurity.msoAutomationSecurityForceDisable;   // disable macros
  • give launch / open permissions to the Excel application in DCOM config, this was tricky because it isn't shown in a 64 bit OS if the program is 32 bit, i found the answer here.
  • set the identity in DCOM for Excel to the interactive user.



Wednesday, December 28, 2011 9:16:30 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]  .Net General | Asp.Net

# Friday, October 14, 2011
Asus P6T deluxe v2 overclock settings with Intel i7 920
Found a safe/low-temp overclock @ 3.6Ghz for this board. Using 1600Mhz DDR3 RAM. standard air cooling in a z-machine GT1000 case.

RAM set to XMP profile #1. 8/8/8/24/1.66V/1.35v
BCLK:180
PCIE:100
Speedstep/turbotech:enable
RAM:~1450 Mhz
CPU Volt:1.25V
QPI/DRAM:1.35V
DRAM bus:1.66v

everything else auto/default
CPU Fan and chassis fan set to Standard profile.

44c @ idle. 66c under orthos CPU stress test.  The 1.25 CPU voltage keeps the temps nice and low, and it's very stable.  the 920 does this o'c with ease, could probably go lower but stability is more of a priority for a software dev PC.


Friday, October 14, 2011 1:42:08 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  General

# Monday, January 24, 2011
Playing a DVD remotely from a network share
you can rip a DVD and then stream the file to a remote computer, or with VLC media player you can stream the DVD itself, but that takes a bit of setting up.  i wanted to pop a DVD into my desktop PC and then play it remotely from a netbook plugged in to the TV.  so i share out the DVD drive on the desktop, all well and good, i can see the VIDEO_TS and AUDIO_TS folders on the netbook, but there isn't an Autoplay option or any way to 'start' the DVD.  i found a useful tip from the VLC forums, you can drag the VIDEO_TS folder into VLC (on the netbook, for example) and then it will start playing the DVD, with full support for menus and chapters etc.  The bit i got stuck on was that you have to start the DVD for a few seconds on the host PC (desktop in my case) which authenticates the disc and allows it to be streamed. 

not very high tech, but handy, if you ever find yourself without a DVD player.


Monday, January 24, 2011 8:43:52 PM (GMT Standard Time, UTC+00:00)  #    Comments [0]  General

# Tuesday, September 14, 2010
Gridview Delete via LinqDataSource fails with ChangeConflictException: Row not found or changed
if you use SqlMetal to generate DataContext classes against an SQL database, you might run into some problems with GridView and deleting a row, when using a LinqDataSource.
this was a very frustrating problem to track down, apparently there is a bug in the LinqDataSource with datetime fields.  i kept getting this error: ChangeConflictException: Row not found or changed
and there was no apparent reason why it was happening, because the same code worked for other tables.  I eventually narrowed it down to the only difference between the two tables, a non nullable datetime field. changing this field to nullable removed the problem.
this thread was useful in troubleshooting the problem.
i also found that calling DataBind() on the LinqDataSource before re-binding the GridView helped get rid of this error message.


Tuesday, September 14, 2010 12:50:05 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  .Net General | Database