Faberc blog website

 Sunday, June 08, 2008

This application shares a webcam source(publisher) with multiple clients(subscribers). It uses duplex HTTP communication, by which the receiver of an initial message will not reply directly to the initial sender, but may transmit any numer of responses over a period till the connection exists. It's a push-style notification: subscribers send subscription messages to publishers , who then send pubblication messages to the subcribers. You can run multiple instance of subscribers over intranet or internet network.

The subscriber software is a WPF application with reflection effect. Note: the Application doesn't work if hosts are located across NAT's.

Webcam Service Publisher application
WPF Webcam Service Subscriber application

Credits: thanks to Sebastien Durel for the beautiful old style png icon (http://www.crystalxp.net).

6/8/2008 11:03:45 AM (W. Europe Standard Time, UTC+01:00)

This is an example of a WPF browser application (aka XBAP) running in a sandbox of your browser with partial trust security permission. Simple and impressive.

AboutMyFamily.xbap

Note: WPF mediaelement couldn't work in windows XP.

6/8/2008 12:50:54 AM (W. Europe Standard Time, UTC+01:00)
 Friday, August 17, 2007

A mix of technology: XAML, WPF, ClickOnce, Web Service. You need to have installed NET framework 3.5.

http://www.livehome.faberc.com/

8/17/2007 11:12:57 AM (W. Europe Standard Time, UTC+01:00)
 Friday, March 10, 2006

Application architects often struggle with two important but competing goals. They want to write a Windows-based rich client application that runs on the desktop because that provides the best stateful, interactive experience for the user.
However, they also want to minimize the effort required to deploy and update their apps—a goal best accomplished using a thin client model. Users care about applications that are easy to use and that will not interfere with other apps on their machine.

ClickOnce, part of version 2.0 of the NET Framework, allows you to deploy Windows-based rich client apps to a desktop by placing the application files on a Web or file server accessible to the client and providing the user with a link.

Take a tour here: http://www.clickoncetoggle.faberc.com

3/10/2006 6:12:30 PM (W. Europe Standard Time, UTC+01:00)
 Saturday, February 18, 2006

We can embedded a resource, like a txt file, forcing the property Build Action=Embedded Resource.

To access programmatically a text file called foo.txt from inside an Assembly whose default namespace is WindowApplication1 you need to write this code:

Dim resFile as String = "WindowApplication1.foo.txt"
'Get a reference to the current assembly
Dim asm as Reflection.Assembly = Reflection.Assembly.GetExecutingAssembly()
Dim str as Stream = asm.GetManifestResourceStream(resFile)
Dim reader as New StreamReader(str)
Dim txt as string = reader.ReadToEnd()
reader.close

For a bitmap, sample.bmp, the code should be:

Dim resFile as String = "WindowApplication1.sample.bmp"
'Get a reference to the current assembly
Dim asm as Reflection.Assembly = Reflection.Assembly.GetExecutingAssembly()
Dim str as Stream = asm.GetManifestResourceStream(resFile)
Dim bmp as New Bitmap(str)

2/18/2006 6:27:06 PM (W. Europe Standard Time, UTC+01:00)
 Sunday, December 11, 2005

To avoid sneaky errors when running your Application in Machine with a different default culture-specific information,
it is good practice to force explicitally the used culture:

Imports System.Globalization

....
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US")
....

The culture is used parsing numerical strings, working with currency calculations, manipulating dates, and so on.

12/11/2005 12:05:55 PM (W. Europe Standard Time, UTC+01:00)
 Saturday, November 19, 2005

Sometimes you could loop in a method waiting for an external event using Application.DoEvents().
So you exposure yourself to a recursive reentering in that method. One simple solution is to define a private boolean field
to check/set/reset in the your methods. But if there are more than one method in that situation you need to duplicate the field
for each one. So a most practical solution is using a unique shared function that takes advantage of reflection.

Private Function IsRecursive() As Boolean
  Dim st As New StackTrace
  Dim i As Integer
  Debug.WriteLine(st.GetFrame(0).GetMethod()) ''boolean IsRecursive()
  Debug.WriteLine(st.GetFrame(1).GetMethod()) ''Void Button1_Click(System.Object,System.EventArgs)
  For i = 2 To st.FrameCount - 1
    Debug.WriteLine(st.GetFrame(i).GetMethod()) ''current stack callings
    If (st.GetFrame(1).GetMethod() Is st.GetFrame(i).GetMethod()) Then Return true
  Next i
  Return False
End Function

This function return TRUE if there are more callings of the method, st.GetFrame(1).GetMethod(), which is using it.
For example:


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles   Button1.Click
  Debug.WriteLine("enter")
  '''''''''''''''''''''''''''''''''''
  If (IsRecursive()) Then Exit Sub
  '''''''''''''''''''''''''''''''''''
  Application.DoEvents()
  ''simulation of a waiting for an event
  System.Threading.Thread.Sleep(1000)
  Debug.WriteLine("exit")
End Sub

Clicking more times the button1 you have:


without IsRecursive() check:
enter
enter
enter
enter
exit
exit
exit
exit
with IsRecursive() check:
enter
enter  ''skipped because the first calling is in progress
enter  ''skipped because the first calling is in progress
enter  ''skipped because the first calling is in progress
exit   ''close the first calling!

11/19/2005 4:39:18 PM (W. Europe Standard Time, UTC+01:00)

A thread can suspend itself temporarily by using the Thread.Sleep shared method which takes a timeout in milliseconds:

''Pause for two seconds
Thread.Sleep(2000)

The Sleep methods works only in the current thread. Using this method is similar to calling the Sleep Windows API function.

11/19/2005 4:30:39 PM (W. Europe Standard Time, UTC+01:00)
 Sunday, November 06, 2005

In some ways, XML is just another data format. However, XML has several advantages over other formats when storing information.

  • XML allows developers to create their own labeled structures for storing information.
  • XML parsing is well-defined and widely implemented, making it possible to retrieve information from XML documents in a variety of environments.
  • XML is built on a Unicode foundation, making it easier to create internationalized documents.
  • Applications can rely on XML parsers to do some structural validation, as well as data type checking (when schemas are used).
  • XML formats are text-based, making them more readable, easier to document, and sometimes easier to debug.
  • Tools are available for XML processing on different platforms, making it simpler to use XML instead of binary formats to exchange complex information streams.
  • XML documents can use much of the infrastructure already built for HTML, including the HTTP protocol and some browsers.

But pay attention: XML isn't appropriate for every situation, however. XML documents tend to be more verbose than the binary formats they replace. They take up more network bandwidth and storage space, or require more processor time for compression. XML parsing can be slower than parsing highly optimized binary formats and can require more memory. However, careful application design can avoid some of these problems.

11/6/2005 7:10:42 PM (W. Europe Standard Time, UTC+01:00)
 Monday, October 31, 2005

Sometimes working with Access DB you need to know the correspondent OleDbType of native type.

The following table lists the most common data types that are used in Microsoft Access and how these data types relate to the Microsoft .NET Framework data types and to the OleDbType enumeration.

Access Type Name Database Data Type OLE DB Type .NET Framework Type Member Name
Text VarWChar DBTYPE_WSTR System.String OleDbType.VarWChar
Memo LongVarWChar DBTYPE_WSTR System.String OleDbType.LongVarWChar
Number: Byte UnsignedTinyInt DBTYPE_UI1 System.Byte OleDbType.UnsignedTinyInt
Yes/No Boolean DBTYPE_BOOL System.Boolean OleDbType.Boolean
Date/Time DateTime DBTYPE_DATE System.DateTime OleDbType.Date
Currency Decimal DBTYPE_NUMERIC System.Decimal OleDbType.Numeric
Number: Decimal Decimal DBTYPE_NUMERIC System.Decimal OleDbType.Numeric
Number: Double Double DBTYPE_R8 System.Double OleDbType.Double
Autonumber (Replication ID) GUID DBTYPE_GUID System.Guid OleDbType.Guid
Number: (Replication ID) GUID DBTYPE_GUID System.Guid OleDbType.Guid
Autonumber (Long Integer) Integer DBTYPE_I4 System.Int32 OleDbType.Integer
Number: (Long Integer) Integer DBTYPE_I4 System.Int32 OleDbType.Integer
OLE Object LongVarBinary DBTYPE_BYTES Array of System.Byte OleDbType.LongVarBinary
Number: Single Single DBTYPE_R4 System.Single OleDbType.Single
Number: Integer SmallInt DBTYPE_I2 System.Int16 OleDbType.SmallInt
Binary VarBinary* DBTYPE_BYTES Array of System.Byte OleDbType.Binary
Hyperlink VarWChar DBTYPE_WSTR System.String OleDbType.VarWChar


* This data type is not available in the Access designer user interface. You must create this data type through code.

10/31/2005 7:33:33 PM (W. Europe Standard Time, UTC+01:00)
 Saturday, October 22, 2005

To have a unique single instance of your Application you need to use a mutex in this way:

Private Shared Function PrevInstance() As Boolean
    Dim IsNewMutex As Boolean
    Dim MutexKey As String
    ''try to create a unique mutex (it has a machine wide scope) associated to my Application
    MutexKey = Application.UserAppDataPath.Replace("\", "_")
    Dim mt As New Mutex(True, MutexKey, IsNewMutex)
    PrevInstance = Not IsNewMutex
End Function


Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
   If PrevInstance() = True Then End  ''if I'm already running then quit
End Sub

It's enough to check PrevInstance() function in the load form event.

10/22/2005 6:48:00 PM (W. Europe Standard Time, UTC+01:00)
 Sunday, October 16, 2005

Sometimes with need to have a unique instance of form to interact with it from any other forms. The solution is using the pattern Singleton:

Public Class Form2
    Inherits System.Windows.Forms.Form

    Private Shared thisInstance As Form2
    Public Shared ReadOnly Property Instance() As Form2
        Get
            If (thisInstance Is Nothing OrElse thisInstance.IsDisposed) Then
                thisInstance = New Form2
                Return thisInstance
            Else
                Return thisInstance
            End If

        End Get
    End Property

End Class

The solution is the keyword shared for a unique variable instance and relative property that returns the current or make a new one.

Now you can call the form2 in this way, for example:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Form2.Instance.Show()
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Form2.Instance.TextBox1.Text = TextBox1.Text
End Sub

10/16/2005 2:44:12 PM (W. Europe Standard Time, UTC+01:00)
 Saturday, October 15, 2005

You need to extend the System.Web.Mail.MailMessage class setting .flags (for framework 1.1 or higher) as follow:

Imports System.Web.Mail.MailMessage
Public Class email
   Inherits Mail.MailMessage
   Public Sub New()
     MyBase.New()
   End Sub
   Public WriteOnly Property AuthInfo() As UserInfo
    Set(ByVal value As UserInfo)
       ''auth: 0=none, 1=Basic, 2=NTLM
       Me.Fields("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1
       Me.Fields("http://schemas.microsoft.com/cdo/configuration/sendusername") = value.UserName
       Me.Fields("http://schemas.microsoft.com/cdo/configuration/sendpassword") = value.Password
    End Set
   End Property
End Class
Public Class UserInfo
    Public UserName As String
    Public Password As String
    Public Sub New(ByVal user As String, ByVal pass As String)
       UserName = user
       Password = pass
    End Sub
End Class

Usage:

Dim m As New email
m.AuthInfo = New UserInfo("user", "password")
m.Body = "Hello to le monde!"
m.From = "user@server4.com"
m.To = "mickymouse@server4.com"
m.Subject = "test"
SmtpMail.SmtpServer = "mail.server4.com"
SmtpMail.Send(m)

email.zip (,48 KB)
ASPNET | DOTNET | VBNET
10/15/2005 11:14:53 AM (W. Europe Standard Time, UTC+01:00)
 Tuesday, July 19, 2005

When you need to make a long task, as calling remote WS, the best way to do not hang the client is using a thread in background and to be notified at the end of result.

With windows form application(main thread) you cannot update the form's control from the thread because it is a secondary thread.

It's important to make a thread safe programming using delegate and InvokeRequired/Control.Invoke methodology.

Eg.(c#):

//delegate per safe Progress bar invocation

private delegate void InvokeWithParam(int value); //the delegate signature need to be the same of method to call
public void UpdateProgressSafeParam(int value)
{
  if (progress1.InvokeRequired) // this routine is calling from a main or secondary thread?
  {
   InvokeWithParam safeMethod=new InvokeWithParam(UpdateProgressSafeParam);
   object[] par=new object [](value);
   progressbar1.Invoke(safeMethod,par); // force the UpdateProgressSafeParam() function [recursion]
   // to run in the same thread of the control(main).
   //So will go in a queue to be recall from the main thread and in that situation it fall down in the else branch!
  }
 else progressbar1.value=value; //I'm in main thread so can update the progressbar control directly!
}

Eg.(VBNET) working with the main form(me.invoke) instead of a control:

delegate Function GetTextDelegate(ByVal ctrl as Control) as String

'This method might run on a non-UI thread (eg: in a timer event of one instance of System.Timers.Timer)
Sub PerformTask()
  'read the Text property of txtUserName UI control
  Dim userName as String
  if Not Me.InvokeRequired then
    userName = GetText(txtUserName) 'direct access is safe
  else
    ' Call the method indirectly by using a delegate
    Dim args() as Object = {txtUserName}  ''the parameters are passed as an array of objects
    userName = CStr(Me.Invoke(New GetTextDelegate(GetText), args))
  end if
  ' userName now contains the value of txtUserName.Text
  ...
  ...
End Sub

Function GetText(ByVal ctrl as Control) As String
   Return ctrl.Text
End Function

7/19/2005 11:32:19 AM (W. Europe Standard Time, UTC+01:00)