Search  
Thursday, May 24, 2012 ..:: Forum ::.. Register  Login
 Forum Minimize
Pentru a putea posta mesaje trebuie să vă înregistraţi.
Notă: Mesajele cu conţinut jignitor sau ilegal (inclusiv cereri de soft piratat) nu sunt acceptate şi vor fi şterse imediat .

Pentru a primi raspunsuri rapide si corecte, scrieti in mesaj ce intentionati sa faceti, ce mesaj de eroare primiti, in ce context si in urma caror actiuni. De asemenea, mentionati versiunea de FoxPro in care lucrati!
Dacă nu specificați versiunea, se consideră VFP 9.0 SP2.

SearchForum Home
  Visual FoxPro  .NET Interop  Ghid migrare Fo...
 Ghid migrare FoxPro - C#
 
 7/30/2007 4:57:02 PM
User is offlineaxelsoft
8 posts
www.axelsoft.info


Ghid migrare FoxPro - C#
 (N/A)

3. Conversie Visual FoxPro in C# _05 _2005

Nu mai stiu unde am gasit acest ghid, dar mie mi-a fost foarte util (n-am stiut sa fac Attach pe acest Forum).
Scuze daca ce am pus eu aici este din carte de care tot vorbiti aici.
http://www.tiobe.com/tpci.htm

Ion STANCA (53 ani, asta ca sa le dau incredere tinerilor ca nu este tirziu sa migreze spre C#)

 

4. Language Comparison Tables

The tables in this appendix provide a side-by-side comparison of Visual FoxPro, C#, and VB.NET’s features.

Operator Comparison

Table 1 is an adaptation of the table found in the .NET Help topic “Operators compared in different languages”.

Table 1. A comparison of Visual FoxPro, C#, and VB.NET operators

 

Visual
FoxPro

C#

VB.NET

Math

 

 

 

Addition

+

+

+

Subtraction

-

-

-

Multiplication

*

*

*

Division

/

/

/

Modulus

%; MOD

%

Mod

Exponentiation

^, **

n/a

^

Assignment

 

 

 

Assignment

=

=

=

Addition

+

+=

+=

Subtraction

-

-=

-=

Multiplication

*

*=

*=

Division

/

/=

/=

Integer Division

n/a

/=

\=

Concatenate

+, -, $

+=

&=

Modulus

%

%=

n/a

Left Shift

BITLSHIFT()

<<=

n/a

Right Shift

BITRSHIFT()

>>=

n/a

Bitwise-AND

BITAND()

&=

n/a

Bitwise-exclusive-OR

BITXOR()

^=

n/a

Bitwise-inclusive-OR

BITOR()

|=

n/a

Relational and equality

 

 

 

Less than

Less than or equal to

<=

<=

<=

Greater than

Greater than or equal to

>=

>=

>=

Equal

=

==

=

Not Equal

<>, #, !=

!=

<> 

Compare two object reference variables

COMPOBJ()

==

Is

Compare object reference type

n/a

x is Class1 (see also as and typeof)

TypeOf x Is Class1

Table 1, continued

 

Visual
FoxPro

C#

VB.NET

Relational and equality (continued)

 

 

 


 

Compare strings

=

==

-or- String.Equals()

=

 

 

 

 

Concatenate strings

+

+

&

Shortcircuited Boolean AND

n/a

&&

AndAlso

Shortcircuited Boolean OR

n/a

||

OrElse

Shift

 

 

 

Left Shift

n/a

<< 

n/a

Right Shift

n/a

>> 

n/a

Scope Resolution

 

 

 

Scope resolution

::

. and base

.

Postfix

 

 

 

Array Element

( ), [ ]

[ ]

( )

Function call

( )

( )

( )

Type cast

n/a

(type)

CInt, CDbl, …, CType

Member selection

.

.

.

Postfix increment

n/a

++

n/a

Postfix decrement

n/a

--

n/a

Unary

 

 

 

Indirection

n/a

* (unsafe mode only)

n/a

Address of

n/a

& (unsafe mode only; also see fixed)

AddressOf

Logical-not

!

!

Not

One’s complement

BITNOT()

~

Not

Prefix increment

n/a

++

n/a

Prefix decrement

n/a

--

n/a

Size of type

n/a

sizeof

n/a

Bitwise

 

 

 

Bitwise-AND

BITAND()

&

And

Bitwise-exclusive-OR

BITXOR

^

Xor

Bitwise-inclusive-OR

n/a

|

Or

Logical

 

 

 

Logical-AND

AND

&&

And

Logical-OR

OR

||

Or

Conditional

 

 

 

Conditional

IIF

?:

IIf Function ()

Pointer to member

 

 

 

Pointer to member

n/a

.  (Unsafe mode only)

n/a

Reference

 

 

 

Reference

n/a

n/a (use reference types)

@

 


 

Keyword Comparison

Table 2 is an adaptation of the table found in the .NET Help topic “Keywords compared in different languages”.

Table 2. A comparison of Visual FoxPro, C#, and VB.NET keywords

Purpose

Visual
FoxPro

C#

VB.NET

Declare a variable

[implicit declaration]; also PUBLIC, LOCAL, PRIVATE

declarators (keywords include user-defined types and built-in types)

Private, Public, Friend, Protected, Static, Shared, Dim

Declare a named constant

#DEFINE

const

readonly

Const

Create a new object

CREATEOBJECT,

NEWOBJECT

new

New

Assign a variable to an object

=, also STORE

=

=

Function/method does not return a value

Void (COM Servers only)

void

Sub

Overload a function or method (Visual Basic: overload a procedure or method)

(No language keyword required for this purpose)

(No language keyword required for this purpose)

Overloads

Refer to the current object

This, ThisForm

this

Me

Make a nonvirtual call to a virtual method of the current object

n/a

 

MyClass

  DATE() DateTime.ToDay.ToString()  

Retrieve character from a string

SUBSTR()

[ ]

GetChar

Declare a compound data type (Visual Basic: Structure)

n/a

struct, class, interface

Structure <members> End Structure

Initialize an object (constructors)

Init event

Constructors, or system default type constructors

Sub New()

Terminate an object directly

Destroy event

n/a

n/a

Method called by the system just before garbage collection reclaims an object

Destroy event

destructor

Finalize

Initialize a variable where it is declared

n/a

// initialize to a value

int x = 23

// or use default constructor:

int x = new int();

Dim x As Long = 5

Dim c As New Car(FuelTypeEnum.Gas)

 

Take the address of a function

n/a

delegate

AddressOf (For class members, this operator returns a reference to a function in the form of a delegate instance)

Declare that an object can be modified asynchronously

n/a

volatile

n/a


Table 2, continued

Purpose

Visual
FoxPro

C#

VB.NET

Force explicit declaration of variables

_VFP.LanguageOptions 

n/a. (All variables must be declared prior to use)

Option Explicit

Test for an object variable that does not refer to an object

EMPTY(); ISNULL()

obj == null

obj = Nothing

Value of an object variable that does not refer to an object

n/a

null

Nothing

Test for a database null expression

ISNULL()

n/a

IsDbNull

Test whether a Variant variable has been initialized

EMPTY()

n/a

n/a

Define a default property

n/a

by using indexers

Default

 

1. Conversie Visual FoxPro in C# _05 _2006

It is very usual that our clients be interested in checking information from the Web and even from an Intranet using the Explorer. C# enables us to perform this task in a very simple and friendly way.

However, it is possible that you never programmed in C and also that you have never even programmed in another language except for FoxPro. This makes you afraid when you have to face a new Web project.

This is the first part of an article oriented to the introduction of Visual FoxPro developers in a simple way, to the C# language, to the .NET platform and to some of the most common libraries in the framework.

In this first issue, I shall focus on comparing the languages in respect of their more basic elements: control structures, variable declaration, error handling and, needless to say when addressing the FoxPro community, to data access.

In the next part we shall see in more detail how to use from C# a component made in Visual FoxPro, but first we have to see how to configure the IIS, how to create a new project in C#, how to configure a grid and even how to pass parameters between forms.

C# round 1 - Comparing the languages

To begin with it is important to remember that C# is one of the standard options that .NET has to build developments for the web. For this reason, further on we shall talk about ASPX and C#, because they are both intimately related.

I am going to walk you briefly through C#, showing you the similarities and the differences between both languages, so it will be easier for you to understand and enable you to make a visual comparison.

Something which is very important to remark is the fact that C# is case sensitive, that is, it makes a distinction between upper and lower case. For that reason, you have to be specially careful, because for is not the same as For.

It is also important to remember that most code lines require a colon at the end of the line. Fortunately, the development environment is very friendly, highlighting an error by underlining in red (as if it were a Word spelling error). In the same manner, it auto-adjusts a block's tabulation by closing a curly bracket or when copying text from another place. It also colors the syntax just like Visual FoxPro. For this reason if, when typing a command it does not become colored, then it is better to review the line, to see that an error was not made.

Commands such as if, case or for in C# are handled in a slightly different way than in Visual FoxPro, because these commands use curly brackets {} to show the beginning and the end of a code block, in the following way:

Table 1: If-EndIf

Visual FoxPro C#
If cNombre = "pablo"
   * commented with an asterisk
   * Process something ...
Else
   * Process more ...
EndIf
if (cNombre == "pablo")
   {
   // commented with double bars
   // Process something ...
   }
else
   {
   // Process more ...
   }

In the case of C# there is no ENDIF, ENDCASE, ENDDO nor ENDFOR or NEXT, because when you close the curly bracket you are ending the instruction. Also in the case of if there are two points to consider...

  1. The logic condition in the if must be surrounded by two brackets.
  2. In C# one sign is not the same as two, so:
    a.  An equal sign assigns a value as for example age = 44,
         in this case I am assigning the value 44 to the variable age.
    b.  Two equal signs compare one value, where age == 4 means
         that I want to know if the value of the variable age is 44.

NOTE: If the command only has one line of code, it is not necessary to put the curly brackets of beginning and end of block.

Table 2: Do Case-EndCase

Visual FoxPro C#
Do Case
   Case nValue = 1
      * Process something ...
   Case nValue = 2
      * Process something ...
   Case nValue = 3
      * Process something ...
   OtherWise
      * Process something ...
EndCase
switch(nValue)
   {
   case 1;
   // * Process something ...
      break;
   case 2;
   // * Process something ...
      goto case 1;
   case 3;
   // * Process something ...
      break;
   default
   // * Process something ...
      break;
   }

Evidently, the C# version is more structured, however it is easy to remark the more important differences.

  • The whole logic of the case should point to a single variable indicated at the beginning.
  • The variable should be place between brackets.
  • A break command should indicate the wish to leave the case;
    otherwise the following cases will continue to be evaluated.
  • You can go from one case to another using goto case n.
  • The equivalent of Otherwise is default.

Table 3: For-Next

Visual FoxPro C#
For i = 1 to 30
   * * Process something ...
Next
for (int i=1; i<=30; i++ )
   {
    // * Process something ...
   }

As can be seen, the C# version is a bit more complex at first sight, because is is separated into three parts:

  • The first one indicates the variable (which can be declared in situ)
  • In second place is the loop condition
  • In third place is the increment (STEP in case of Visual FoxPro) where the pointer variable is incremented by 1 on 1.

The use if i++ is interpreted as variable i adding 1 to its present value with the following combinations:

  • i++ is the same as i=i + 1
  • i+= 10 is the same as i=i + 10
  • i-- is the same as i=i - 1

Within the loop you could also use ++i which means that, instead of adding 1 at the end of the processing of the code snippet, it will be added before processing the code snippet.

Table 4: Do While-EndDo

Visual FoxPro C#
Local i as integer
I = 30
Do While i > 0
   i = i - 1
   * Process something ...
EndDo
int i=30;
while (i>0)
   {
       i--;
       // Process something ...
   }

As you can see the differences in this case are minimal, even though in C# the logic condition goes between brackets.

It is important to remark that in the case of if as in the case of case, the while and the for, the main condition of each one is between brackets, that is, in the case of the if and the while the logical condition is between brackets, in the case of the case the variable goes between brackets and in the case of the for the parameters in the loop go between brackets.Also these lines of code between brackets do not have an ending colon and the following line is a curly bracket or beginning of block.

What in Visual FoxPro is known as AND, in C is &&. There is also the equivalent of OR of Visual FoxPro which is ||.

Data handling in C#

In C# a very interesting concept of data handling is used: the DataSet, which is a set of tables contained in an object, almost like having a VFP data base with all its tables into one variable, a very interesting thing indeed. But the use we are going to give it is for now very reduced.

Because the DataSet object is a container object, it contains tables, which contain records, which contain fields. This is the manner to access the information contained in a DataSet, always remembering that arrays in C# are always zero based. Therefore, if I want to ask for the first table in the DataSet dsDatos I need to do the following:

dsDatos.Tables[0]; // The first table
dsDatos.Tables[1]; // The second table

Following along this same logic, a table's records are accessed thus:

dsDatos.Tables[0].Rows[0]; // The first record of the first table
dsDatos.Tables[0].Rows[1]; // The second record of the first table
dsDatos.Tables[0].Rows[2]; // The third record of the first table
dsDatos.Tables[2].Rows[9]; // The eigth record of the third table

In order to know the value of the field "LastName" we have to write:

x = dsDatos.Tables[0].Rows[0]["LastName"];

Or if we wanted to know the value of the fourth field in the array:

x = dsDatos.Tables[0].Rows[0][3];

You might also want to know the quantity of tables or record a table has, in which case you could:

dsDatos.Tables.Count;
dsDatos.Tables[0].Rows.Count;

Table 5: Variable declaration

Visual FoxPro C#
Local nAge As Integer
Local cName As String
Local oRs As MyDll.method
int nAge = 0;
string cName = "";
MyDll.method oRs = new MyDll.methodClass();

In C# you should first indicate the type of variable to use, then the name of the variable and finally assign a value to it. In case it is an object, it is necessary to place new between the equal sign and the object.

Most objects have the possibility of converting, whatever their value, to a string, using ToString(). This function is very interesting because it is incorporated in a very unconventional way for those developers who are not used to program in C.

Table 6: Convert values

Visual FoxPro C#
Local nAge As Integer
Local cAge As String
Local nLong As Integer
nAge = 55
cAge = Alltrim(Str(nAge))
nLong = Len(cLastName)
int nAge = 0;
string cAge = "";
int nLong = 0;
nAge = 55;
cAge = nAge.ToString().Trim();
nLong = cLastName.Length();

In the case of C# there is Convert, which handles convertion to almost all types of data supported by the system. You only have to write Convert in the edit window and Intellisense appears with all possible options.

Scanning the table

Even though in C# data are handled as objects, let us see a simple equivalence on how to scan a table in Visual FoxPro and how to do it in C#, to add a variable.

Visual FoxPro
Local nTotal as Integer
nTotal = 0
Select mycursor
Scan
   * Add the amounts of all records in the cursor...
   nTotal = nTotal + amount
EndScan

C#
decimal nTotal = 0;
For(int i=0; i < dsDatos.Tables[0].Rows.Count; i++ )
   {
   // Add the amounts of all records in the table...
   nTotal += dsDatos.Tables[0].Rows[i]["amount"]
   }

AS can easily be seen not too much code is required. However you have to start working with objects like DataSet in case you are manipulating a set of tables, or with DataTable in case you are only using one table.

Further on we shall see that we can load an XML into a DataSet, which means we can load several XML into the same DataSet and use the tables collection to access the different tables in the DataSet.

Catching errors

In C# there is try-catch, which has been incorporated into Visual FoxPro 8.0. Even though the functionality is very similar for those who have not yet programmed anything in Visual FoxPro 8.0, let me tell you what it is all about.

C#
try
   {
   // when an error occurs within the try instruction, the catch block is jumped into 
   }
catch(Exception exc)
   {
   // Variable exc, of type Exception, contains the error produced. If I have a page called
   // error.aspx which receives a parameter with the text or the error message...
   Response.Redirect("error.aspx?message=" + exc.ToString().Trim())
   }

You have to take into account certain characteristics regarding functioning, such as:

  • You cannot redirect to another page within the try.
  • If an error occurs and catch is entered into, you redirect to a page with Response, the code under it is not executed, as shown in the following example:

En this routine to send an email you can see that at the end of it a call is made to the message.aspx page to inform the user that an email has been sent. However, that line of code will never be executed if an error occurs.

C#
private void Send_Mail( string MailMSG )
{
   MailMessage msgMail = new MailMessage();
   try
   {
      msgMail.To = "whoever@server.com.ar";
      msgMail.From = "whoever@server.com.ar";
      msgMail.Subject = "New user";
      msgMail.BodyFormat = MailFormat.Text;
      msgMail.Body = MailMSG;
      // Send the email to the administrator
      SmtpMail.SmtpServer = "smtp.server.com.ar";
      SmtpMail.Send(msgMail);
   }
   catch (Exception exc)
   {
      Response.Redirect("error.aspx?Message=" + exc.ToString().Trim());
   }
   Response.Redirect("message.aspx?Message=Email has been sent");
}

Because of the way it works, if an error occurs withing the try it will be caught by the catch which in turn calls the error page error.aspx which will cause the line before the last one in the routine not to be executed. This line shows a message indicating that an email has been sent. On the contrary, if their is no error, the line before the last line of code in the routine will be executed.

Conclusion

As seen,C# is not a difficult language and beyond the evident differences between both languages, I believe that C# is very intuitive, even though you have to remember to place a colon at the end of the majority of the lines of code, or that code has to be placed between brackets.

In the next part we shall see with more detail how to use a component made in Visual FoxPro from C#, but before that we have to see how to configure the IIS, how to create a new project in C#, how to configure a grid and how to pass parameters between forms.

 

2. Conversie Visual FoxPro in C# _05 _2006

To keep showing the interoperation posibilities between Visual FoxPro and C#, we will go into further detail with the creation of a Visual FoxPro business class to be consumed from C#.

This time, we are going to use VFP 8 and its new XmlAdapter class together with the new structured error handling, called Try/Catch...

Using Try-Catch-Finally

A new command have being incorporated to the already existing ones on Visual FoxPro's control structure: the brand-new Try/Catch. This instruction set allows for a structured error handling style and offers great simmilarity with .NET and even with Visual C++. Though I have already shown similarities and differences between both platforms' control structures, I will explain just the Visual FoxPro implementation of this structure, as this and its .NET sibling are simmilar enough to understand one by knowing the other.

Just like every Visual FoxPro instruction, Try has its corresponding EndTry, which indicates the end of the error trapping, but before this happens, there are two elements to deal with: Catch and Finally.

Let’s consider each point in order to understand them:

  1. Try: Starts the error trapping. Since there, any error will be redirected to the CATCH block, and the lines following the one that produced the error will not be executed, of course.
  2. Catch [ To loError ]: Here is where the error itself is handled. The instruction is able to create an Exception object, which has properties like ErrorNo or Message to know more details about the error.
  3. Throw [ eUserExpression ]: When this clause is included with eUserExpression, Visual FoxPro forces the Exception object's ErrorNo property to 2071 and shows "User Thrown Error(Error 2071)". If eUserExpression is omitted, Visual FoxPro looks for the original object Exception if it exists, else, it creates a new Exception object and assigns the value 2071 to ErrorNo property.
  4. Exit: This instruction immediately stops the execution of the current block. If Exit is in the Try or Catch blocks, the program executes the Finally block if any, otherwise, the first line after EndTry is executed.
  5. Finally: The code included in this block will be executed whether or not an error happens, provided all your code is written in TRY-CATCH blocks. The Finally block may be used to clean things up, i.e. to release not required variables or cursors.
  6. EndTry: This is the end of the instruction.

The first contact with Try-Catch

Function Print_Report_CR9( tcReportName as string ) as Boolean
   Local loCR as CrystalRuntime.Application, llOk as Boolean
   llOk = .t.
   if empty(tcReportName )
      tcReportName = "C:\MiReporte.rpt"
   endif
   
   Try
      loCR = CreateObject( "Crystal Runtime.Application" )
      MessageBox( "The object has been property created." )
   Catch
      llOk = .f.   
      MessageBox( "An error has occurred." )
   EndTry

   Return ( llOk )
EndFunc

In this example, since Crystal Report's runtime library is misspelled, an error will occur and Catch will trap it. Nevertheless, the error trapping is still quite primitive, as you do not know what the message or the error number are.

To trap the error object

Function Print_Report_CR9( tcReportName as string ) as Boolean

   Local loCR as CrystalRuntime.Application, llOk as Boolean
   llOk = .t.
   if empty( tcReportName )
      tcReportName = "C:\MiReporte.rpt"
   endif
   Try
      loCR = CreateObject( "CrystalRuntime.Application" )
      loRP = loCR.OpendReport( tcReportName )
      MessageBox( "The report has been property opened." )

   Catch to loError
      llOk = .f.
      MessageBox( "Error Nro: " + alltrim( str( loError.ErrorNo ) );
      + chr( 13 ) + "Message: " + loError.Message )
   EndTry

   Return ( llOk )
EndFunc

Now we can see that trapping the error number and message is very easy, and it gives us the chance to handle any other property of the loError object.

Obviously, you can write your own routine to save and/or to format the error according to your needs. Instead of the MessageBox() function, just call your routine.

NOTE: Making some tests, I tried to save the last error within an object i.e. goApp.oError, and I got an error, as it seems that you can store the error in a variable, but not in an object property.

Multiple Catch blocks

Function Print_Report_CR9( tcReportName as string ) as Boolean

   Local loCR as CrystalRuntime.Application, llOk as Boolean
   llOk = .t.
   if empty( tcReportName )
      tcReportName = "C:\MiReporte.rpt"
   endif
   Try
      loCR = CreateObject( "CrystalRuntime.Application" )
      loRP = loCR.OpendReport( tcReportName )
      MessageBox( "The report has been property opened." )

   Catch to loError When loError.ErrorNo = 1733
      llOk = .f.
      MessageBox( "Cannot find the Crystal Report Runtime Library" )

   Catch to loError When loError.ErrorNo <> 1733
      llOk = .f.
      MessageBox( "Error No: " + alltrim( str( loError.ErrorNo ) );
      + chr( 13 ) + "Message: " + loError.Message )
   EndTry

   Return ( llOk )
EndFunc

Within the catch block, we are able to set different actions according to the error number returned by the exception object. This may be done in two different ways: the first one is to write several catch blocks that execute different actions; the second one is to write a Do Case in the Catch block and handle the errors therein.

Nesting blocks

This new command allows to nest Try/Catches just like we can nest an If or any other command belonging to Visual FoxPro's control structure. Though I am sure that what nesting is and how to nest instructions do not need to be explained, I found interesting to show how Try-Catch performs when nested, even when its behavior is what you should expect.

Function Print_Report_CR9( tcReportName as string ) as Boolean

   Local loCR as CrystalRuntime.Application, llOk as Boolean

   llOk = .t.
   if empty( tcReportName )
      tcReportName = "C:\MiReporte.rpt"
   endif

   Try
      loCR = CreateObject( "CrystalRuntime.Application" )
      loRP = loCR.OpendReport( tcReportName )
      MessageBox( "The report has been property opened." )

      Try
         loRP.Print( 1234567890 )
         MessageBox( "The report was printed successful" )
      Catch to loError
         MessageBox( "Nested Error: " + loError.Message )
      EndTry
      MessageBox( "This is always shown." )
   Catch to loError
      MessageBox( "Error No: " + alltrim( str( loError.ErrorNo ) );
      + chr( 13 ) + "Message: " + loError.Message )
   EndTry

   llOk = ( vartype( loError ) <> "O" )
   Return ( llOk )
EndFunc

According to this example, once the object is created and the report is opened, another Try block starts, when we intend to print, but we entered a wrong parameter, so that an error occurs. Then, the error is trapped by the Catch in this Try block and the message "Nested Error" is shown. Exiting this block, the program executes the following code line and exits the next Try level. This way, as expected, we see that each Catch traps the errors from its own Try instead passing the errors to the next level.

On the other hand, you can pass the error from one block to the higher level, using the Throw instruction. This command "sends" the error occurred to the next Catch level, and so you can pass the error through different tiers.

Passing an error to the next higher level

Function Print_Report_CR9( tcReportName as string ) as Boolean

   Local loCR as CrystalRuntime.Application, llOk as Boolean
   llOk = .t.
   if empty( tcReportName )
      tcReportName = "C:\MiReporte.rpt"
   endif
   Try
      loCR = CreateObject( "CrystalRuntime.Application" )
      loRP = loCR.OpendReport( tcReportName )
      MessageBox( "The report has been property opened." )

      Try
         loRP.Print( 1234567890 )
         MessageBox( "The report was printed successful" )
      Catch
         Throw
      EndTry
      MessageBox( "If there is an error, this will never be shown." )

   Catch to loError
      MessageBox( "Error No: " + alltrim( str( loError.ErrorNo ) );
      + chr( 13 ) + "Message: " + loError.Message )
   EndTry
   llOk = ( vartype( loError ) <> "O" )
   Return ( llOk )
EndFunc

In the lines above, if an error occurs in the nested Try-Catch, it is passed to the higher level by the Throw instruction. Without any parameters, this instruction hands the Exception object over to the next level, so it can handle the error. You may need to create a custom error; in that case you can create your own exception an assign it the required values as follows:

Function Print_Report_CR9( tcReportName as string ) as Boolean

   Local loCR as CrystalRuntime.Application, llOk as Boolean
   llOk = .t.
   if empty( tcReportName )
      tcReportName = "C:\MiReporte.rpt"
   endif
   Try
      loCR = CreateObject( "CrystalRuntime.Application" )
      loRP = loCR.OpendReport( tcReportName )
      MessageBox( "The report has been property opened." )

      Try
         loRP.Print(1234567890)
         MessageBox( "The report was printed successful." )
      Catch
         loExc = createobject( "Exception" )
         loExc.ErrorNo = -1
         loExc.Message = "Printing error."
         Throw loExc
      EndTry
      MessageBox( "If there is an error, this will never be shown." )
   Catch to loError
      MessageBox( "Error No: " + alltrim( str( loError.ErrorNo ) );
      + chr( 13 ) + "Message: " + loError.Message )
   EndTry
   llOk = ( vartype( loError ) <> "O" )
   Return ( llOk )
EndFunc

What is Finally useful for?

Function Print_Report_CR9( tcReportName as string ) as Boolean
   Local loCR as CrystalRuntime.Application, llOk as Boolean
   llOk = .t.
   if empty( tcReportName )
      tcReportName = "C:\MiReporte.rpt"
   endif
   Try
      loCR = CreateObject( "CrystalRuntime.Application" )
      loRP = loCR.OpendReport( tcReportName )
      MessageBox( "The report has been property opened." )

      Try
         loRP.Print( 1234567890 )
         MessageBox( "The report was printed successful" )
      Catch
         Throw
      Finally
         MessageBox( "This is always shown." )
      EndTry
      MessageBox( "If there is an error, this will never be shown." )
   Catch to loError
      MessageBox( "Error No: " + alltrim( str( loError.ErrorNo ) );
      + chr( 13 ) + "Message: " + loError.Message )
   EndTry

   llOk = ( vartype( loError ) <> "O" )
   Return ( llOk )
EndFunc

From CursorToXml to XmlAdapter

The XmlAdapter class is among the most interesting new features on the 8th version of Visual FoxPro as it allows us to interact with .NET by supporting multi-table XML documents, resembling a .NET DataSet. This is why Visual FoxPro 8 is the most advisable choice when facing a three-tier project, not only because it is a very powerful tool, but also because it is totally compatible with .NET.

Though the XmlAdapter object holds several properties, methods and events, I will focus in showing its functionality rather than enumerate them. To see the complete list of methods and properties of this class you can always read the Visual FoxPro help.

Although we have already seen how to pass an XML document to C#, we are going to see a couple of simple examples about passing multiple results, thus loading several screen elements in a single call, i.e. heading data, a grid and a combobox.

Generating the XML from Visual FoxPro

Let's create a class that contains a method which returns an XML with 3 tables.

Define Class Customers as Session OLEPUBLIC

   Function Init
         set talk     off
         set safety   off
         set delete    on
         set exact     on
         set near      off
         set exclusive off
         set multilock on
         set century   on
         set century   to 19 ROLLOVER 50
         set date      to DMY
         set reprocess to 10 seconds
   EndFunc

   Function GetOrders( tcCustomerID as string ) as String
      Local lcXml as string      ,;
            loXA as XmlAdapter   ,;
            loError as Exception
      lcXml = ""
      Try
         Open DataBase home( 2 ) + "\Northwind\NorthWind" Shared

         Select * From Customers   ;
            Where CustomerID = tcCustomerID into cursor cur_Customers
         Select * from Orders ;
            where CustomerID = tcCustomerID Into Cursor cur_Orders

         loXA = CreateObject( "XmlAdapter" )
         loXA.XMLSchemaLocation = "1"
         loXA.AddTableSchema( "cur_Customers" )
         loXA.AddTableSchema( "cur_Orders" )
         loXA.ToXML( "lcXml", "", .F. )
      Catch to loError
         if version( 2 ) = 0
            comreturnerror( str( loError.ErrorNo ), loError.Message )
         else
            messagebox( loError.Message )
         endif
      Finally
         Close Tables All
      EndTry
      Return lcXml
   EndFunc
EndDefine

In this example we create several cursors from a Visual FoxPro database. As we intend to generate a multi-table Xml, we use the AddTableSchema() method to store the different cursors -one at a time- into the object. Once the cursors are loaded, we can check the Count property of the Tables collection to know how many Tables the Xml object carries.

Getting the data from C#

You should remember that it is important to add a reference to the component written in Visual FoxPro to your C# Project, so that you are able to access its public methods.

To see more details about how to add a reference to a COM component in a .NET project, you can see the article www.utmag.com/spanish/october2003/page8.asp.

public void cmdGetData_Click()
{
   DataSet dsCustomers = new DataSet();
   try()
   {
      myproject.customers oCustomer = new myproject.CustomersClass();
      string xml = oCustomer.GetOrders( "ALFKI" );
      dsCustomers.ReadXml( new System.IO.StringReader( xml ) );
      dsCustomers.AcceptChanges();
      grdOrders.DataSource = dsCustomers.Tables[1];
   }
   catch(Exception exp)
   {
      MessageBox.Show( exp.Message.Trim() );
   }
}

Updating data from C#

In order to complete the integration between Visual FoxPro and C#, let's create an updating routine in the customers class, whose only function is to update records in the table orders. This routine uses the XmlAdapter and CursorAdapter objects to achieve the updating from an Xml Diffgram originated from an ADO.NET DataSet.

Function UpdateOrders( tcXml as String, tcCustomerID as string ) as VOID ;
   helpstring "Update de orders related to a Customer id." 

   Local loXA as XmlAdapter, loCA as CursorAdapter
   Try
      Open DataBase home( 2 ) + "\Northwind\NorthWind" Shared
      loXA = CreateObject( "XmlAdapter" )
      loCA = CreateObject( "CursorAdapter" )
       with loCA
          .Alias = "cur_orders"
          .SelectCmd = "Select * From Orders Where CustomerId = '" + alltrim( tcCustomerID ) + "'"
          .DataSourceType = "NATIVE"
          .DataSource = "FOX"
          .CursorFill()
          .KeyFieldList = "CustomerId, OrderId"
          .UpdatableFieldList = CursorGetProp("UpdatableFieldList")
          .UpdateNameList = CursorGetProp("UpdateNameList")
      endwith
      CursorSetProp( "Buffering", 5 )
      with loXA
         .AddTableSchema( Alias() )
         .IsDiffgram = .T.
         .LoadXML( tcXml )
         for niCount = 1 to loXA.Tables.Count
            if lower( loXA.Tables[ niCount ].Alias ) = "cur_orders"
               select ( loXA.Tables[ niCount ].Alias )
               loXA.Tables[ niCount ].ApplyDiffGram()
               TableUpdate( .t., .t., "cur_orders" )
            endif
         next
      endwith
   Catch to loError
      if version( 2 ) = 0
         comreturnerror( str( loError.ErrorNo ), loError.Message )
      else
         messagebox( loError.Message )
      endif
   Finally
      Close Tables All
   EndTry
EndFunc
  1. Create XmlAdapter and CursorAdapter objects
  2. Query original data back from CursorAdapter object
  3. Relate the alias got with CursorAdapter to XmlAdapter
  4. Load the Xml with its DiffGram
  5. Issue the ApplyDiffGram on the alias
  6. Issue the TableUpdate to confirm changes.

Though this routine is a simple example on how to update a single table, with a small effort and a bit of imagination, you can write a generic routine with the required intelligence to perform all the updating associated to an Xml DiffGram.

We need to introduce a small adjustment to our data gathering routine. To make easier to handle the form’s info, we will create a property of the type DataSet and use it to store all needed data, thus, when associating a grid to a table of that property, it becomes easier to extract the xml with the changes to pass it through the tiers.

Conclusion

As you can see, each new step makes stronger the existing tie between Visual FoxPro and C#, their interaction and coexistence in a common project is pretty intense because both are compatible in many aspects.

In the next issue, I will discuss in deeper detail some features and similarities between the creation of a business tier with Visual FoxPro and with C#, what issues you should keep in mind, and how difficult can be to face the migration of a class.
 

This time, we will take an approach to similarities, differences and features of a business component built in Visual FoxPro and in C#, for what is mandatory to get a thorough detail of the concepts of overloading and overriding.

Overload

In Visual FoxPro we often use optional parameters, since the language allows this. In case we do not set some parameter, this is initialized as a logical variable with its value in false, by default. Nevertheless, it is not so simple in C#, for this language does not accept optional parameters, and variables are strong typed, meaning that every variable must have its type defined and you can’t pass –let’s say- a numeric value to a date type parameter or a Boolean value to a string parameter.

This is of course a hard shock for the developer who never had the chance to use a language that compels him to set the exact quantity of parameters or explicitly declare the data type for each variable.

While in Visual FoxPro you just can omit a parameter, in C# is needed define several times the same method with different quantity and even type of parameters in order to depending upon the quantity and type of the parameters passed, the corresponding block of code be executed. This combination of method name and quantity and type of parameters is known in .Net as signature.

A simple example for this is the collection fields of a table within a DataSet, where you can reference a field by its position in the array or by its name. This means that there are two internal methods, the first one has as parameter, a numeric value, and the second one takes as parameter a string value.

Declaring a function

Declaration of methods in C# has some differences relating to Visual FoxPro, as is shown bellow.

Visual FoxPro C#
function GetEmployee() as string
   *Get an employee by id 
Endfunc
public string GetEmployee()
{
   //Get an employee by id
}

As to C#, you need to indicate the return data value before the name of the method, just like when you declare a variable.

Visual FoxPro
function GetEmployee( tnEmployeeId as integer ) as string
   *Get an employee by id 
Endfunc
C#
public string GetEmployee( int tnEmployeeId )
{
   //Get an employee by id
}

Similarly to the function, you must indicate the data type for the parameters before their names, since these are also strong typed, meaning they must be explicitly declared in order to avoid a compilation error.

Declaring an overload for a parameter

In order to get the concept clear, a method can be written several times with the same name, but each time it receives different parameters. In the example, we declare the function GetEmployee() setting as parameter a numeric variable called tnEmployeeID..

public string GetEmployee( int tnEmployeeId)
{
   // Get an employee by id
}

What follows is the overloaded method, same name but the function expects a string parameter instead a numeric one, called tcLastName.

public string GetEmployee( string tcLastName)
{
   // Get an employee by last name
}

Declaring an overloaded function with several parameters

We will assume that the GetEmployeeOrders() method may receive 2 parameters, where the first one indicates the employee code and the second one the list of fields by which you desire to sort the query. This example differs from the previous one for we add an optional parameter instead of change the type of the existing one, so that we get a function that may receive one parameter in order to seek just by the key of the employee or may receive two parameters and perform a query seeking by key and sorted by a field set according to the second parameter.

Visual FoxPro.

Function GetEmployeeOrders( tnEmployeeId, tcOrderBy ) as string
   If Pcount() > 1 And VarType( tcOrderBy ) == "C"
      tcOrderBy = " Order By " + tcOrderBy
   Endif
   * Get the employee orders by id and in some specific order
EndFunc

Keep in mind that in C# you need to declare the overloaded methods, then we start declaring the firs method as follows:

public string GetEmployeeOrders( int tnEmployeeId )
{
   // Get the employee orders by the id
}

On the other hand, this second method has one more string type parameter that the former one called tcOrderBy.

public string GetEmployeeOrders( int tnEmployeeId, string tcOrderBy )
{
// Get the employee orders by id and in some specific order
}

So we implement in C# what in VFP would be a simple routine with an optional parameter. Nonetheless, once you compile in C#, intellisense finds for you two sets of parameters, meaning that (according to C#) there is one method with two overloads, enabling the calling method to send one or two parameters depending on the desired result. If the method receives one parameter, the firs version will be executed, while if two parameters are passed, it will trigger the second version.

Intellisense shows a text that starts with “1 of 2” before the parameters ennumeration, and if you use the up-down cursor keys you can see the different parameter sets for the different overloads overloads.

Let us see how to us an overloaded method in C#.

string xml = "";
try
{
   if (this.OrderBy.Trim() == "")
      //Si no hay un orden especifico, no pasar el parámetro.
      xml = GetEmployeeOrders( "ALFKI" );
   else
      //if the OrderBy property is filled.
      xml = GetEmployeeOrders( "ALFKI", this.OrderBy.Trim() );

   //Do something with the xml document.
   DataSet ds = new DataSet();
   ds.ReadXml( new System.IO.StringReader( xml ) );
   Datagrid1.DataSource( ds );
}
catch (exception exc)
{
   MessageBox.Show( exc.Message )
}

The range of this is –no doubts- pretty wide, what makes apparent that we face a develop scheme that allows quite thoroughly to handle routines.

Override

In Visual FoxPro we can clearly override code from an inherited class and this results in the replacement of the behavior of the method for the new code, as is shown below:

Let us define a simple class as custom, and write in it a method to be overwritten later.

Define class Employee as Custom OLEPUBLIC
   Function GetEmployee() as String
      Return "Original"
   EndFunc
EndDefine

Then, let us define a class that inherits the former one and override the method changing the return message.

Define class OverEmployee as Employee OLEPUBLIC
   Function GetEmployee() as String
      Return "Override"
   EndFunc
EndDefine

But C# does not allow so easily override a function, it is required to set the function in order that it can be overridden, declaring it as follows:

public virtual string GetEmployee( int tnEmployeeId )
{
// Get the employee by the id and by some specific order
}

In order to override an inherited routine you need to declare it as virtual and public. This allows at the proper time to use the clause override and write code that will supersede the original one.

public override string GetEmployee( int tnEmployeeId )
{
// Get the employee by the id and by some specific order (override)
}

Please keep in mind that you can’t override a function with a different signature (name and quantity or type of parameters), for as it was explained before, there is no such a thing as optional parameters and hence it appears as physically different functions, shown as just one by IntelliSense.

Conclusion

As you can see, some similarities between Visual Foxpro and C# are really strong, besides, for a developer with some experience in Visual Foxpro, C# gets quite simple and even intuitive, thanks to the impeccable IDE of .NET.
 

 7/31/2007 8:59:19 AM
User is offlinenae racaru
714 posts
www.rarom.ro
1st




Re: Ghid migrare FoxPro - C#
 (Romania)
http://foxcentral.net/microsoft/NETforVFPDevelopers.htm
VFP 6 si 9 + Oracle
  Visual FoxPro  .NET Interop  Ghid migrare Fo...

Search  Forum Home         

 Google Ads Minimize

    

Copyright 2002-2010 Profox   Terms Of Use  Privacy Statement