Posts
7
Comments
2
Trackbacks
0
April 2009 Entries
C# string formatting
In C++, one uses the sprintf function to build a formatted string like this:

char szOutput[256];
sprintf(szOutput, "At loop position %d.\n", i);



The C# equivalent is the String.Format method [string.format(string, object)].


TrkCmnRec.szMillOrderNbr = String.Format("MO #{0}", i);

Each placeholder in the string is numeric, so if we want to have a string with three placeholders, we would use {0}, {1}, {2},...{n} as shown in this example:

String sA = "Test string"
int i = 10;
Single f = 45.0
String s = String.Format("String = {0}, int = {1}, Single
= {2}", sA, i, f};

String, numeric and date data types have their own formatting specifiers.


Numeric Format Specifiers
Specifier Description Example C#
c Currency; specify the number of decimal places  $12,345.00 string.Format("Currency: {0:c}", iNbr)
d Whole numbers; specifies the minimum number of digits - zeroes will be used to pad the result  12345 string.Format("Whole: {0:d}", iNbr)
e Scientific notation; specifies the number of decimal places  1.2345e+004 string.Format("Exponential: {0:e}", iNbr)
f Fixed-point; specifies the number of decimal places  12345.00 string.Format("Fixed: {0:f3}", iNbr)
n Fixed-point with comma separators; specifies the number of decimal places  12,345.00 string.Format("Fixed formatted: {0:n3}", iNbr)
p percentage; specifies the number of decimal places  1,234,500.00% string.Format("Percentage: {0:p2}", iNbr)
x Hexadecimal  3039 string.Format("Hexadecimal: {0:x}", iNbr)

posted @ Monday, April 13, 2009 3:56 PM | Feedback (0)
Using win32 API in C#
When I was working in VC++, it was relatively easy to include a win32 API function.  All we did was include the header file and then made a call to a function like so:
 
        #include <Mailbox.h>
 
                CMailbox::MbxStatus CMailbox::iCreateMbx() {
        MbxStatus iStatus = mbxSuccess;

        switch ( m_iType ) {
        case mbxReceiver:
        case mbxBoth:
                // for receive type mailboxes we need to create a
                // space for the reception of data
                /* if ( m_hRecvMbx ) CloseHandle( m_hRecvMbx ); */
                m_hRecvMbx = ::CreateMailslot(
                        m_strInName,
                        0,
                        MAILSLOT_WAIT_FOREVER,
                        &( SECURITY_ATTRIBUTES )m_saInfo // previously was NULL
                );

                // if the mailslot already exists, return error
                if ( m_hRecvMbx == INVALID_HANDLE_VALUE ) {
                        m_hRecvMbx = NULL;
                        iStatus = mbxCreateFailure;
                }
                /* if ( m_iType == mbxReceiver ) */ break;

        case mbxSender:
                // for send type mailboxes we need to obtain a
                // target to send to
                iStatus = iSetReceiver( m_strOutName );
                break;
        }

        return iStatus;
            }
 
 
But, now, we have to use interop services because the DLL functions are considered to be in unmanaged code, which does not execute under the control of the CLR.
 
The list of DLL functions are listed in the MSDN in the Platform SDK as System Services.
 
Use DLLImport to specify  an entry point into the DLL for the win32 function that is to be called.  The DLLImport Attribute has four fields: EntryPoint, CharSet, CallingConvention, SetLastError.  From the MSDN library, these are defined as such:
 

DllImportAttribute field

Description

EntryPoint

Specifies the DLL entry point to be called. The default entry point name is the name of the managed method.

CharSet

Controls the name mangling and the way that String parameters should be marshaled. The .NET Compact Framework only supports CharSet..::.Unicode and CharSet..::.Auto. CharSet..::.Auto equates to CharSet..::.Unicode on Windows CE. The default marshaling on the .NET Compact Framework is CharSet..::.Unicode, unlike the .NET Framework that defaults to CharSet..::.Ansi.

Because the .NET Compact Framework does not support the DllImportAttribute..::.ExactSpelling field, the common language runtime automatically searches for an entry point according to the values specified by CharSet.

CallingConvention

Specifies the calling-convention values used in passing method arguments. The default is CallingConvention..::.Winapi, which corresponds to __cdecl on the Windows CE platform.

SetLastError

Enables the caller to use the GetLastWin32Error method to determine whether an error occurred while executing the platform invoke method. In Visual Basic 2005, the default is true; in C#, the default is false.

 
Here's an example of using the DLLImport attribute:
 
        [DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true)]
        public static extern IntPtr CreateFile (
            String lpFileName, int dwDesiredAccess, int dwShareMode,
            ref SECURITY_ATTRIBUTES lpSecurityAttributes, int dwCreationDisposition,
            int dwFlagsAndAttributes, IntPtr hTemplateFile );
 
I want to make a few notes about the way a win32 function is defined:
 
   1. Use the extern keywprd as it defines a function as external, meaning it is implemented outside the C# code.
   2. Verify that the function definition matches its signature found in the DLL
   3. Some functions return a handle or pointer.  In this case use the IntPtr type since it represents a pointer/handle in the .Net world.
   4. On a personal note, I like putting these definitions in its own class.
 
Once a win32 function is defined, we use it as follows:
 
hFile = Win32Api.CreateFile (  
                fileName,                       // Filename
                desiredAccess,                  // Open Read/Write
                desiredShare,                   // Share Reading
                ref security_attributes,        // NULL Security new 15-May-2007
                OPEN_ALWAYS,                    // Creation attrib
                desiredAttrib,                  // File Attributes
                IntPtr.Zero  );                 // NULL  no template
 
posted @ Tuesday, April 07, 2009 9:51 AM | Feedback (0)
Adding items to a listview in C#

I created a listview with two columns as part of a text C# solution to test the use of structures. This list was created with the IDE. When creating a list where you want to show multiple columns, set the listview's view property to Details. I use the IDE to define the columns by selecting columns from the properties list.

To fill in the listview before displaying it, I programmatically add the items in the form's LOAD event.

BTW, I'm moving from VB.Net to C# and adding events to the form is different in C# from VB .Net. Rather than selecting the event from a drop-down list (as in VB), the event is pro grammatically defined as shown here:

this.Load += new EventHandler(frmL1Cmn_Load);
this.Activated += new EventHandler(frmL1Cmn_Activated);

Here's the generated callback

void frmL1Cmn_Activated(object sender, EventArgs e)
{
     throw new NotImplementedException();
}

But, to add this eventhandler is much different than VB. After enter +=, let the IDE instruct you to enter the TAB. It is at this point that the TAB key is depressed. Then, let the IDE prompt you one more time to hit the TAB key to generate the callback function. Select the TAB key a 2nd time and the callback function is generated.

Coming back from this tangent, here's the code in the form's load callback function to populate the listview.

void frmL1Cmn_Load(object sender, EventArgs e)
{
   try
   {
      // Populate lstReadL1Ints with lngVals
      lstReadL1Ints.BeginUpdate();
      lstReadL1Ints.Items.Clear();
      for (i = 0; i < 50; i++)
     {
           ListViewItem row = new ListViewItem(i.ToString());
           int j = i * 2;
           row.SubItems.Add(l1CmnRec[i].lngVal[j].ToString());
           lstReadL1Ints.Items.Add(row);
     }
     lstReadL1Ints.EndUpdate();
     lstReadL1Ints.Refresh();
  }
  catch (Exception ex)
   {
      StringBuilder sb = new StringBuilder();
      sb.Append("Cannot fill in Int listview. ex = ").Append(ex.Message);
     Console.WriteLine(sb.ToString());
   }
}

posted @ Sunday, April 05, 2009 4:50 PM | Feedback (1)
News