Navigation


VFPConversion Blog

This blog is dedicate to the adoption of technologies such as Microsoft .NET or SQL Server in addition to Visual FoxPro. Expect posts on this blog to be fairly technical, as this blog is geared towards developers, testers, and technical decision makers.

Content Area Footer

Wednesday, July 20, 2005
Some Interesting Stats...

Microsoft recently posted some interesting stats about VFP developers.

One interesting set of data looks at the current group of VFP developers and what other products they use:

  • 20% of VFP developers also use VB6, 13% VB.NET, 12% use C#, 10% use Java, and 8% use C++
  • 26% of VFP developers also use VS.NET, 21% ASP.NET

So at least about a quarter of VFP developers (not counting people who have moved off to .NET) are also using .NET in some form. This means that close to three quarters of the current VFP community has not yet adopted .NET. However, a lot of them are generally interested in .NET, as the following stat shows:

  • 31% of current VFP developers who have not looked into .NET yet are planning to do so within the next 2 years

Or on other words: About 40% of the remaining three quarters plan to adopt .NET in the next 2 years. This will bring us to a total of 57% (or more) of current VFP developers using .NET within 2 years. This is very interesting, because it means that counting the people who used VFP 12 months ago but have now moved to .NET (which are not included in the above numbers), the majority of VFP developers will adopt .NET. (Well, even not counting those that have already moved, this statement is still true).

What is also interesting (and cool) is that 98% of the current VFP developers (and this also includes EPS!) predict that they will still use VFP 12 months from now in some capacity (for EPS, this probably applies much longer).

VFP developers also seem very open minded when it comes to databases:

  • 55% use SQL Server
  • 22% use MSDE (the "small version of SQL Server")
  • 21% use MySQL (the "open source equivalent to SQL Server")
  • 14% use Oracle
  • 4% use DB2

One could interpret this as "almost all VFP developers use a non-VFP database". However, while there seems to be some truth to that (most large apps certainly seem to be using a dedicated database server product these days), a full 89% still use DBF files, at least in addition to other databases (if not exclusively).

At EPS and VFPConversion.com, we think these are pretty amazing and encouraging numbers. Adopting technologies like .NET and SQL Server in combination with Visual FoxPro certainly makes for a very powerful toolbox!



Posted @ 10:25 PM by Egger, Markus (megger@eps-software.com) -
Comments (1)


Monday, July 18, 2005
Exposing strongly-typed VFP COM objects to .NET

VFP is a weakly-typed language by nature, and that can cause problems when consuming VFP objects from .NET through COM Interop. One way to improve the developer’s experience on the .NET side is by adding type information in the VFP code to make the VFP object a "little more strongly typed" (even though VFP still won’t enforce type-safety internally, allowing developers to do things like assigning logical values to string properties from within VFP ). Here are some things one can do to make exposed elements more usable in .NET:

  • Specify the type of method parameters, as well the type of the return value
  • Make use of the COM_Attrib array in order to provide information that gets generated in the object's type-library describing properties exposed by the object. 
  • Create well-defined interfaces that describe what’s exposed by other objects that are used by the COM object.

For instance, consider the simple Employee business object:

Define Class Employee As Biz Of Biz.prg OlePublic
   Implements Iemployeedata In "DataObjectInterfaces.EmployeeData"
  
  
*-- Keeps a Reference To the Data Object.
   oData = Null
   *-- Properties For Error handling Info.
   lError = .F.
   cErrorMsg = ""

   Procedure GetEmployeeByPK(String employeePK) As Boolean
      *-- Run whatever Code populates the oData Member.
      This.oData = Createobject("Empty")
      AddProperty(This.oData, "EmployeeID", 99)
      AddProperty(This.oData, "EmployeeName", "Jane Doe")
   Endproc

   Protected Procedure Iemployeedata_get_EmployeeID() As Number;
      HelpString "Employee ID"
      Return This.oData.EmployeeID
   Endproc

   Protected Procedure Iemployeedata_put_EmployeeID(eValue As Number @); 
      HelpString "Employee ID"
      This.oData.EmployeeID = eValue
   ENDPROC

   Protected Procedure Iemployeedata_get_EmployeeName() As String;
      HelpString "Employee Name"
      Return This.oData.EmployeeName
   ENDPROC

   Protected Procedure Iemployeedata_put_EmployeeName(eValue As String @);
      HelpString "Employee Name"
      This.oData.EmployeeName = eValue
   Endproc

   *-- Property's attributes for COM interface.
   Dimension lError_COMATTRIB[4]
   lError_COMATTRIB[1] = COMATTRIB_READONLY
   lError_COMATTRIB[2] = "Indicates whether an error has occurred inside the object."
   lError_COMATTRIB[3] = "lError"
   lError_COMATTRIB[4] = "Boolean"

   Dimension cErrorMsg_COMATTRIB[4]
   cErrorMsg_COMATTRIB[1] = COMATTRIB_READONLY
   cErrorMsg_COMATTRIB[2] = "Info about last error."
   cErrorMsg_COMATTRIB[3] = "cErrorMsg"
   cErrorMsg_COMATTRIB[4] = "String"

   Dimension oData_COMATTRIB[4]
   oData_COMATTRIB[1] = .F.
   oData_COMATTRIB[2] = "Keeps master data object."
   oData_COMATTRIB[3] = "oData"
   oData_COMATTRIB[4] = "IDispatch"
Enddefine

Note that:

  • The GetEmployeeByPK method defined one parameter of type string, and the return type is a Boolean (logical value in VFP).
  • COM Attrib arrays are created for public properties, specifying more information about each one of them (that information is used when the type-library for the COM object is created).
  • The class exposes an oData member, which is created on the fly. In order to expose that in a strongly-typed manner, the class implements an IEmployeeData interface (listed below), which in turn determines what members are exposed by the oData object.

The IEmployeeData interface is created off of the following class:

// Declare variable and create business object.
EmployeeClass oBiz = new EmployeeClass();

// Call method to retrieve employee.
if (oBiz.GetEmployeeByPK(employeeID))
{
   // Get a reference to the business object as a data interface.
   Iemployeedata oData = oBiz as Iemployeedata;

   // If we got the reference properly, we can start using the data.
   if (oData != null)
   {
      this.txtEmployeeID.Text = oData.EmployeeID;
      this.txtEmployeeName.Text = oData.EmployeeName;
   }
}

An article about this will soon be posted to the www.vfpconversion.com web-site.



Posted @ 12:19 PM by Lassala, Claudio (lassala@foxbrasil.com.br) -
Comments (2)


Monday, July 11, 2005
Why Interfaces Are Important

.NET supports the concept of interfaces in addition to classes. So does VFP. However, in VFP interfaces are only required in special scenarios, while in .NET, they are used all the time. This is something VFP developers need to get used to.

But why is that exactly? There are a number of reasons why interfaces are incredibly important and useful. This post represents just one example scenario. Before we look at that, we need to address the question "what exactly is an interface". An interface is the definition of methods and properties and object has. In VFP, when we create an object, it just ends up with all the methods and properties define (which is also true in .NET). With a specific interface definition however, it is possible to set the expectations. This is very important for code reuse and generic programming.

Let's examine a simple VFP example: Let's say I want to create a toolbar that has a save button. Whenever that save button gets clicked, it will call the Save() method on the active form. This means that I expect that the form has a Save() method. In other words: I expect that the form "implements an interface that has the Save() method". In VFP, I can call the Save() method in the following fashion:

_Screen.ActiveForm.Save()

In VFP, we do not have to specify that the active form implements a certain interface. If a form has a Save() method, it will get called. This makes things very easy, but it also has a significant downside: If the currently active form does not happen to have a Save() method (perhaps because the developer forgot to add it), then the system will crash during runtime. There is no way for the compiler to verify whether or not the ActiveForm object indeed has a Save() method.

.NET's strong typing solves this problem. In .NET, object references always are of a specific type (or class... which is really the same as a type in .NET). So let's say we have a reference to the active form called "ActiveForm". (For now, we do not care how that came to be). This reference would not just be typed as an object (as in VFP), but it would be of type "System.Windows.Forms.Form". In VB.NET, we could define this like so:

Dim ActiveForm As System.Windows.Forms.Form
ActiveForm.Save()   ' Fails!!!

However, the "Form" class does not have a Save() method. Therefore, the compiler would not let us get away with defining a reference as "Form" and call a Save() method. Instead, we would have to create a special form class that does have a Save() method:

Public Class SaveForm
    Inherits System.Windows.Forms.Form

    Public Function Save() As Boolean
        ' Save and return success code in subclasses
        Return False

    End Function
End Class

Now, we can use this form to define the type of our variable, and are thus able to call the Save() method on it, since the compiler can verify that every object reference that can be stored in this variable must have a Save() method:

Dim ActiveForm As SaveForm
ActiveForm.Save()   ' Works

So far so good. The problem with this is that inheritance is a very static technique. Just like in VFP, we can only subclass any class from one parent class in .NET. And in this scenario, that means we already maxed out our options. So if we have some cool class that we wanted to use as the parent class, then we can't, because we always need to inherit from "SaveForm". Once again, in VFP that is not a problem, because we could just add a Save() method to our new form. But then again, that would lead to a quality problem that we really wouldn't be happy with in modern development. And that's where Interfaces come into play!

Interfaces allow us to define that a certain object has certain methods, without wasting an inheritance relationship. So instead of creating a class, we can define an interface:

Public Interface ISaveForm
    Function Save() As Boolean
End Class

We can now create a form class that subclasses from whatever other form class we want it to subclass, and in addition, we always implement the interface we just defined:

Public Class MyCoolForm
    Inherits SomeOtherForm
    Implements ISaveForm

    Public Function Save() As Boolean
       
' Save here...
        Return True

   
End Function
End Class

When we now talk to an object created from this class, we can look at it in several different ways: We can look at it as a generic form (without a Save() method), or we can look at it as type "MyCoolForm" (which has a Save() method, but our toolbar button would not know that since it has no concept of what "MyCoolForm" is), or as type "ISaveForm" (which has only a Save() method and the toolbar button can use it). So we can do this:

Dim ActiveForm As ISaveForm  ' Uses the Interface!!!
ActiveForm.Save()   ' Works, no matter what it is subclassed from

The nice thing is that this is all very easy to do (once you get comfortable with this new concept), and it is very easy to quality control, since the compiler can verify 100%, that our code will work at runtime.



Posted @ 2:07 PM by Egger, Markus (megger@eps-software.com) -
Comments (2)


Friday, July 01, 2005
Care to Enumerate?

Have you checked out .NET enums yet? No? Well, you should!

Enums are a handy way to define a limited list of setting. Let's say you have an object that stores different types of phone numbers. How do you define the types? Perhaps you have a PhoneType property, which might be a numeric type. 1 stands for office phone, 2 for home phone, 3 for cell phone, and so forth. The problem with this approach is that it is hard to memorize all these settings. As a result, it is easy to get the mixed up, or assign a value that is invalid altogether. In .NET, there is a very simply solution to that particular problem: You define an "Enum". This can be done like so:

public enum PhoneTypes
{
    Office = 1,
    Home = 2,
    Cell = 3
}

This defines a new type/object (remember that there is no difference in .NET between a data type and an object) which derrives from the .NET internal type "Enum". This is the fancy way of saying "we created something that is an object and it behaves according to the rules of enums". This means, we can now use this enum in our code:

PhoneTypes myType;

This defines a local variable called "myType", and it is of type "PhoneTypes". This would be kind of like the following statement in VFP (assuming this was available in VFP, which it isn't):

LOCAL myType AS PhoneTypes

We can of course also assign a value to our variable:

myType = PhoneTypes.Cell;

What's cool is that we do not have to remember that a 3 indicates a cell phone. We just say "PhoneTypes.Cell" as we defined it in the enum. Also, we do not even have to remember which PhoneTypes are available, because as soon as we type "PhoneTypes." C# IntelliSense provides a list of all available PhoneTypes. (Note: If you do this in VB.NET, the editor works even better by showing the list of available phone types as soon as you type the "=" sign...). Note also, that we have to pick one of the available options, if we pick something else, then the compiler catches the problem and won't let us get away with it. (Although there are some "expert tricks" to cheating that system, but we will ignore those for now...).

Of course, we can also expose properties that take advantage of this new type

public PhoneTypes Type
{
    get
    {
        return wherever the value comes from...
    }
    set
    {
        wherever we want to store the value to = value;
    }
}

What's also very cool is that it is very easy to store the actual numeric value to the database (or retrieve it from there). Let's say phoneRow is an ADO.NET DataRow out of a DataTable in a DataSet, and "iType" is an integer field in the underlying SQL Server table. In this case, our property could be coded like this:

public PhoneTypes Type
{
    get
    {
        return (PhoneTypes)phoneRow["iType"];
    }
    set
    {
        phoneRow["iType"] = (int)value;
    }
}

In other words: We can simply cast any enum to an integer value, and vice-versa. If our database field has the integer value 2, and we cast it to our enum, it will end up as "PhoneTypes.Home". Pretty slick, hm?



Posted @ 10:49 PM by Egger, Markus (megger@eps-software.com) -
Comments


 

 

 

 

 

 

 

Syndication RSS 2.0 RSS 2.0

All My Blogs:
My personal blogs:
Dev and Publishing Dev and Publishing
Travel and Internat. Living Travel and Internat. Living
Other blogs I contribute to:
Milos Blog (US) Milos Blog (US)
VFPConv. Dev Blog (US) VFPConv. Dev Blog (US)
VFPConv. Dev Blog (DE) VFPConv. Dev Blog (DE)

 

Blog Archives
All Blog Posts

2009
    February (1)
2008
    November (1)
    October (2)
    April (1)
    March (1)
2007
    August (1)
    July (1)
    June (2)
    March (1)
    January (1)
2006
    December (1)
    November (2)
    October (1)
    September (1)
    August (1)
    April (3)
    March (2)
    February (1)
    January (1)
2005
    December (2)
    November (3)
    October (2)
    September (7)
    August (3)
    July (4)
    June (12)

 

 

 

This Blog is powered by MilosTM Collaboration Components.