vulcan.net at warp speed · 8 vulcan.net at warp speed paul piko, 2010 3.1 introduction t he famous...

165
Paul Piko, February 2010 Vulcan.NET at Warp Speed

Upload: lamliem

Post on 03-Jul-2018

223 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

Paul Piko, February 2010

Vulcan.NET at Warp Speed

Page 2: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …
Page 3: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

3Contents

Paul Piko, 2010

Table of Contents

Vulcan.NET At Warp Speed 5

Copyright and Legalities 6

Preface 7

.................................................................................................................... 81 Introduction

.................................................................................................................... 102 Audience

.................................................................................................................... 113 Requirements

.................................................................................................................... 124 Organisation

.................................................................................................................... 135 Conventions

.................................................................................................................... 146 Source Code

.................................................................................................................... 157 Updates and Errata

Part I: Basic .NET Concepts 16

.................................................................................................................... 171 .NET Overview

.................................................................................................................... 182 Common Language Runtime

.................................................................................................................... 193 Common Type System

.................................................................................................................... 204 Intermediate Language

.................................................................................................................... 215 Memory Management

.................................................................................................................... 236 Assemblies

.................................................................................................................... 267 Assemblies in Different Languages - OK!

Part II: The Vulcan.NET Language 27

.................................................................................................................... 281 Absolute Basics - Building the simplest Vulcan.NET application

.................................................................................................................... 302 New and Changed Features .......................................................................................................................................... 30Assemblies and Libraries .......................................................................................................................................... 30Namespaces .......................................................................................................................................... 31Types .......................................................................................................................................... 33Type Conversion .......................................................................................................................................... 35Classes .......................................................................................................................................... 40Arrays .......................................................................................................................................... 42Enums .......................................................................................................................................... 42Functions and Procedures .......................................................................................................................................... 43Overloading .......................................................................................................................................... 45Exception Handling .......................................................................................................................................... 46Delegates and Events .......................................................................................................................................... 47Attributes .......................................................................................................................................... 47"." versus ":" .......................................................................................................................................... 49Pragmas

.................................................................................................................... 513 Vulcan Runtime Library

Page 4: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

Vulcan.NET at Warp Speed4

Paul Piko, 2010

Part III: The VO Way 52

.................................................................................................................... 531 Making VO Code Usable by Vulcan.NET

.................................................................................................................... 632 Using the VO Class Libraries

.................................................................................................................... 643 Handling VO Binary Entities

Part IV: The .NET Way 65

.................................................................................................................... 661 Using Visual Studio .......................................................................................................................................... 66Creating a Solution and a Project

.................................................................................................................... 732 Creating An MDI Application .......................................................................................................................................... 73The Parent Form .......................................................................................................................................... 78The Child Form .......................................................................................................................................... 78Child Management .......................................................................................................................................... 80Menu Handling

.................................................................................................................... 843 Data Handling With WinForms .......................................................................................................................................... 84Displaying a Form .......................................................................................................................................... 85WinForm Elements Cross Reference .......................................................................................................................................... 88Simple Data Display .......................................................................................................................................... 90Changing The View .......................................................................................................................................... 92Validation .......................................................................................................................................... 95Setting Up More Test Data .......................................................................................................................................... 98Data Handling Basics

.......................................................................................................................................... 100Hand-Coded Data Form

.......................................................................................................................................... 106Data Form Using The Form Designer

.......................................................................................................................................... 116Master-Detail Form

.......................................................................................................................................... 121Using Typed Datasets

.................................................................................................................... 1354 Debugging

.................................................................................................................... 1485 Resources

.................................................................................................................... 1526 Using the Command Line .......................................................................................................................................... 153Creating Applications .......................................................................................................................................... 154MSBuild

.................................................................................................................... 1557 Interoperability .......................................................................................................................................... 155Using COM from .NET .......................................................................................................................................... 160Using .NET Components via COM .......................................................................................................................................... 165Platform Invoke

Page 5: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

5Vulcan.NET At Warp Speed

Paul Piko, 2010

1 Vulcan.NET At Warp Speed

Vulcan.NET at Warp Speedby Paul Piko

Grafx Database Systems, Inc.

A quick start guide to Vulcan.NET for Visual Objects programmers

Page 6: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

6 Vulcan.NET at Warp Speed

Paul Piko, 2010

2 Copyright and LegalitiesAuthor: Paul Piko

Publisher: Grafx Database Systems, Inc.11900 Torreyanna CircleWest Palm Beach Florida USA 33412www.grafxsoft.com

Copyright © 2006 Grafx Database Systems, Inc., West Palm Beach, Florida, USA

No part of this publication may be reproduced, stored in a retrieval system or transmitted in any form or by anymeans, electronic, mechanical, photocopying, recording, scanning or otherwise, except as permitted underSections 107 or 108 of the 1976 United States Copyright Act, without either the prior written permission of thePublisher.

LIMIT OF LIABILITY/DISCLAIMER OF WARRANTY: THE PUBLISHER AND THE AUTHOR MAKE NO REPRESENTATIONSOR WARRANTIES WITH RESPECT TO THE ACCURACY OR COMPLETENESS OF THE CONTENTS OF THIS WORK ANDSPECIFICALLY DISCLAIM ALL WARRANTIES, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR APARTICULAR PURPOSE. NO WARRANTY MAY BE CREATED OR EXTENDED BY SALES OR PROMOTIONALMATERIALS. THE ADVICE AND STRATEGIES CONTAINED HEREIN MAY NOT BE SUITABLE FOR EVERY SITUATION.THIS WORK IS SOLD WITH THE UNDERSTANDING THAT THE PUBLISHER IS NOT ENGAGED IN RENDERING LEGAL,ACCOUNTING, OR OTHER PROFESSIONAL SERVICES. IF PROFESSIONAL ASSISTANCE IS REQUIRED, THE SERVICESOF A COMPETENT PROFESSIONAL PERSON SHOULD BE SOUGHT. NEITHER THE PUBLISHER NOR THE AUTHORSHALL BE LIABLE FOR DAMAGES ARISING HEREFROM. THE FACT THAT AN ORGANIZATION OR WEBSITE ISREFERRED TO IN THIS WORK AS A CITATION AND/OR A POTENTIAL SOURCE OF FURTHER INFORMATION DOESNOT MEAN THAT THE AUTHOR OR THE PUBLISHER ENDORSES THE INFORMATION THE ORGANIZATION ORWEBSITE MAY PROVIDE OR RECOMMENDATIONS IT MAY MAKE. FURTHER, READERS SHOULD BE AWARE THATINTERNET WEBSITES LISTED IN THIS WORK MAY HAVE CHANGED OR DISAPPEARED BETWEEN WHEN THIS WORKWAS WRITTEN AND WHEN IT IS READ.

Trademarks: Grafx, Vulcan.NET are trademarks or registered trademarks of Grafx Database Systems, Inc. and/or itsaffiliates, in the United States and other countries, and may not be used without written permission. VisualObjects is a trademark or registered trademark of CA, Inc. in the United States and/or other countries. All othertrademarks are the property of their respective owners.

Credits:Editor: John ParkerPublisher: Brian FeldmanAdvisor: Don Caton

About the AuthorPaul Piko was a Systems Analyst working on mainframe databases for one of the major oilcompanies, when he decided to run his own software consultancy. That was a long time agoand since then he has been working on financial, medical and agricultural database software.Paul was president of the Clipper User Group (Melbourne), contributor to two books aboutClipper and author of articles published in VO/Clipper journals. He has shared his experiencewith other developers at numerous conferences in Australia, US and Europe. He is creator ofthe VO Productivity Pack and been part of the VO and Vulcan development teams.

Page 7: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

7Preface

Paul Piko, 2010

3 Preface

Preface

Page 8: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

8 Vulcan.NET at Warp Speed

Paul Piko, 2010

3.1 Introduction

The famous book by Douglas Adams, "The Hitchhiker's Guide To The Galaxy", contains the

following passage:

"Space," it says, "is big. Really big. You just won't believe how vastly hugely mindboggingly bigit is. I mean you may think it's a long way down the road to the chemist, but that's just peanutsto space. Listen ..."

This could have been written about the .NET Framework. "The .NET Framework is big. Reallybig. You just won't believe how vastly hugely mindboggingly big it is...". And Microsoft'sMSDN magazine (Vol 21, No 3) said this on the release of version 2 of the framework:

"Comparing the assemblies in the framework directories for versions 1.1 and 2.0, almost 4,500new classes have been added for 2.0, and the number of public members has grown to over400,000!"

So the transition for Visual Objects programmers, familiar with the Windows 32 operatingenvironment, up to .NET is a huge step. In addition to the massive object-oriented class librarythere are many new concepts and techniques to learn. Why take the step? Because theframework offers modern capabilities delivered via object orientation rather than the olderfunctional-based APIs. And Microsoft delivers access to most of its technology through the .NET framework. Fortunately Vulcan.NET helps smooth out the learning curve by providing afamiliar programming language and the ability to handle a high percentage of existing VO codewithout change. And it gives you the opportunity to take advantage of the .NET features. .NETis also the way of the future - version 3 of the .NET framework was released in early November2006. It incorporates new classes and technologies including the Windows Presentation,Communication and Workflow Foundations and Windows CardSpace. It is pre-installed withWindows Vista, which was also released to manufacturing during November 2006, and isavailable as an update for Windows XP.

The purpose of this guide is to give the experienced Visual Objects developer an introductionto Vulcan.NET. While not every issue can be covered in detail here, many of the essentialtopics are covered. Existing VO applications, with the help of the Transporter utility, can becompiled to work in the .NET environment. With Vulcan.NET you can add functionality to yourapplications that was previously unavailable or difficult in Visual Objects. This guide walks youthrough those topics, helping you start down the road of productive .NET applicationdevelopment.

Overview of Vulcan.NET's goalsOne of the primary goals of Vulcan.NET is to allow developers to migrate their existing VisualObjects code to the .NET platform, with minimal source code changes. Vulcan.NET compilesexisting Visual Objects source code into code that conforms to the "Common LanguageInfrastructure" (CLI). The CLI is an international standard specifying how languages andlibraries can work seamlessly together, under the control of a "Common Language Runtime"(CLR). ".NET" is Microsoft's implementation of the CLI for the Windows desktop and portabledevice platforms. There are other implementations of the CLI such as Mono, which runs onWindows and Linux operating systems.

There is of course, little point in simply recompiling your Visual Objects applications if youcannot also take full advantage of the features that a CLI environment offers. So an equally

Page 9: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

9Preface

Paul Piko, 2010

important goal for Vulcan.NET is to allow you to make full and complete use of thisenvironment once you have migrated your applications. This not only includes the .NETframework class library, but a multitude of third party class libraries, controls and tools. .NET isa language-neutral environment; it does not favour any particular development language overanother. All CLR-compliant .NET tools and class libraries can be used with any .NETdevelopment system, including Vulcan.NET.

To achieve this goal, Vulcan.NET extends the Visual Objects language and adds the ability tocreate and use method overloading, operator overloading, static class members, events,delegates, enumerations, attributes, and so on.

Vulcan.NET is designed to be a first-class .NET language implementation, delivering codequality, performance and compilation speed comparable to Microsoft's .NET compilers.

Page 10: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

10 Vulcan.NET at Warp Speed

Paul Piko, 2010

3.2 Audience

This guide assumes the reader has a working knowledge of developing applications with Visual

Objects. It highlights the differences between Visual Objects and Vulcan.NET in order to givethe existing VO software developer a quick start at working with Vulcan.NET. As such the basicconcepts of things such as program structure and flow, variables and introductory objectorientation - many things covered in the initial chapters of the VO Programmer's Guide - are notcovered in detail here unless there is a significant difference in how they are handled in Vulcan.NET. As a "rule of thumb" you should consider that Vulcan.NET operates the same as VisualObjects unless otherwise stated.

Page 11: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

11Preface

Paul Piko, 2010

3.3 Requirements

The things you need to get the most from this guide are:

· Vulcan.NET

· Visual Studio 2005/2008 (a version of Visual Studio 2005/2008 is included with Vulcan)

· .NET Framework 2.0 or above

· MSDN Library (optionally installed with Visual Studio 2005/2008)

Optionally, you may find the following useful:

· .NET Framework 2.0 (or above) SDK

The .NET Framework SDK and additional tools are available for download from http://msdn.microsoft.com/netframework/downloads.

If you do not have a local copy of the MSDN library you can refer to http://msdn2.microsoft.com. Alternatively you can download the May 2006 edition from here: http://www.microsoft.com/downloads/details.aspx?FamilyId=373930CB-A3D7-4EA5-B421-DD6818DC7C41&displaylang=en.

Page 12: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

12 Vulcan.NET at Warp Speed

Paul Piko, 2010

3.4 OrganisationThis Getting Started guide introduces essential concepts about the .NET environment andabout Vulcan.NET in particular. It will give you a solid foundation on which to start effectiveprogramming using Vulcan.NET. However, in conjunction with reading this guide, you shouldconsider dedicating a good amount of time to studying and becoming familiar with the .NETFramework classes. As previously stated, the number of classes in the framework is huge, andit continues to grow as Microsoft release new updates.

To kick off your venture into .NET this guide presents a quick overview of .NET concepts. Youmay have heard some of the terms before, or maybe this is the first time you have seen themdescribed in a context such as this.

Once the basics have been covered the guide moves on to discussion of the Vulcan.NETlanguage. This section assumes knowledge of Visuals Objects and does not go over the thingsthat are the same between VO and Vulcan. Unless otherwise stated, you should expect thingsin Vulcan work exactly the same as they did in VO. This section concentrates on the things thathave changed, or are new.

The third part of the guide looks at how Visual Objects code can be taken from a repository andmoved to Visual Studio. Even before moving any code there are a small number of VO codeimprovements that can be made by the Transporter utility, and they are applied directly to thecode within the repository. When you are ready you can ask Transporter to create a VisualStudio solution for your selected VO project. The majority of the transported code will remainunchanged and make use of the Vulcan-compiled versions of the VO class libraries.

Part IV makes the move into .NET programming and using new tools that are available. Themost significant new tool is Visual Studio and this section presents a number of examples thathighlight some of its features.

Page 13: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

13Preface

Paul Piko, 2010

3.5 Conventions

A number of conventions are used throughout this guide to make it easier for you to

recognise important information:

· External links are shown like this: www.grafxsoft.com

· Links within this guide are shown like this: Title

· Significant terms or concepts are shown like this:

Vulcan.NET is highly compatible with Visual Objects

· Commands at the DOS/command prompt look like this:

vulcan hello

· Source code is shown like this:

FUNCTION Start() AS VOIDLOCAL o AS OBJECT

// ... more code here

RETURN

· Visual Objects is often abbreviated to VO

· Vulcan.NET is sometimes referred to as Vulcan

Page 14: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

14 Vulcan.NET at Warp Speed

Paul Piko, 2010

3.6 Source Code

You may like to type the code examples in manually, or copy and paste them from this guide.

The completed examples are also provided with the guide. All of the source code is alsoavailable for download from http://www.govulcan.net/gsupdates.aspx.

Page 15: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

15Preface

Paul Piko, 2010

3.7 Updates and Errata

Errata information and any updates for this guide can be found at http://www.govulcan.net/

gsupdates.aspx.

Every effort is made to ensure the information in this guide is accurate and that there are noerrors in the text or code. However it is possible that a gremlin might creep in. We welcomeany feedback you might have if you discover a mistake or dysfunctional code, however pleasecheck to see if it has already been reported. Your help gives us the opportunity to improve thequality of this guide.

Page 16: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

16 Vulcan.NET at Warp Speed

Paul Piko, 2010

4 Part I: Basic .NET Concepts

Part I: Basic .NET Concepts

Page 17: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

17Part I: Basic .NET Concepts

Paul Piko, 2010

4.1 .NET Overview

When creating the .NET Framework Microsoft invested huge amounts of effort to

completely review the way in which software works with the operating system. They came upwith object-oriented class libraries covering areas such as data handling, presentation andcommunication, encapsulating low-level complexity within consistent object models. Theseobject models are far easier to work with than the old Windows API calls.

Part of the design of .NET includes the idea of the base being "language agnostic". In otherwords, the common language runtime works effectively with all .NET compliant languages.Vulcan.NET is a .NET compliant language.

The .NET Common Language Runtime is shared by all .NET compliant languages, includingVulcan.NET. The CLR allows code written in different languages to cooperate smoothlytogether. In your Vulcan.NET application you can not only inherit from the standard .NETFramework classes but also from other third party classes. With the common type system eachlanguage can understand the exchanged data without conversion.

.NET can still make use of Win32 code where required via COM and DLL calls.

The outcome of all of this is that Vulcan.NET operates cleanly with all other .NET components,be they part of the base framework or provided separately. Third party libraries, written inlanguages such as C# and VB.NET, work well with Vulcan.NET. On the same basis, classescreate using Vulcan.NET can be easily used in other languages. For interoperability, the nativelanguage used is not an issue as it was in the Win32 environment.

Microsoft is continuing to develop .NET. In particular, at the moment, the moves towardsWindows Vista and 64 bit Windows is progressing. Vulcan.NET will be placed ready to take fulladvantage of the new technology as it becomes available.

The following sections briefly describe core .NET concepts.

Page 18: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

18 Vulcan.NET at Warp Speed

Paul Piko, 2010

4.2 Common Language RuntimeThe .NET Common Language Runtime (CLR) is used by all .NET compliant languages to providecore behaviour for the operation of code within applications. It handles memory allocation,garbage collection, security and code loading. Code that runs within the Common LanguageRuntime is called managed code. Vulcan.NET applications make use of the Common LanguageRuntime through the .NET class libraries, just as applications written in C# or VB.NET do.

Page 19: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

19Part I: Basic .NET Concepts

Paul Piko, 2010

4.3 Common Type System.NET's Common Type Specification (CTS) enables applications and assemblies written indifferent languages to share information without having to convert the data. It contains therules on how data types are declared and used. This allows all data, including objects, to beunderstood by all .NET compliant languages and be treated in the same way. This then makesit straightforward for one language to make use of data that is passed from an assemblywritten in another language. You can even inherit from classes written in another language - aVulcan.NET class can inherit from a C# class, a VB.NET class can inherit from a Vulcan.NET class.

Page 20: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

20 Vulcan.NET at Warp Speed

Paul Piko, 2010

4.4 Intermediate LanguageThe .NET compilers, Vulcan.NET included, output code in the format of Microsoft intermediatelanguage (MSIL). It is this intermediate language that the common language runtime uses.When a .NET application is run the intermediate language is compiled into machineinstructions by the Just-In-Time compiler (JIT).

Vulcan.NET Code C# Code VB.NET Codeâ â â

Vulcan.NET Compiler C# Compiler VB.NET Compilerâ â â

Intermediate Languageâ

Just-In-Time Compilerâ

Processor-specific machineinstructions

When a method is invoked the CLR calls the JIT compiler to convert the code into machinelanguage. This machine language is stored while the application is running so that the JITcompilation only occurs once per method.

Page 21: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

21Part I: Basic .NET Concepts

Paul Piko, 2010

4.5 Memory Management

Visual Objects programmers are used to the idea of a garbage collector. It is a feature that has

been used for many years. .NET has its own garbage collector and all .NET languages make useof it. The garbage collector periodically looks for unused objects and when it finds one itdestroys it, freeing up the memory and resources. Just as in VO, when an object referencegoes out of scope the object is not necessarily destroyed straight away. It is only when thegarbage collector is fired that the unreferenced objects are cleaned up.

Normally .NET objects do not require any special code when they are being collected.However in some situations you might need an object to perform some action when it is beingdestroyed, typically to handle any unmanaged (non-.NET) resources such as closing databaseconnections or freeing manually allocated memory.

Vulcan allows a destructor to be defined for a class and it will be called automatically before thegarbage collector reclaims an object of that class. The special keyword DESTRUCTOR is usedfor this.

Here is a very simple example.

FUNCTION Start AS VOIDLOCAL o AS Test

o := Test{}

RETURN

CLASS Test

DESTRUCTOR() ? "Goodbye"

RETURN

END CLASS

In this Start function an object of type Test is created and the application ends. The output thatappears on the console is this:

Goodbye

This indicates that the destructor method of the Test class was automatically called. Thishappens because of the final clean up being performed by the garbage collector after Starthas completed and the application finishes.

A method name of Axit has no special meaning inVulcan unless you tell the compiler to treat is as theDESTRUCTOR. You can do this in the projectproperties in Visual Studio or by using the /vo1 switchon the command line.

The use of the DESTRUCTOR keyword actually creates a method called Finalize. This method is

Page 22: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

22 Vulcan.NET at Warp Speed

Paul Piko, 2010

called by Vulcan and is not called directly by the programmer.

Unmanaged and unsafeCode that is not under control of .NET is known as unmanaged. A typical example ofunmanaged code is the code that exists within existing Win32 DLLs; they were written outsideof .NET and have their own way of handling memory.

Unsafe code is code that uses pointers; this code manipulates memory directly. Unsafe codecan be written in .NET languages by using a directive to tell the compiler that you want writeunsafe code. The directive can be a compiler switch, /unsafe in Vulcan.

Page 23: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

23Part I: Basic .NET Concepts

Paul Piko, 2010

4.6 Assemblies

Assemblies are the building blocks of .NET applications. For Visual Objects

programmers, an assembly is like an Windows-32 EXE or DLL except it containsadditional information such as details of the types (classes) and resources it contains.Assemblies can also hold version and security information.

You can think of an assembly as a collection of code that describes one or more types (classesor structures). The assembly could be a library (a DLL) or an executable (an EXE). It makessense if the types have some logical relation but there is no strict rule enforcing that.

Functions in Vulcan.NET are actually implemented asmethods of an internal class, so the discussion herealso applies to Functions

Simple Assemblies

Here is some simple Vulcan.NET code:

FUNCTION Start() AS VOID? "Hello World"RETURN

The main program execution in a Vulcan.NETapplication begins in FUNCTION Start().

If this code is placed in hello.prg you can compile it like this:

vulcan hello

This will yield hello.exe, a small executable that is an assembly.

Alternatively, we can take this code:

CLASS MyWorld

METHOD SayHello() AS VOID? "Hello World"RETURN

END CLASS

and put it into myworld.prg. The file can then be compiled like this:

vulcan myworld /t:library

This produces myworld.dll which is also an assembly.

Page 24: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

24 Vulcan.NET at Warp Speed

Paul Piko, 2010

Global Assembly Cache

Assemblies used by a single application (private assembles) are stored in the same folder as theapplication.

Assemblies that are shared by multiple applications are usually stored in the Global AssemblyCache (GAC). Assemblies in the GAC can be used by all .NET applications on the computer. TheGAC is usually located in the C:\Windows\Assembly folder and the .NET framework'sassemblies are found in that folder.

All assemblies that are put in the GAC must have a "strong name". The strong name is acombination of the textual name, version number, culture information and a signature key.The strong name is used to uniquely identify the assembly, distinguish different versions andcheck its integrity.

If you have a strongly named assembly you can just drag and drop it into the GAC. The GAC canbe inspected by using Windows Explorer and selecting the Windows\Assembly folder:

You can also install a strong named assembly into the GAC from the command prompt by usingthe utility called gacutil (use /? to see the options).

Page 25: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

25Part I: Basic .NET Concepts

Paul Piko, 2010

To make your own strong named assembly you should make sure your assembly containsversion information - an example of this is the AssemblyInfo.prg that is created by Visual Studiowhen you create a Vulcan project. Then you need to create a signature key - you can run theStrong Name utility (sn at the command prompt) to get this:

sn -k mykey.snk

Then you need to add the key to your assembly by using Vulcan's /snk switch.

vulcan MyLibrary /t:library /snk:mykey.snk

The above line will result in a strongly-named MyLibrary.dll.

Page 26: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

26 Vulcan.NET at Warp Speed

Paul Piko, 2010

4.7 Assemblies in Different Languages - OK!

"The Hitchhiker's Guide to the Galaxy" says:

"If you stick a Babel fish in your ear you can instantly understand anything said to you in anyform of language."

You could consider that .NET's capabilities are not dissimilar to this. The mythical Babel fishprocesses incoming speech and outputs signals that are understood by the recipient. Each ofthe .NET languages are compiled and turned into a format that is understood by the CommonLanguage Runtime. By the time the CLR receives the instructions the original language is notimportant; it gets something that it understands - Intermediate Language.

It is this capability that lets us write code like this in Vulcan.NET:

CLASS MyForm INHERIT System.Windows.Forms.Form

This code shows that we can create our own class, MyForm, and directly inherit from a class,called System.Windows.Forms.Form, that was written in another .NET language.

Vulcan.NET code can easily use assemblies that were authored in any .NET compliantlanguage. Similarly, Vulcan.NET assemblies can be used anywhere a .NET assembly is required.Be aware, however, that other languages will not know how to completely handle Vulcan-specific items such as USUALs. Use of the standard, common types will not cause any issues.

Page 27: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

27Part II: The Vulcan.NET Language

Paul Piko, 2010

5 Part II: The Vulcan.NET Language

Part II: The Vulcan.NET Langauge

Page 28: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

28 Vulcan.NET at Warp Speed

Paul Piko, 2010

5.1 Absolute Basics - Building the simplest Vulcan.NET applicationVulcan.NET can be used from the command prompt or via the feature-rich, user-friendly,wizard-assisted, point-and-click Visual Studio.

In this section we will take a bare-bones approach to keep things as simple as possible andconcentrate on the basic concepts.

The samples here are short and can be created with your favourite text editor.

There is an introduction to Visual Studio later in this guide.

One of the Vulcan.NET options available from the Windows Programs menu is "Vulcan.NETCommand Prompt". This option opens a command prompt in the Vulcan.NET BIN folder andchanges the prompt's PATH to include the BIN folder and the main .NET Framework folder.For example, when I use the Vulcan.NET Command Prompt option on my machine and querythe path this is what I see:

Microsoft Windows XP [Version 5.1.2600](C) Copyright 1985-2001 Microsoft Corp.

D:\Program Files\Vulcan.net\Bin>pathPATH=D:\Program Files\Vulcan.NET\bin;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\;.....

If you would like to have Vulcan.NET accessible fromany command prompt on your computer withoutgoing through the Vulcan.NET Command Promptoption you can edit the path in the environmentvariables (accessed through System Properties).

To make sure Vulcan can be run, type

vulcan

at the command prompt and you should see something like this:

Vulcan.NET Compiler version 1.0.0.112 >>> Development Build <<<Copyright (c) Grafx Database Systems, Inc. 2004-2006. All rights reserved.

vulcan.exe: error VN1003: no input files specified

Next create a file called hello.prg with notepad and put the following lines into it:

FUNCTION Start() AS VOID? "Hello"RETURN

Page 29: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

29Part II: The Vulcan.NET Language

Paul Piko, 2010

The main program execution in a Vulcan.NETapplication takes place in FUNCTION Start()

This program can now be compiled like this:

vulcan hello

And Vulcan should compile the program and produce output like this:

Vulcan.NET Compiler version 1.0.0.112 >>> Development Build <<<Copyright (c) Grafx Database Systems, Inc. 2004-2006. All rights reserved.

Compiling ...hello.prgGenerating code...

Build time 0:05:889hello.exe - 0 error(s), 0 warning(s)

Having built hello.exe you can execute it from the command prompt by typing hello and theEXE will respond with this output:

Hello

You can follow steps similar to these for the examples that are presented in the rest of thissection.

The Start function can also receive values from the command line as an array of STRINGs. Hereis some sample code handling command line arguments:

FUNCTION Start(cmdLineArgs AS STRING[]) AS VOIDLOCAL i AS DWORD

FOR i := 1 UPTO cmdLineArgs:Length? cmdLineArgs[i]

NEXT

RETURN

Note that STRING[] is the notation specifying a .NET System array. This array type is differentto a Vulcan ARRAY. One immediately apparent difference is that the .NET array is an objectthat has an instance variable called Length. There is more discussion about arrays in the DataTypes section.

Here is an example of how the program above could be run:

TestCmdArg Kirk McCoy "Mr Spock"

and it would output the following:

KirkMcCoyMr Spock

Page 30: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

30 Vulcan.NET at Warp Speed

Paul Piko, 2010

5.2 New and Changed FeaturesIn addition to supporting the standard Visual Objects features, Vulcan introduces many newconcepts, classes and capabilities. The following pages provide an overview of the newfeatures, which are discussed further in the Vulcan help file.

In a small number of cases, it has been necessary to alter the Visual Objects behaviour, andthese changes are also discussed below.

5.2.1 Assemblies and Libraries

Assemblies were discussed in the section about basic .NET concepts. An assembly is anexecutable or DLL.

In addition to executables and DLLs, VO has a concept of a library. A library is a collection ofcode that can be shared. When the application or DLL using the library is built the code fromthe library is read and included within the generated binary.

In .NET there is no separate, distinct concept of a library in the way it is thought of in VO. Thebest way of reproducing the VO library concept in .NET is to create a file (or group of files) thatcontain the code that you want to share. If you then include this file in the build of your .NETapplication or DLL then you have achieved the same result that the VO library provides.

In .NET when the term library is used it normally meaning a Dynamic Link Library - a DLL.

5.2.2 Namespaces

A .NET namespace is a logical grouping of types. Typically all types within a .NET project belongto the one namespace.

If you compile a single PRG, Vulcan automatically assigns a namespace derived from the filename. For example, if the file being compiled is test.prg the namespace generated is test. Ifmultiple PRGs are compiled the namespace is derived from the first file name. The compilerswitch /ns can be used to explicitly control the namespace:

vulcan test /ns:MyNameSpace

Any types defined within the PRG belong to the namespace. The fully qualified name of anytype includes the namespace. For example, if you create a class called MyClass within test.PRGthe qualified name of the class is test.MyClass.

The namespace becomes especially significant when using multiple assemblies because ithelps the compiler to identify which type is being used.

The .NET Framework uses namespaces to group related types together. Many of the GUIrelated types are in the System.Windows.Forms namespace, the XML related types are in the

Page 31: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

31Part II: The Vulcan.NET Language

Paul Piko, 2010

System.XML namespace and so on.

It is possible for a namespace to span more than one assembly but it is also possible that anassembly can contain more than one namespace. For this reason it is important to know whichnamespace a class belongs to and the assembly it is in. When examining the MSDNdocumentation this information is shown just after the class description:

SqlConnectionRepresents an open connection to a SQL Server database. This class cannot be inherited.

Namespace: System.Data.SqlClientAssembly: System.Data (in system.data.dll)

The extract above shows that the SqlConnection class belongs to the System.Data.SqlClientnamespace. This means the full name of the class is System.Data.SqlClient.SqlConnection. Theclass resides in the assembly called System.Data and the file name is system.data.dll.

5.2.3 Types

Types in Vulcan.NET are not just the basic, primitive data types such as LOGIC, DWORD, etc.but also include classes, structures and enums. Each of them can be thought of as a type.

A number of the types we are familiar with in VO are represented by types that are alreadybuilt in to .NET. For example, the type we know of as LOGIC corresponds to the .NET typeSystem.Boolean. In Vulcan we can refer to the type using either of the forms.

There are also many more basic predefined types available in .NET that were not available inVO. For example, there is the "new" type System.UInt64 - which also has the Vulcan synonymUINT64.

In .NET, as in VO, types can be split into two groups, value types and reference types. Valuetypes actually contain the value and are stored in the memory area known as the stack. All ofthe basic types are value types except a STRING, which is a reference type. Reference typevariables do not contain the actual value. Instead they contain a memory address where thereal value is located. The location that is pointed too is located in the memory known as theheap.

When a variable containing a value type is assigned to another variable a copy of the value ismade. Each variable then contains the same value but occupy different places in memory. Assuch, changing the value of a variable containing a value type cannot affect the value inanother variable.

When a variable containing a reference type is assigned to another variable a copy of thememory address is made. You then have two variable both containing a reference to the samememory location. Visual Objects programmers should be familiar with this concept because it isthe technique used to handle VO dynamic arrays.

.NET also introduces Structs. Structs are used to create value types, whereas classes arereference types. Structs can be considered to be like a light weight class. Because they arevalue types, and are stored on the stack, their size should be kept to a minimum. It is notpossible to inherit from a Struct but they can have methods and fields.

Page 32: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

32 Vulcan.NET at Warp Speed

Paul Piko, 2010

Structs are different STRUCTUREs in VO. A VO STRUCTURE is a block of memory, and does nothave the .NET type features. Because of the similarity in name of Struct and STRUCTURE,Vulcan has renamed VO's STRUCTURE to VOSTRUCT. The term Struct in Vulcan retains its .NETmeaning.

Numeric Types

Integers

.NET Name Vulcan

Name

Size

(bits

)

Low Value High Value Signe

d?

System.

SByte

SBYTE 8 -128 127 Yes

System.

Byte

BYTE 8 0 255 No

System.

Int16

SHORT,

SHORTIN

T

16 -32768 32767 Yes

System.

UInt16

WORD 16 0 65,535 No

System.

Int32

INT,

LONG,

LONGINT

32 -2,147,483,648 2,147,483,647 Yes

System.

UInt32

DWORD 32 0 4,294,967,295 No

System.

Int64

INT64 64 -9,223,372,036,854,775,808 9,223,372,036,854,775,80

7

Yes

System.

UInt64

UINT64 64 0 18,446,744,073,709,551,6

15

No

Floating Point

.NET Name Vulcan

Name

Size

(bits)

Low Value High Value

System.

Single

REAL4 32 -3.402823E+38 3.402823E+38

System.

Double

REAL8 64 -1.79769313486232E+308 1.79769313486232E+308

Note: The Vulcan type FLOAT contains a System.Double along with some other internal data.Therefore the range and operation of FLOAT are similar to System.Double.

DecimalSystem.Decimal is a high precision numeric type typically used for large calculations. It doesnot suffer from the rounding errors that commonly when floating point numbers are used.

.NET Name Size

(bits)

Low Value High Value

System.

Decimal

128 -79228162514264337593543950335 7922816251426433759354395033

5

Page 33: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

33Part II: The Vulcan.NET Language

Paul Piko, 2010

StringsStrings in Vulcan.NET are Unicode UTF-16 format. Note that in UTF-16 each character isrepresented by two bytes. Care should be taken when reading non-unicode text from externalsource because a conversion can occur, which could produce unexpected results if you do notconsider it. For more information about the handling of text and conversions consult theSystem.Encoding class.

5.2.4 Type Conversion

An implicit conversion from one type to another occurs when an assignment is made and theleft and right sides are different types.

FUNCTION Start AS VOID

LOCAL x AS WORDLOCAL y AS DWORD

x := 1y := x

? x,y

RETURN

In this situation the compiler knows that a WORD will fit within the DWORD and theassignment can be made safely. In the next code sample the compiler will produce a warningmessage because it is possible that the INT value may not fit into a DWORD - for example, anynegative INT values cannot be expressed as DWORD.

FUNCTION Start AS VOID

LOCAL x AS INTLOCAL y AS DWORD

x := 1y := x

? x,y

RETURN

Visual Objects allows explicit conversion from one data type to another using the syntax:

<idtype>(<value>)

where idtype is one of ARRAY, INT, PTR, SYMBOL, CODEBLOCK, LOGIC, REAL4, WORD, DATE,LONGINT, REAL8, DWORD, OBJECT, SHORTINT, FLOAT, PSZ, STRING.

If the programmer is certain the value can be safely converted the explicit cast can be used toinform the compiler that the operation is acceptable:

FUNCTION Start AS VOID

Page 34: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

34 Vulcan.NET at Warp Speed

Paul Piko, 2010

LOCAL x AS INTLOCAL y AS DWORD

x := 1y := DWORD(x)

? x,y

RETURN

VO also has (the sometimes misused) _CAST operator:

<idtype>(_CAST, <Value>)

The _CAST is an instruction to the compiler to ignore the current data type and use the valueof the variable, without any conversion, as if it was a different data type. This handling requiresthorough understanding of the memory layout of the contents of the variable to ensurecorrect operation of the program. The inappropriate use of _CAST is often the cause of errors,particularly the ubiquitous 5333. The .NET runtime does not allow unsafe casts betweenincompatible data types and so, while Vulcan.NET accepts _CAST for compatibility, it is actuallyignored. The result of this is that if the source and target data types are incompatible, acompile time error occurs.

While the VO conversions are supported by Vulcan the preferred .NET way of explicitly castingis:

(<idtype>)<value>

where idtype is any data type.

So the sample above could have been written as

FUNCTION Start AS VOID

LOCAL x AS INTLOCAL y AS DWORD

x := 1y := (DWORD)x

? x,y

RETURN

Note that in explicit casting, idtype can be any type, even one of your own classes.

There are also other ways to convert values from one type to another. Many of the .NETclasses have a Parse method to provide more advanced conversion from other types. Forexample, the class DateTime has a Parse method:

FUNCTION Start AS VOIDLOCAL dt AS DateTimeLOCAL cText AS STRING

cText := "2006/09/15 15:15"

dt := DateTime.Parse(cText)

Page 35: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

35Part II: The Vulcan.NET Language

Paul Piko, 2010

? dt

RETURN

There is also a helper type called System.Convert that can be used for the predefined .NETtypes:

FUNCTION Start AS VOIDLOCAL bool AS LOGICLOCAL cText AS STRING

cText := "TRUE"

bool := System.Convert.ToBoolean(cText)

? bool

RETURN

5.2.5 Classes

This page describes the various building blocks used to create classes.

CLASS...END CLASSAs in VO, a class is defined by using the CLASS keyword. In Vulcan it is also necessary to specifya termination to the class definition by using the END CLASS statement.

CLASS Publication

END CLASS

All the code of the class is defined between the CLASS...END CLASS statements. If you want tosplit the code of the class across multiple PRG files you need to use the PARTIAL modifier. Thisinstructs the compiler to look in all the files to find all the parts of the class definition.PARTIAL CLASS Publication

END CLASS

In Vulcan.NET all objects inherit from System.Object

Because all of the parts of the class are contained within the CLASS...END CLASS statements itis no longer necessary to explicitly name the class in METHOD/ACCESS/ASSIGN declarations; inother words, the CLASS <classname> clause that is mandatory in VO can be omitted whenusing Vulcan:

CLASS Publication

// The following line is the old way// METHOD Print AS LOGIC CLASS Publication

// This is the new wayMETHOD Print AS LOGIC// ...

END CLASS

Page 36: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

36 Vulcan.NET at Warp Speed

Paul Piko, 2010

MembersIn .NET the general term for each of the parts of a class definition is member. Methods aremembers, instance fields (sort of like instance variables in VO, see below) are members,properties (ACCESSes/ASSIGNs) are members.

SUPER()When you are within a method you can call the parent version of the method by using the termSUPER().

ConstructorsThe constructor is a special method that is called when an instance of a class is created. InVisual Objects the constructor is the method Init() of the class. You can use Init() in Vulcanusing VO compatibility mode, but the preferred way to write a constructor is to use theCONSTRUCTOR keyword.

CLASS Publication

CONSTRUCTOR() // Instead of METHOD Init()SUPER()// ... more code

Instance FieldsIn Visual Objects we are familiar with the term instance variable. It is a named value that iscontained within an object. In .NET these values are referred to as instance fields.

FUNCTION Start AS VOIDLOCAL o AS Circle

o := Circle{}? o:pi

RETURN

CLASS CircleEXPORT pi := 3.14159 AS REAL8

END CLASS

Static FieldsIn Vulcan the STATIC can be used on a field declaration within a class. A static field is a classfield; the field does not belong to any one instance of the class but to the class itself. Thefollowing example contains a static field called lastAllocated. Each time an instance of the classis created and the CONSTRUCTOR is called the value of lastAllocated is incremented by one.This gives us a rudimentary way of giving each instance of the class a different publicationnumber.

Note that the way we refer to the static field is different to the way we refer to an instancefield. In VO and Vulcan we use the colon, ":", when we want to use an object's field or method,e.g. pub1:pubNumber. The colon always has an object to the left. With static fields there is noobject instance involved, we are working at the class level. A reference to a static field takesthe form of classname.fieldname, e.g. Publication.lastAllocated.

FUNCTION Start AS VOID

Page 37: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

37Part II: The Vulcan.NET Language

Paul Piko, 2010

LOCAL pub1 AS PublicationLOCAL pub2 AS Publication

pub1 := Publication{} // create object and increments lastAllocated? pub1:pubNumber // 1? Publication.lastAllocated // 1

pub2 := Publication{} // create object and increments lastAllocated? pub2:pubNumber // 2? Publication.lastAllocated // 2

RETURN

CLASS PublicationSTATIC EXPORT lastAllocated AS DWORDEXPORT pubNumber AS DWORD

CONSTRUCTOR()SUPER()lastAllocated++pubNumber := lastAllocated

END CLASS

Static MethodsWe saw above that using the STATIC keyword denotes that a field belongs to a class itselfrather than a object of the class. In a similar manner a class method can be declared by usingthe STATIC keyword; in which case the method belongs to the class itself. In the examplebelow GetNextPubNumber is a class method because it contains the keyword STATIC in itsdeclaration. The class method is called using the form classname.methodname, e.g.Publication.GetNextPubNumber().

FUNCTION Start AS VOIDLOCAL pub1 AS Publication

? Publication.GetNextPubNumber() // 1

pub1 := Publication{} // create object and increments lastAllocated? pub1:pubNumber // 1? Publication.lastAllocated // 1

RETURN

CLASS PublicationSTATIC EXPORT lastAllocated AS DWORDEXPORT pubNumber AS DWORD

CONSTRUCTOR()SUPER()lastAllocated++pubNumber := lastAllocated

STATIC METHOD GetNextPubNumber() AS DWORD RETURN lastAllocated+1

END CLASS

Static ConstructorsIn VO we are familiar with the concept that the Init method - or CONSTRUCTOR in Vulcan - isused to initialise an object. Vulcan also supports STATIC CONSTRUCTOR which used to initialisea class itself. A static constructor is called automatically when the first reference to the class is

Page 38: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

38 Vulcan.NET at Warp Speed

Paul Piko, 2010

encountered in the code, and it can be used for whatever initialisation processing you require.

To illustrate this concept the following example uses a static constructor to initialise the valueof the field lastAllocated. This could have been implemented by just assigning the value in theclass declaration but for more complex initialisation, not just a simple value assignment, a staticconstructor is necessary.

FUNCTION Start AS VOIDLOCAL pub1 AS Publication

? Publication.GetNextPubNumber() // 1001

pub1 := Publication{} // create object and increments lastAllocated? pub1:pubNumber // 1001? Publication.lastAllocated // 1001

RETURN

CLASS PublicationSTATIC EXPORT lastAllocated AS DWORDEXPORT pubNumber AS DWORD

STATIC CONSTRUCTOR()// The first usage of this class will // cause the STATIC CONSTRUCTOR to be invokedlastAllocated := 1000

CONSTRUCTOR()SUPER()lastAllocated++pubNumber := lastAllocated

STATIC METHOD GetNextPubNumber() AS DWORD RETURN lastAllocated+1

END CLASS

VIRTUALAll methods in VO are VIRTUAL, meaning that they can be overridden in subclasses, and thelowest occurrence of the method in the inheritance hierarchy is executed. Because this wasnot optional we did not have to explicitly deal with the term VIRTUAL. In Vulcan all methodsare non-VIRTUAL by default, because that is more efficient. It is possible to force Vulcan tomake all methods virtual by using the /vo3 compiler switch.

To explain how virtual/non-virtual methods work, here is an example, starting with somesimple class definitions:

CLASS Publication

VIRTUAL METHOD Print() AS VOID? "Printing publication"

METHOD File() AS VOID? "Filing publication"

END CLASS

CLASS Paper INHERIT Publication

VIRTUAL METHOD Print() AS VOID? "Printing paper"

Page 39: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

39Part II: The Vulcan.NET Language

Paul Piko, 2010

METHOD File() AS VOID? "Filing paper"

END CLASS

Now to demonstrate the method calls we create a Start function. It is important to note thatthe variable o has been declared to be of type Publication; it is this that influences which non-virtual method is called.

FUNCTION Start AS VOIDLOCAL o AS Publication

o := Paper{}

o:Print() // this executes virtual method and prints "Printing paper"o:File() // this executes non-virtual method and prints "Filing publication"

RETURN

The call to the virtual method works in the way we are familiar with in VO. The variable o isdeclared as type Publication but actually created as an instance of Paper, which is alrightbecause Paper is a subclass of Publication. When o:Print() is executed, because Print is virtual,it is the Print() method of Paper that is run. When o:File() is executed, because File() is non-virtual and o is typed as Publication, it is Publication's File() that is run. Had o been declared asPaper then the File() method of Paper would have been run.

INTERNALThe INTERNAL keyword specifies that the item is only accessible within the current assembly.

PRIVATEThe PRIVATE keyword performs the same functions as VO's HIDDEN keyword.

CONST fieldsCONST fields are automatically STATIC, so the value applies to the class, and all instances of theclass see the same value. They are given a value at compile time, and cannot be changed atruntime.

CLASS MyClassCONST EXPORT pi := 3.1415 AS Double

END CLASS

ACCESS and ASSIGN.NET has a concept of a Property, special code that is used to look like a field but actuallyexecutes when the value is set or requested, providing a "virtual" field. This is like VO'sACCESS and ASSIGN pair. An ACCESS represents the "get" and the ASSIGN is the "set". Vulcanplaces a new condition on the use of ACCESS and ASSIGN - the data type of the value beingassigned must be the same as the data type returned from the ACCESS. Here is a validexample:

FUNCTION Start AS VOIDLOCAL pub1 AS Publication

pub1 := Publication{}pub1:Title := "the hitchhiker's guide to the galaxy"? pub1:Title

Page 40: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

40 Vulcan.NET at Warp Speed

Paul Piko, 2010

RETURN

CLASS PublicationPROTECT theName AS STRING

ACCESS Title() AS STRINGRETURN theName

ASSIGN Title(newName AS STRING) AS VOIDtheName := Proper(newName)

END CLASS

The ACCESS returns a STRING and the ASSIGN receives a STRING. If either of these data typeswas different then Vulcan would provide a compile error whereas VO would have let it throughunchallenged.

To create a read-only property, create an ACCESS without a corresponding ASSIGN.

You can use the STATIC keyword on ACCESS and ASSIGN to make class properties, in a similarfashion to using STATIC on a method.

SEALEDThe SEALED keyword, when used on a class, prevents the class from being subclassed. Whenused on a method, SEALED means the method cannot be overridden in a subclass.

ABSTRACTIf a class is ABSTRACT it cannot be instantiated, and so must be subclassed to be of use. If amethod is ABSTRACT it must be overridden in a subclass to be callable.

5.2.6 Arrays

Vulcan supports Visual Objects' dynamic and DIM arrays. It also supports the .NET framework'sSystem.Array and System.Collections.ArrayList.

The VO compatible dynamic array, the type ARRAY, is an array of USUAL values. Using ARRAYis the same in Vulcan as it is in VO:

LOCAL a AS ARRAY

a := { 1, 2, 3 }

? a[1], a[2], a[3]

This dynamic array type is actually a subclass of System.Collections.ArrayList.

Declaring a VO-style dimensioned array looks like this:

LOCAL b[10] AS INT

This declaration creates a strongly typed array with each element being an INT.

The .NET framework's System.Array is something like a VO DIM array; it is an array of stronglytyped values. However System.Array has many useful methods including Sort, BinarySearch,and Reverse.

Page 41: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

41Part II: The Vulcan.NET Language

Paul Piko, 2010

Arrays in .NET are normally zero-based but by default Vulcan treats them as one-based. Youcan declare a System.Array by using the data type of the elements followed by squarebrackets; so declaration of an array of STRINGs would look like this:

LOCAL c AS STRING[]

Arrays with more dimensions are created by using commas between the square brackets. Atwo dimensional STRING array is declared like this:

LOCAL d AS STRING[,]

There is a special syntax to represent a literal strongly typed array. The {} characters representa literal dynamic array, as seen in the first example on this page. The syntax for a stronglytyped array is similar; the type, enclosed in < and >, precedes the {}. So a literal strongly typedSTRING array is represented in the following code fragment:

LOCAL c AS STRING[]

c := <STRING>{ "a", "b", "c" }

You can create a System.Array of a certain size at runtime using the following syntax:

LOCAL c AS STRING[]

c := STRING[]{3}

c[1] := "a"c[2] := "b"c[3] := "c"

Alternatively you can use the CreateInstance method of System.Array to allocate an array of aspecific size, which can then be filled with values later:

LOCAL c AS STRING[]LOCAL len AS INT

len := 3

// need to cast the System.Array returned// by CreateInstance to a STRING[] arrayc := (STRING[])Array.CreateInstance( typeof(STRING), len )

If you use System.Collections.Array list you do not need to initially specify the size of the array.You can just use the Add method to place new entries at the end of the list. The elements canbe of any type:

LOCAL a AS System.Collections.ArrayList

a := ArrayList{}a:Add( "a" )a:Add( 2 )a:Add( TRUE )

Page 42: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

42 Vulcan.NET at Warp Speed

Paul Piko, 2010

5.2.7 Enums

An Enum is a type that provides a way to give names to elements in a set of values. You canchoose to let the elements be given values automatically or you can explicitly provide them.

Enums are much more readable then using literal values. They are better than #definesbecause you can group together related values.

Here is a sample of an Enum:

ENUM DirectionNorthEastSouthWest

END ENUM

And the Enum is used as follows:

FUNCTION DoSomething() AS VOID...DO CASECASE x == Direction.South

...CASE x == Direction.West

...ENDCASE...

The value of the members within the Enum must be an integral type; by default, the type isINT. You can control the type of the Enum members by using the AS clause:

ENUM Direction AS DWORDNorthEastSouthWest

END ENUM

When no value is explicitly given the members will automatically be given values, starting withzero. The Enum above could be re-written as:

ENUM Direction AS DWORDNorth := 1East := 2South := 3West := 4

END ENUM

5.2.8 Functions and Procedures

In Vulcan.NET functions and procedures are implemented as static methods of a hidden,compiler generated class.

The hidden class name is made up of the namespace name followed by "Functions". Forexample the full name of a function could be MyLibrary.MyLibraryFunctions.Test(). In this

Page 43: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

43Part II: The Vulcan.NET Language

Paul Piko, 2010

example the MyLibrary is the namespace name, MyLibraryFunctions is the hidden class nameand Test is the static method/function name.

The way it works is as follows: If you have a library of functions in MyLibrary.prg the compilerautomatically gives it a namespace name that is the same as the PRG name. So the namespacefor MyLibrary.prg defaults to MyLibrary. The compiler then uses the namespace name tocreate the hidden class and calls it MyLibraryFunctions. Any functions or procedures withinthat PRG are then made static methods of the hidden class.

Other .NET languages such as C# or VB.NET are not aware of the Vulcan.NET feature ofFUNCTIONs and PROCEDUREs. In order to call a Vulcan.NET function (or procedure) fromanother language you need to call it as the static method of the hidden class, e.g.MyLibraryFunctions.Test(). The following is a C# console application calling a function in aVulcan-authored assembly:

using System;using System.Collections.Generic;using System.Text;using MyLibrary;

namespace ConsoleApplication3{ class Program { static void Main(string[] args) { MyLibraryFunctions.Test(); } }}

5.2.9 Overloading

Methods in Vulcan.NET can be overloaded. This means you can have the same method nameused more than once within a class, provided the parameters used in each declaration aredifferent, creating a different parameter signature for each method. The parameter signatureof a method is determined by the types of the parameters and the manner in which they arereceived (i.e. whether they are passed by reference or not). Overloading can not occur if onlythe type of the return is different.

Functions can also be overloaded; once again the parameter signatures must be different tooverload successfully.

The following example shows the overloading of SubStr. The first function declared acceptstwo parameters, the second function accepts three. Because the first function is only giventhe string and starting point, it calculates a default length and then directly calls the secondSubStr.

FUNCTION SubStr(c AS STRING, nStart AS INT) AS STRING LOCAL cReturn AS STRING LOCAL nLen AS INT

nLen := c:Length

IF nStart < 0

Page 44: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

44 Vulcan.NET at Warp Speed

Paul Piko, 2010

nLen := Abs(nStart) ENDIF

cReturn := SubStr(c,nStart,nLen-nStart+1) RETURN cReturn

FUNCTION SubStr(c AS STRING, nStart AS INT, nLength AS INT) AS STRING LOCAL cReturn AS STRING

IF nStart == 0 nStart := 1 ENDIF

IF nStart < 0 nStart := c:Length+nStart+1 ENDIF

IF nLength < 0 nLength := c:Length ENDIF IF nStart <= c:Length .and. nStart > 0 nLength := Min(c:Length-nStart+1,nLength) cReturn := c:Substring(nStart-1,nLength) ENDIF RETURN cReturn

Overloading is also useful when you want to pass different data types to the same function ormethod.

The next example shows the overloading of Empty. By having different overloads of Emptythe compiler can determine the actual function that will be called at compile time, and soproduce more efficient code. It also allows the compiler to perform type checking, potentiallyidentifying errors at compile time rather than runtime.

FUNCTION EMPTY( n AS REAL8 ) AS LOGIC RETURN n == 0 FUNCTION EMPTY( l AS LOGIC ) AS LOGIC RETURN ! l

// and more Empty overloads for other data types// ....

Consider the less efficient alternative without overloading; if Empty() receives a USUAL then ithas to work out at runtime what the data type is. This means more work to be carried out atruntime (and therefore slower execution) and loss of compile time type checking:

// The old, less efficient, non-overloaded alternative// NOT RECOMMENDED!!!FUNCTION EMPTY(u AS USUAL) AS LOGIC LOCAL nType AS WORD LOCAL ret AS LOGIC

nType == UsualType(u) DO CASE CASE nType == LOGIC ret := ! u CASE nType == LONG ret := ! u == 0 // more CASEs for other data types // ....

Page 45: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

45Part II: The Vulcan.NET Language

Paul Piko, 2010

RETURN ret

5.2.10 Exception Handling

VO has the capability to define a single place where all errors are routed through the use of adefault error handler. The error handler is installed by using ErrorBlock().

The .NET Common Language Runtime does not support the concept of a central error handler.So Vulcan does not have a default error handler. It does, however, support the use ofexception handling blocks such as BEGIN SEQUENCE-RECOVER, and the new TRY-CATCH-FINALLY. It is within these exception handling blocks that your error handling should occur.

In .NET, exception handling takes place in the code close to the exception. When anexception is thrown the Vulcan looks back through the call stack, looking for an encompassingexception handling block. The exception is then passed to the appropriate RECOVER orCATCH.

BEGIN SEQUENCE-RECOVER has been updated to include a new statement within the block:FINALLY. The FINALLY section of code is always executed, whether there was an error or not.It is a good place to put cleanup code that must run, irrespective of error:

FUNCTION Start AS VOIDLOCAL err AS USUAL

BEGIN SEQUENCE

// code that may produce error

RECOVER USING err? "An error occurred"

FINALLY? "Cleaning up"

END SEQUENCE

RETURN

As in VO, the RECOVER can accept a USUAL variable when an error occurs. You can also useBREAK to explicitly raise an exception.

There is also a new exception handling block, TRY-CATCH-FINALLY. Here is an example:

FUNCTION Start AS VOID

TRY// code that may produce error

CATCH divError AS System.DivideByZeroException? "An error occurred"

CATCH? "Other error"

FINALLY? "Cleaning up"

Page 46: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

46 Vulcan.NET at Warp Speed

Paul Piko, 2010

END TRY

RETURN

The CATCH statement can be used to handle different types of exception, and receive theexception in a strongly-typed variable. Any exception inherited from System.Exception can behandled.

BREAK passes a USUAL back to the exception block, so cannot be used with TRY-CATCH-FINALLY, which wants to receive a System.Exception or subclass. To raise a strongly typedexception you need to use THROW.

5.2.11 Delegates and Events

Delegates have some similarity to function pointers available in Visual Objects. In VO it ispossible to do something like this:

FUNCTION StartLOCAL p AS PTR

p := @Test()

PCALL(p)

inkey(0)

RETURN

FUNCTION Test()? "Hello"RETURN

In the above example the pointer to a function is stored in a variable and then later executed.

On the other hand, a delegate in .NET is a way of representing a method call and allows you topass around the reference to the method for later execution. And unlike function pointersdelegates incorporate type checking. In the example above it is easy to experience problemsif the pointer variable is invalid, or represents a function other than the particular one that isexpected. Delegates are commonly used for event handlers or anywhere a call-back isrequired.

It is possible to define your own delegates however you will find that you are frequently usingdelegates that are predefined in the .NET framework. System.EventHandler is often used;System.Windows.Forms.MouseEventHandler is another that occurs often. The delegateconstructor takes two arguments; the first is the class instance on which the method will beinvoked and the second is the reference to the method to execute:

LOCAL handler AS System.EventHandlerLOCAL OKButton AS System.Windows.Forms.Button

handler := System.EventHandler{SELF, @MyForm.OnOKButton()}

Once the delegate is defined it can be connected to the event as follows:

Page 47: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

47Part II: The Vulcan.NET Language

Paul Piko, 2010

OKButton:Click += handler

Click is an event belonging to the Button class. The += is used to attach the delegate instanceto the event; it is possible to add multiple delegates, hence the use of +=. The only otherdelegate assignment is -= which is used to remove a delegate. Use of the standard assignment:= is not supported when dealing with delegates and events - you need to use += and -= toattach and detach the delegates.

5.2.12 Attributes

Attributes provide additional information to the compiler about program items. Attributes canapply to whole assemblies, types (classes, structs, enums), methods, fields, properties and soon. Each program item will have its own set of attributes that are applicable to it.

Attributes usually appear before the item they apply to, and are enclosed in square brackets.

For example, when creating a web service class, only methods that have the WebMethodattribute are accessible via the web service.

CLASS MyService INHERIT System.Web.Services.WebService

CONSTRUCTOR()SUPER()RETURN

[WebMethod(Description := "Example web method")] ;METHOD WebQuery(c AS STRING) AS STRING

// This method can be called via the web service// ...

METHOD LocalProcess() AS VOID// This method is not visible via the web service// ...

END CLASS

For readability the attribute is often written on a line by itself, connected to the following lineby the use of the line continuation character (semi-colon).

When the attribute only applies to part of a line it is normally just embedded within the line. Forexample, when a method or function can receive a variable number of parameters they areactually contained within a array. The ParamsArray attribute helps tell the compiler that theindividual arguments used in the function call should be collected into the array. Without thisattribute the compiler would think that the function needs to be explicitly passed an array,rather than a list of entries:

FUNCTION DoSomething( [ParamsArray] arguments AS OBJECT[] ) AS VOID

5.2.13 "." versus ":"

When you are very familiar with Visual Objects but are still new to Vulcan, the use of "." and ":"can appear confusing.

Page 48: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

48 Vulcan.NET at Warp Speed

Paul Piko, 2010

The ":" is the object message send operator; the thing to the left of it is an object, and thething to the right is a method name, an instance variable or an ACCESS/assign.

So typical VO code fragment can appear like this:

LOCAL o AS MyClass

o:DoSomething()

The code above is valid in Vulcan as well.

In Vulcan the "." is used when you want to qualify a name. All types (classes, structs, etc)belong to a namepace. Functions, being implemented as methods of an internal class, alsobelong to a namespace. When we want to fully qualify the name of a function we use<Namespace>.<FunctionName>. So the full name of a function called DoAnotherThing innamepace MyNamespace is:

MyNamespace.DoAnotherThing()

If we have a class called MyClass with namespace MyNamespace its full name is in the form<Namespace>.<ClassName>:

MyNamespace.MyClass

One of the common system namespaces is System.Windows.Forms, and it contains a classcalled Form. Form's full name is:

System.Windows.Forms.Form

You can use the #using directive to avoid having to write the full names of types; the compilerwill try to resolve the type names by looking at the namespaces specified in any #usingdirectives:

#using System.Windows.Forms

CLASS MyForm INHERIT Form // compiler works out this is System.Windows.Forms.Form

Some classes have static members. You can think of static members as methods, fields(variables) and properties that belong to the class itself rather than of an object. Visual Objectsdoes not have anything equivalent to static members, although they were available in Clipper ifyou used the add-on called Class(y).

If you want to refer to a static member you need to use the "." before the member name. Youmight be tempted to use ":" because it looks like an object message send but the ":" needs tohave an object to its left.

The following code is an example to illustrate the point. The class, MyClass, has a staticmember, an exported field called count. To refer to this static member we use MyClass.count:

FUNCTION Start() AS VOIDLOCAL o1 AS MyClassLOCAL o2 AS MyClassLOCAL o3 AS MyClass

Page 49: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

49Part II: The Vulcan.NET Language

Paul Piko, 2010

o1 := MyClass{"One"}? MyClass.count // prints 1, there has been 1 MyClass instantiation

o2 := MyClass{"Two"}? MyClass.count // prints 2, there have been 2 MyClass instantiations

o3 := MyClass{"Three"}? MyClass.count // prints 3, there have been 3 MyClass instantiations

o1:DoSomething()o2:DoSomething()o3:DoSomething()

RETURN

CLASS MyClass STATIC EXPORT count AS DWORDEXPORT Name AS STRING

CONSTRUCTOR(newName AS STRING)SELF:Name := newNamecount++

METHOD DoSomething() AS VOID? SELF:NameRETURN

END CLASS

5.2.14 Pragmas

Pragmas, instructions to the compiler embedded within the code, take a different form inVulcan.NET. To use a pragma you start the line of code with #pragma, and then follow it withdetails of the compiler directive. There are three main directives you can use: warnings,options and reference.

Compiler WarningsYou can save and restore the current state of all warnings, and explicitly enable and disableindividual warnings.

For example, to turn off a particular compiler warning you do this:

#pragma warnings( push )#pragma warnings( 3030, off )

// code that produces 3030

#pragma warnings( pop )

OptionsThere are three compiler options that you can control via pragmas: "vo2", "ovf", and "fovf".The vo2 option controls the way strings are initialised, like the /vo2 compiler switch. The ovfoption determines if exception are thrown from integer overflows; fovf determines if floatoverflows result in exceptions. You can save and restore the state of the options using pushand pop:

Page 50: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

50 Vulcan.NET at Warp Speed

Paul Piko, 2010

#pragma options ( push )#pragma options ( "ovf", off )

// code that produces overflow

#pragma options( pop )

ReferenceWhen your code needs something from an assembly outside your project you need to addreference to it. This is normally done using the compiler's /r switch. It is possible to include thereference in your code by using a pragma:

#pragma reference ( "MyLibrary.dll" )

Page 51: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

51Part II: The Vulcan.NET Language

Paul Piko, 2010

5.3 Vulcan Runtime LibraryMost of the Visual Objects runtime functions have been rewritten in Vulcan itself. The Vulcanruntime functions are contained in the VulcanRTFuncs.dll assembly. The functions belong tothe VulcanRTFuncs namespace.

As described earlier, functions in Vulcan are actually implemented as methods of a class. Theclass in this case is Functions.

A list of all the runtime functions is provided in the Vulcan help file.

Page 52: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

52 Vulcan.NET at Warp Speed

Paul Piko, 2010

6 Part III: The VO Way

Part III: The VO Way

Page 53: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

53Part III: The VO Way

Paul Piko, 2010

6.1 Making VO Code Usable by Vulcan.NETThe easiest way to make your Visual Objects source code accessible to Vulcan.NET is to use theTransporter utility. This utility reads the code in your VO repositories and writes it out as PRGfiles. It also automatically creates a Visual Studio solution that can be used to build a Vulcan.NET executable from the code.

To ease the movement of code to Vulcan.NET it is strongly recommended that you enable allwarnings in VO 2.8 SP1 and ensure you have addressed all compilation messages.

As an example we will take a simple master-detail VO application and transport it. The followingimage shows an application called Orders in a VO project called Demo.

The Orders application has two DBServers, generated with VO's DBServer editor, and amaster-detail DataWindow based on those DBServers. There is also a class to handle simpleprinting of the orders. When the application is run it looks like this:

Page 54: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

54 Vulcan.NET at Warp Speed

Paul Piko, 2010

The navigation controls can be used to move through the file, entries can be added, editedand deleted. When the Print option is selected the current order is printed. The image belowshows the order printed to Vista's XPS printer:

To transport this application you can select Import Visual Objects Application from the VisualStudio Tools menu. You can also run transporter.exe from the Vulcan.NET BIN folder.

Page 55: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

55Part III: The VO Way

Paul Piko, 2010

Transporter first displays an introductory screen:

Transporter then looks at your VO configuration and finds your projects. You can select oneproject.

Page 56: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

56 Vulcan.NET at Warp Speed

Paul Piko, 2010

Transporter reads the selected project and shows a list of the applications, libraries and DLLs.You can select one or more of them to transport. In our example the application we want totransport is Orders, as shown below. The Library is unrelated code, so we leave it unchecked.

You need to specify where Transporter should write out the files. Transporter creates asolution folder and each application that was selected is written to a sub-folder of that solutionfolder:

Page 57: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

57Part III: The VO Way

Paul Piko, 2010

Once you have completed all the steps Transporter presents a summary of what it is about todo. Clicking the Next button commences processing.

Transporter displays a progress screen as it processes.

Page 58: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

58 Vulcan.NET at Warp Speed

Paul Piko, 2010

When processing is complete the final wizard screen is displayed.

Transporter produces a conversion report that shows the results of the processing. In ourexample there are a number of warnings. The position of the cause of the warning is given sothat you can see what requires attention. In this case all the warnings arise from the DBServereditor generated code, where the field ASSIGNs return a value. It is optional whether youchange the code to remove this warning - by default Transporter disables the warning in theVisual Studio solution to ease the conversion.

Page 59: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

59Part III: The VO Way

Paul Piko, 2010

The following image shows the Demo folder that was created by Transporter, and the Orderssub-folder.

The Visual Studio solution, Demo.sln, can also be seen in the Demo folder along with theconversion report, TransporterLog.xml.

The Order folder contains the transported PRG files, one for each module within the VOapplication. Within the Orders folder is another folder called Original. The Original foldercontains the source code as it was before Transporter made any changes to it. The changesthat are made are documented in the Vulcan help in the section titled "Source Code ChangesMade By The Transporter".

The Orders folder also contains a Resource folder, where all the resources referenced by theapplication reside.

At this stage you can choose to continue on with Visual Studio, or you could decide to use thetransported files in another environment such as VIDE. If you do choose to use anotherdevelopment IDE you should consult its documentation on how to make use of thetransported files.

Page 60: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

60 Vulcan.NET at Warp Speed

Paul Piko, 2010

For this example we will continue with Visual Studio. When you open the solution in VisualStudio you can see the PRGs in the Solution Explorer:

Attempting to build the solution immediately results in an error. The reason for this error isdocumented in the Vulcan help section called "Compiling and Running Your MigratedApplication". Basically, the presence of the compiler keyword __VERSION__ within a resourceneeds addressing by replacing it with a define. The following image shows the compile error:

Page 61: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

61Part III: The VO Way

Paul Piko, 2010

Double clicking the error opens the offending code:

The error can be corrected by create a #define called MYAPPVERSION, then replacing the__VERSION__ with MYAPPVERSION. Compiling then results in a successful build.

There is one more thing to do before attempting to run this code. The application makes useof a DataBrowser. The core DataBrowser functionality is not contained in VO code but isprovided by some additional DLLs: CATO3CNT.DLL, CATO3DAT.DLL, CATO3MSK.DLL,CATO3NBR.DLL, CATO3SBR.DLL, CATO3TBR.DLL, CATO3TIM.DLL. Our transported example isalso using DataBrowser, so also requires these additional DLLs. So it is necessary to copy theseDLLs to a location where they can be accessed by our new executable. Probably the easiest

Page 62: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

62 Vulcan.NET at Warp Speed

Paul Piko, 2010

thing to do is to copy then to the Debug folder within the Orders folder. Once that is done wecan run the executable from Visual Studio, or from the Debug folder, and the new .NETapplication appears, looking and working like the original:

Page 63: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

63Part III: The VO Way

Paul Piko, 2010

6.2 Using the VO Class LibrariesThe VO class libraries are compiled with Vulcan.NET, and perform just as they did in VO. Youinstantiate objects of the classes the same way, call the methods in the same manner and setthe value of properties the same way.

When writing VO-style code you should be making use of the VO compatibility compilerswitches. In Visual Studio these are set via the project properties:

At the command line the switches to use are:

Switch(Follow with a + to enable, a - to disable. E.g. /lb+)

Description

/lb Allow Late Binding

/vo1 Support Init as object constructor, Axit as finaliser

/vo2 String variables initialised to ""

/vo3 Methods of objects are virtual

/vo4 Automatic conversion between signed/unsigned integers

/vo5 CLIPPER calling convention is the default

/vo6 Allows implicit return values

These switches are described very well in the Vulcan.NET reference help file.

Page 64: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

64 Vulcan.NET at Warp Speed

Paul Piko, 2010

6.3 Handling VO Binary EntitiesWhile VO binary entities cannot be directly maintained in Visual Studio it is still possible to workwith the content of some of the entities.

Transporter has an option to re-create windows that were originally constructed with the VOWindows editor as Visual Studio forms. You can see an example of this in the "Making VO CodeUsable by Vulcan.NET" section.

The Visual Studio image editor can be used to edit any image resources. When Transportercreates a Visual Studio solution it copies any resources it finds to a sub-folder of the project,and an entry for each resource is included in the Solution Explorer.

Page 65: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

65Part IV: The .NET Way

Paul Piko, 2010

7 Part IV: The .NET Way

Part IV: The .NET Way

Page 66: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

66 Vulcan.NET at Warp Speed

Paul Piko, 2010

7.1 Using Visual StudioVisual Studio VersionsIn this document Visual Studio 2005 is used for most of the examples. The user interface inVisual Studio 2008 is a little different but in most cases the same technique can be used.

SolutionsAt the highest level, Visual Studio works with Solutions. Each solution contains a collection ofprojects. The projects in turn contain a collection of files:

Solution

â â â

Project 1 Project 2 Project 3

â â â

File1, File2, etc File1, File2, etc File1, File2, etc

While solutions can only contain projects it is possible for a project to belong to more than onesolution.

The following table shows how the Visual Studio terms correspond to the terms we are familiarwith in Visual Objects:

Visual Studio Term Visual Objects Term

Solution Repository or Project

Project Application, Library or DLL

File Module

ProjectsProjects contain the source files required to build an assembly, that is, an executable or a DLL.The main project types available with Vulcan.NET are: Windows Application, ConsoleApplication, Class Library and Empty Project. The first two produce executables and the thirdproduces a DLL. The fourth, Empty Project, just sets up the skeleton project with no additionalfiles and can be used for building any type of assembly from scratch.

Visual Studio can be extended with addition projects types and templates so the list ofavailable projects is expected to grow over time.

7.1.1 Creating a Solution and a Project

When you fire up Visual Studio the Start Page is displayed. On the left side of this page is a boxthat displays the recent projects that have been worked on. Beneath the list of RecentProjects are options to open or create a project:

Page 67: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

67Part IV: The .NET Way

Paul Piko, 2010

When you select Create Project a dialog is displayed where you can choose the type of projectyou want to create. Part of this dialog also contains the name of the solution that will containthe new project; the solution and the project are created at the same time:

Page 68: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

68 Vulcan.NET at Warp Speed

Paul Piko, 2010

When the project is created its contents depend on what template had been selected. For aWindows Application the new project contains code to display a form and automatically opensthe form designer:

Page 69: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

69Part IV: The .NET Way

Paul Piko, 2010

A new Console Application project just contains the simple code to write to the console, withthe project properties set appropriately:

FUNCTION Start( cmdlineArgs AS STRING[] ) AS INT LOCAL retcode AS INT ? "Hello from Vulcan" RETURN retcode

A new Class Library project contains the code for a simple class with the project settingsconfigured to create a DLL.

While you are working on a solution if you want to create a new project in a new solution youcan select File, New, Project from the menu. If you want to add another project into thecurrent solution you need to right-click on the solution name in the Solution Explorer andselect Add, New Project from the context menu.

The Build menu gives you the option of building the solution or just the current project:

Page 70: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

70 Vulcan.NET at Warp Speed

Paul Piko, 2010

When you build a project the location of the output is determined by the current configurationof the project. The configuration is selected via the toolbar or through the Configurationmanager in the Build menu. There are two default configurations: Debug and Release. Eachconfiguration contains its own set of project and compiler settings. When the Debugconfiguration is selected for a project the output is written to the Debug folder within theproject folder. When the Release configuration is selected for a project the output is written tothe Release folder within the project folder.

If the project produces an executable it can be run via the Debug menu using the StartDebugging or Start Without Debugging options:

Adding Files to the ProjectYou can add additional files to the project by right clicking on the project name in the SolutionExplorer and selecting Add, New Item. A dialog is displayed containing templates for the typesof file you are able to add:

Page 71: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

71Part IV: The .NET Way

Paul Piko, 2010

If you want to add a file that already exists to the project you right click on the project name inthe Solution Explorer and selecting Add, Existing Item. An open file dialog is then shown soyou can select the existing file.

Adding ReferencesWhen a project depends on something external to the project it needs to reference thatexternal component. References can point to another project within the same solution, a .NETassembly or a COM component.

To add a reference click on the project name in the Solution Explorer and select AddReference. A dialog like the following is displayed:

Page 72: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

72 Vulcan.NET at Warp Speed

Paul Piko, 2010

There are four tabs on this dialog; one for .NET assemblies, one for COM, one for projects andone called Browse. The Browse tab is used to locate assemblies that are not shown on the .NET tab.

When you add a reference to a COM component Visual Studio will look for a pre-existingassembly representing the component (an "interop assembly"). If it does not find one it willcreate one. An interop assembly is a .NET wrapper class around a COM component. When aninterop assembly has been strongly signed it is called a primary interop assembly. You cangenerate an interop assembly from the command line by using the TLBIMP.exe utility.

Page 73: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

73Part IV: The .NET Way

Paul Piko, 2010

7.2 Creating An MDI ApplicationMany Visual Objects applications make use of the Multiple Document Interface (MDI)approach. In appearance an MDI application has a single parent (shell) window that cancontain one or more child windows. These child windows can only be seen within in the parentwindow and do not protrude outside the parent. Normally the menu and any toolbar arehosted by the parent form and are not part of the child window although it is possible to breakthis convention programmatically. Within the parent only one of the child windows can beactive at a time and all input is directed to that window.

Some of the Visual Objects template applications are MDI applications. In this section we seehow to create an MDI application using Visual Studio.

7.2.1 The Parent Form

Creating the Parent FormFirst we need to create a new Vulcan project using the Windows Application template:

When the new form is displayed find the IsMdiContainer property in the Windows Style sectionof the form's Properties window and change it to True. The appearance of the form willimmediately change; the form's background turns to a darker colour:

Page 74: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

74 Vulcan.NET at Warp Speed

Paul Piko, 2010

You can then change the Text property to whatever you want to appear in the caption bar ofthe window. If you also want to you can rename the PRG file to something more meaningful, e.g. MyShellWindow.prg. You can do this by right clicking on the Form1.prg entry in the SolutionExplorer treeview and selecting Rename from the context menu. While that renames the PRGit does not affect the class name of the window. To change the class name you need to go tothe Design section of the form's properties and change the (Name) entry. After those changesyou should end up with something like this:

Page 75: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

75Part IV: The .NET Way

Paul Piko, 2010

If you change the class name of the first generatedform in a project do not forget to change thereference to it in the Start function!

The next step is to create a menu for our shell window. To do this find the MenuStrip in theToolbox and drag and drop it on to the form. The form designer then appears as follows:

Page 76: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

76 Vulcan.NET at Warp Speed

Paul Piko, 2010

MenuStrip supercedes the MainMenu class of earlierversions of the .NET framework. It provides greaterconfigurability, including the ability to easily add avariety of controls and change appearance similar toMS Office menus.

The "Type Here" area of the menu strip is the area where we can enter the menu options wewant. As you are typing additional prompts appear, allowing you to add items to the right andbelow the current item. After adding items for File, Open, Exit and Window the form designerlooks like this:

Page 77: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

77Part IV: The .NET Way

Paul Piko, 2010

The Window menu option is where we want the list of open child windows to appear. Toenable this we just need to set a property and do not have to provide additional code. Theproperty that needs to be set is the MdiWindowListItem property of the MenuStrip; it needs tobe set to the name of our Window menu item which is automatically generated aswindowToolStripMenuItem.

There are some more changes to make to the shell window but we will come back to thoseafter we have created the child form.

Page 78: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

78 Vulcan.NET at Warp Speed

Paul Piko, 2010

7.2.2 The Child Form

Right click on the project in the Solution Explorer and select Add, New Item from the contextmenu. In the Add New Item dialog that appears select the Window Form template and fill inthe name:

The new form is then displayed in the form designer. In the simplest situation that is all that weneed to do in the designer. The connection between the shell and the child is made when thechild is instantiated which is typically handled by a method of the shell, so there is no directreference made to the parent from here.

Of course you would continue designing you child form, customising it as your applicationrequires. Maybe your form would contain a DataGridView control to show data, or possibly aRichTextBox for input of text. For our example here we will leave the form blank.

One other issue you may be wondering about is how the application's menu works inconjunction with the child window. .NET provides a different approach to the one we are usedto with VO where each window is given its own menu. This issue is discussed after the nextpart covering how the parent window manages the child windows.

7.2.3 Child Management

Now that we have our child form designed we can return to the MDI parent window.

Click on the File, Open menu item in the MenuStrip. In the Properties window switch to Eventview (click the lightning bolt icon) and double click the area next to the Click event. VisualStudio automatically creates an event name, openToolStripMenuItem_Click, and switches tothe source code editor so that you can write the code for that event. The code to create achild window and specify its parent is shown below.

Page 79: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

79Part IV: The .NET Way

Paul Piko, 2010

PRIVATE METHOD openToolStripMenuItem_Click( sender AS OBJECT, e AS System.EventArgs ) AS VOID LOCAL child AS MyChildWindow child := MyChildWindow{} child:MdiParent := SELF child:Show() RETURN

The Form:Show() method displays a modelesswindow. For modal behaviour take a look at theShowDialog method.

Our MDI sample can now be run and each time the File, Open menu option is selected a newchild window is displayed. The Window menu option is also automatically updated, andswitching from one open window to another is handled by the MDI parent.

Child LayoutIt is also common to include menu options that provide default layouts of child windows withina parent, such as Cascade or Tile. Adding this behaviour is straight forward:

Page 80: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

80 Vulcan.NET at Warp Speed

Paul Piko, 2010

· Add three new menu items under the Window menu: Cascade, Tile Vertically and TileHorizontally. For clarity it may be useful to add a separator before these items by typing adash/minus sign as the item name

· Double click next to the Click event in the Properties for each of the items.

· Add code into the generated stub methods as shown below:

PRIVATE METHOD cascadeToolStripMenuItem_Click( sender AS OBJECT, e AS System.EventArgs ) AS VOID SELF:LayoutMdi(System.Windows.Forms.MdiLayout.Cascade) RETURN PRIVATE METHOD tileVerticallyToolStripMenuItem_Click( sender AS OBJECT, e AS System.EventArgs ) AS VOID SELF:LayoutMdi(System.Windows.Forms.MdiLayout.TileVertical) RETURN PRIVATE METHOD tileHorizontallyToolStripMenuItem_Click( sender AS OBJECT, e AS System.EventArgs ) AS VOID SELF:LayoutMdi(System.Windows.Forms.MdiLayout.TileHorizontal) RETURN

The image below shows the child windows tiled vertically.

7.2.4 Menu Handling

The .NET Framework has its own built-in handling for menus in MDI applications. Essentially ithas a concept of two menu types; one for the parent and another for the child. When a childwindow is attached to the parent the child's menu items are merged with the parent's,creating a combined menu derived from both of them. This is an automatic behaviour. Whenthe child windows are closed the menu returns to the original parent menu.

Page 81: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

81Part IV: The .NET Way

Paul Piko, 2010

The way the two menus are merged is controlled by the menu items' MergeIndex andMergeAction properties. The MergeIndex controls the relative item positions when themenus are merged. The MergeAction determines what happens when items in the menusmatch; the possible actions are Append, Insert, MatchOnly, Remove and Replace. If you wanttwo submenus to be combined into one it is important that they should both have the sameMergeIndex.

We will now work through an example to see how this is use in practice.

Our earlier menu had two main items on the parent window: File and Window. Beneath the Fileitem are the options Open and Exit. Beneath the Window item are the options Cascade, TileVertically, Tile Horizontally and a menu separator. This submenu also automatically containsitems representing any open child windows. This menu can be represented like this:

File Open Exit

Window Cascade Tile Vertically Tile Horizontally Separator

Now, for this example, we want to achieve a menu structure that has the following optionswhen a child window is open:

File Open Close Exit

Edit

Window Cascade Tile Vertically Tile Horizontally Separator

Because the child's menu will be merged with the parent's menu the new items we need todefine are Close (beneath a File menu) and Edit. We also need to set the MergeIndex andMergeAction properties so that we get the desired result.

To do this we open the child form and drop a MenuStrip on to it. In the MenuStrip we createFile and Edit items, and beneath File we create a Close item.

Page 82: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

82 Vulcan.NET at Warp Speed

Paul Piko, 2010

In the Layout section of the Properties of the File menu item the MergeAction is set toMatchOnly. This means the File item will only be used to assisting the framework in matchingthe menu items but nothing is done with that item itself. This is the way this File menu is linedup with the File menu in the parent window - the names of the items must be exactly thesame (including any accelerator, i.e. the & character) for the match to be successful.

The MergeAction of the Edit item and the Close item are set to Insert because we want theseitems to be inserted into the parent's menu.

The MergeIndex values of these items and those of the parent menu determine where theinserted items appear. So we need to return to our parent menustrip and allocate someMergeIndex values (by default MergeIndex is -1). The main items of the menustrip are File andWindow, so we allocate MergeIndex values of 1 and 2 respectively to those items.

Because the MergeIndex applies to each menu level we can set the MergeIndex of the Openitem in the submenu to 1 and it will not conflict with the main level containing File and Window.We give the Exit item a value of 2.

The menu merging we are proposing does not affect the Window submenu so it is notmandatory to allocate MergeIndex values to those items. If we later decide we do want childmenu items to be merged with the Window submenu we would need to allocate the values.

Now that we have MergeIndex values set for the parent menu we can adjust the child menuitem properties. The Edit menu MergeAction was set to Insert. The insertion occurs at theposition after the MergeIndex value. So if we set the Edit MergeIndex to 1 the item will beinserted after the item in the parent menu that has a MergeIndex value of 1. In our case thatmeans it will be inserted after the File item.

The merging of the Close menu option occurs in a similar manner except that its parent item,the File item, comes into play. The File item has a MergeAction of MatchOnly so automaticallythe parent and child File submenus are matched. The MergeIndex values then relate to the

Page 83: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

83Part IV: The .NET Way

Paul Piko, 2010

matched submenu, so the Close MergeIndex of 1 and MergeAction of Insert mean that theitem is inserted after the Open item (which has a MergeIndex of 1).

The last thing that needs to be done is to set the Visible property of the child menu to False. Ifthe child menu's Visible property is True the menu is displayed on the child form and nomerging takes place. By setting the Visible property to False the child's menu items aremerged with the parent's menu, and no menu is shown on the child.

The resulting menu appears as shown in the image below. The completed example code is inthe MDI2 solution.

Page 84: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

84 Vulcan.NET at Warp Speed

Paul Piko, 2010

7.3 Data Handling With WinFormsThis section begins with simple form elements and builds up to more complex forms displayingdata. It shows Vulcan DBF handling in use, as well as examples of working with an OLEDB dataprovider. We see how data binding, the linking of data to controls, is achieved and look at someadvanced .NET components such as DataGridView and DataSet.

7.3.1 Displaying a Form

Before we get into the details of data handling we need to review a basic application thatdisplays a window. The code follows, and we examine it below.

#using System#using System.Windows.Forms#using System.Drawing

[STAThread];FUNCTION Start() AS VOID

Application.EnableVisualStyles()Application.Run(Form{})RETURN

Dissecting the program#using The full name of any class takes the form <namespace>.<classname>. Sometimes it isconvenient, and quicker, just to use the class name and exclude the namespace name. Forexample, one class we are interested in here is System.Windows.Forms.Form. It is handy to beable to refer to it as just Form. However the compiler needs to have some way of working outthe full name of the Form class. That is where the #using directive helps out. The compiler willuse any namespaces named in the #using statements to help resolve class names that are notfully qualified.

[STAThread]The [STAThread] reference is actually connected to the following line by the semicolon, andso that part of the code could be written like this:

[STAThread] FUNCTION Start AS VOID

[STAThread] is an attribute - an attribute is a setting that applies to the following program item.Attributes are enclosed in square brackets. In our example the STAThread attribute applies tothe function Start. Using STAThread means that any COM interaction will use the Single-Threaded Apartment model. A number of Windows components make use of COM - the Folderdialog, as one example - and need the calling application to use the Single-ThreadedApartment model. It is for this reason the STAThread attribute is commonly included in GUI .NET applications.

FUNCTION Start() AS VOIDThe main code of all Vulcan applications commences in function Start.

Application.EnableVisualStyles()This method calls turns on support for the Visual Styles provided by Windows. Visual Styles arethe graphically-rich display features introduced with Windows XP.

Page 85: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

85Part IV: The .NET Way

Paul Piko, 2010

Application.Run(Form1{})This line instantiates a Form object and passes it to the Application.Run method. Application.Run starts running a standard Windows message loop and displays the form passed to it.

When you need to explicitly show a window you can do it in two ways: call the Show methodor call the ShowDialog method. Show displays the window modelessly (i.e. execution of theapplication continues and is not halted by the Show). ShowDialog displays the window as amodal dialog; code following the ShowDialog is not executed until the window is closed.

7.3.2 WinForm Elements Cross Reference

The following table shows many of the classes commonly used in creating windows in VisualObjects. The name of the corresponding .NET class is shown. There are a few VO classes thathave no direct .NET version. But there are many new controls in .NET with more options thatprovided in VO.

Visual Objects Class Equivalent .NET Class

PushButton Button

CheckBox CheckBox

RadioButton RadioButton

SingleLineEdit TextBox

MultiLineEdit TextBox

ListBox ListBox

ComboBox ComboBox

VerticalScrollBar VScrollBar

HorizontalScrollBar HScrollBar

GroupBox GroupBox

FixedText Label

FixedIcon PictureBox

FixedBitmap PictureBox

ProgressBar ProgressBar

HorizontalSlider TrackBar

VerticalSlider TrackBar

VerticalSpinner see NumericUpDown, DomainUpDown

HorizontalSpinner

TabControl TabControl

ListView ListView

TreeView TreeView

RichEdit RichTextBox

AnimationControl

HotKeyEdit

DateTimePicker DateTimePicker

MonthCalendar MonthCalendar

IPAddress

DataListView

RadioButtonGroup RadioButtonGroup

SysLink LinkLabel

In addition to the controls there are some other visual elements used in Window design and

Page 86: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

86 Vulcan.NET at Warp Speed

Paul Piko, 2010

require a different approach in .NET:

· VO Sub-Data Window - use a subclass of UserControl

· DataWindow - see following sections on Data Forms and DataGridView

· VO SplitWindow - use SplitContainer control

· VO StatusBar - use StatusStrip

· VO Toobar - use ToolStrip

· VO Menu - use MenuStrip

· VO ToolTip - use ToolTip

· VO Pointer - use Pointer

The form designer in .NET doesn't just have controls that can be put on a form; you canassociate Components with a form. The additional components typically have little or no visualdisplay on the form but act as a helper to the form. The following list shows .NET controls thatare not available in VO and the form components:

Common ControlsCheckedListBoxDataGridViewMaskedTextBox

ContainersFlowLayoutPanelPanelTableLayoutPanel

Menus and ToolsbarsContextMenuStripToolStripContainer

General ControlsPropertyGridSplitContainerWebBrowser

DataDataSetBindingNavigatorBindingSourceReportViewer

ComponentsBackgroundWorkerDirectoryEntryDirectorySearcherErrorProviderEventLogFileSystemWatcherHelpProviderImageListMessageQueue

Page 87: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

87Part IV: The .NET Way

Paul Piko, 2010

PerformanceCounterProcessSerialPortServiceControllerTimer

PrintingPagSetupDialogPrintDialogPrintDocumentPrintPreviewControlPrintPreviewDialog

DialogsColorDialogFolderBrowserDialogFontDialogNotifyIconOpenFileDialogSaveFileDialog

Some notes about the new elements

CheckedListBox shows a list of items with a checkbox beside each. It allows either just oneitem to be checked or multiple items.

MaskedTextBox is similar to a SingleLineEdit with a picture template controlling what can beentered and how it is displayed. There is a choice from a number of predefined masks or acustom mask may be used.

NumericUpDown is like a combination of a SingleLineEdit and a VerticalSpinner in the onecontrol.

The Panel control is a container holding other controls and is used to group togethercomponents that have some logical relationship.

The SplitPanel control creates two Panel controls, and has a splitter bar to adjust the size.

The FlowLayoutPanel adjusts the postions the controls it contains. By default they fill the spacewithin the panel going from left to right and top to bottom. This is like the display on a webpage.

The TableLayoutPanel positions controls as if they were cells in a table.

BackgroundWorker simplifies the creation and use of threads. To use it the code to be run in athread is put into an event handler attached to the DoWork event. The RunWorkerAsyncmethod is then used to execute the code and your main application can monitor it via theProgressChanged and RunWorkerCompleted events.

Page 88: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

88 Vulcan.NET at Warp Speed

Paul Piko, 2010

7.3.3 Simple Data Display

Our first example of displaying data in a Windows form makes use of a DataGridView control,with data obtained from a DBF file. In summary what we need to do is:

· Create a subclass of Form and define some instance fields to hold a push button, theDataGridView control and a DataSet object. The DataSet is needed by the DataGridView todisplay the data.

· Create a method of the form that executes when the push button is pressed. The methodcreates a DataSet by reading the DBF and then assigns the DataSet to the DataGridView.

Here is the class declaration and the constructor below. After controls are created they areattached to the form by calling the Add method of the Controls collection.

CLASS DataFormDB INHERIT FormPROTECT loadButton AS ButtonPROTECT tableGrid AS DataGridView

PROTECT dataset AS DataSet

CONSTRUCTOR()SUPER()

// Set up the window and controlsSELF:TEXT := "DataGridView Test"SELF:Size := Size{600,350}

loadButton := Button{}loadButton:Location := Point{10,10}loadButton:TEXT := "Load"

tableGrid := DataGridView{}tableGrid:Location := Point{10,50}tableGrid:Size := Size{570,250}

SELF:Controls:Add(loadButton)SELF:Controls:Add(tableGrid)

loadButton:Click += EventHandler{SELF,@OnLoadButton()}

This last line does not really have a direct equivalent in Visual Objects. In .NET the Button classhas an event called Click. Code can be attached to the click event by assigning an EventHandler. The += is used to assign the handler. It is possible, although uncommon, to add morethan one handler to an event. When the user clicks the button the Click event is fired and anyattached Event Handlers are called.

So when the Load button is clicked the OnLoadButton method is called. The OnLoadButtonmethod does two things. The first is create the dataset by calling the CreateDataSet method;the second is assign the dataset to the DataGridView:

METHOD OnLoadButton(sender AS OBJECT, e AS EventArgs) AS VOID

// Create a dataset that the grid will use as its source// and pass the name of the DBF to loadSELF:CreateDataSet("customer.dbf")

// The grid gets its data from the dataset table// The name here needs to match the name used to create the tabletableGrid:DataSource := dataset:Tables["MyDBF"]

RETURN

Page 89: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

89Part IV: The .NET Way

Paul Piko, 2010

By default, Vulcan will produce a warning message ifthe parameters to a method/function are not used.You can turn off this warning: at the project level usethe /w switch in the project properties (/w3009-), or incode use the #pragma warnings directive. Use#pragma warnings(3009,off) to disable the warning, #pragma warnings (3009,on) to re-enable it.

The core work of this sample is done by the CreateDataSet method. It instantiates theDataSet, and adds a DataTable to it. It then goes through the fields of the DBF and creates aDataColumn in the DataTable for each one. Once the columns are set up the method goesthrough each record in the DBF, adds a row to the DataTable and fills in the column values:

METHOD CreateDataSet(dbfName AS STRING) AS VOIDLOCAL datatable AS DataTableLOCAL row AS DataRowLOCAL i AS DWORD

// Create the datasetdataset := DataSet{}

// Create a table, give it any name you likedatatable := DataTable{"MyDBF"}

// Add the table to the datasetdataset:Tables:Add(datatable)

// Open the DBFDBUseArea(TRUE,"DBFCDX",dbfName)

// Make some columns for the table from each column in the DBFFOR i := 1 UPTO FCount()

datatable:Columns:Add( DataColumn{ FIELDNAME(i) } )NEXT

// Now load with dataDO WHILE ! EOF()

// Create a new rowrow := datatable:NewRow()

// Put data into the columns in the rowFOR i := 1 UPTO FCount()

row[ FIELDNAME(i) ] := AsString(FieldGet(i))NEXT

// Add the row to the tabledatatable:Rows:Add(row)

// Move to next recordDBSkip()

ENDDO

DBCloseArea()

RETURN

Once the DataSet is assigned to the DataGridView's DataSource property the display of thedata is completely handled by the control and nothing further is needed.

Page 90: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

90 Vulcan.NET at Warp Speed

Paul Piko, 2010

It is possible to create a version of this sample thatuses a DataTable without assigning it to a DataSet.However DataSet allows you to manipulate multipleDataTables and gives you the ability to create relationsbetween them. There is an example showing thisscenario later in this section.

7.3.4 Changing The View

Our previous example displayed the complete contents of a DBF. If we want to show only asubset of the records in the DBF, or show them in a particular sequence, there are twoapproaches we can take.

The first is to change the way the information is loaded into the DataTable. For example wecould include a condition when reading the DBF to skip records containing a certain value. Andto change the sequence the records appear we could open an index on the DBF and use thatas the controlling order. Using this approach we have to reload the data if we want to changethe subset or order.

.NET provides an alternative approach that lets you change filter and display order withoutreloading the data. The DataTable class has a DefaultView property which in turn hasproperties Sort and RowFilter. When a DataTable is attached to a DataGridView any changes tothe DefaultView's Sort and/or RowFilter properties are immediately reflected in the display.

These properties use SQL-like statements to specify the desired output. For example, tochange the display order to descending LastName the following code is used:

dataset:Tables["MyDBF"]:DefaultView:Sort := "LASTNAME desc"

Modifying our earlier sample and including this code in the method called by clicking the Sortbutton results in the following screen:

Page 91: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

91Part IV: The .NET Way

Paul Piko, 2010

Note that the DataGridView has automatically shown that a sort is applied by placing a downarrow icon in the LASTNAME column header.

To restrict the display of records to only those that have a State of CA the RowFilter is set asfollows:

dataset:Tables["MyDBF"]:DefaultView:RowFilter := "STATE = 'CA'"

When the Filter button is pressed only the records with a State of CA (the rightmost visiblecolumn below) are displayed:

Page 92: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

92 Vulcan.NET at Warp Speed

Paul Piko, 2010

To clear the sort and filter you just need to assign an empty string to the properties:

dataset:Tables["MyDBF"]:DefaultView:Sort := ""dataset:Tables["MyDBF"]:DefaultView:RowFilter := ""

And our display of data is returned to the original display:

If you want to control the views of multiple tables in aDataSet you should look the the DataViewManagerclass. This class holds a collection of DataViewSettingobjects, one for each table.

7.3.5 Validation

Validating and ValidatedThe .NET framework provides a number of places where you can check and verify the qualityof the data that you collect from your users. Controls such as TextBox have a CausesValidationproperty. When CausesValidition is set to TRUE, a Validating event is fired when there is anattempt to change focus to another control that has CausesValidation set to TRUE. You cancheck the contents of the control in the Validating event and decide whether you want toallow the change of focus or not. The name of the method that is executed when theValidating event is fired is specified by assigning an event handler. The following code causesthe textBox1_Validating method of the current form to be executed when the Validatingevent occurs for the control textBox1:

#using System.ComponentModelCLASS Form1 INHERIT System.Windows.Forms.Form...SELF:textBox1:Validating += CancelEventHandler{ SELF, @textBox1_Validating() }

Page 93: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

93Part IV: The .NET Way

Paul Piko, 2010

We can then write our method to handle the event:

PRIVATE METHOD textBox1_Validating( sender AS OBJECT, e AS CancelEventArgs ) AS VOID IF EMPTY(SELF:textBox1:Text) System.Windows.Forms.MessageBox.Show("Please enter something") e:Cancel := TRUE ENDIF RETURN

This method checks the contents of the TextBox and, if it does not contain any text, displays aMessageBox. It also sets the Cancel property of the event arguments that were passed in toTRUE. The event arguments are checked by the framework after the method call and whenCancel is set to TRUE further processing of the event is halted.

If the Validating event is passed successfully a Validated event can be fired for the control,giving you the opportunity to perform some action when "good" data is entered.

Controls normally have CausesValidation set to TRUE. To give the users a way to abort dataentry on a form it is usual to have a Cancel button, on which you would set theCausesValidation to FALSE, otherwise they would not be able to click on it if the data did notpass the validations.

Error ProviderThe .NET framework also gives a new way to display error messages to the user: using theErrorProvider component. ErrorProvider displays an icon next to the offending control anddisplays the error message as a tooltip:

You can add an ErrorProvider on to your form in Visual Studio by dropping it from the Toolbox:

Page 94: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

94 Vulcan.NET at Warp Speed

Paul Piko, 2010

The ErrorProvider can then be used from your validation code by calling the SetError methodand passing the control and an error message:

PRIVATE METHOD textBox1_Validating( sender AS OBJECT, e AS CancelEventArgs ) AS VOID LOCAL error AS STRING IF EMPTY(SELF:textBox1:Text) error := "Please enter something" e:Cancel := TRUE ENDIF SELF:errorProvider1:SetError(SELF:textBox1,error) RETURN

Form ValidationThe Validating event discussed above fires when the user attempts to move from a control. Inorder to check if all controls on a form are valid the form has a Validate method. The formValidate method triggers the Validating event for each control on the form. Container controls,such as SplitContainer, also have a Validate method that can be used to validate just thecontrols within the container.

You can also validate just a subset of the controls on a form by using the ValidateChildrenmethod. ValidateChildren has options to validate just the visible controls, or only those that are

Page 95: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

95Part IV: The .NET Way

Paul Piko, 2010

enable, or other subsets.

Sometimes you might not want the Validating and Validated methods of the controls to triggeras the user moves from control to control but only when the OK button of the form is pressed.You can do this by setting the form's AutoValidate property. This property's default value isAutoValidate.EnablePreventFocusChange, which stops focus changing if validation fails.AutoValidate.Disable stops the validation except in response to an explicit call to the formValidate or ValidateChildren. AutoValidate.EnableAllowFocusChange will still fire the controlvalidation but will let focus change to another control.

7.3.6 Setting Up More Test Data

In this section we will see two examples of creating simple applications that display some data.The first example will be coded by hand, with each step explained. The second example usesthe point-and-click features of Visual Studio to create an application with very little coding.

The first thing we need for our more advanced data applications is a source of data. DBF filesdo not contain enough metadata to be able to show some of the more involved data handlingfeatures of .NET so a "smarter" database is required. For our examples here we will use MS-Access since it provides some database management features but is not as complex as a fully-fledged database such as SQL Server, Oracle or MySQL.

Creating the databaseTo understand the data we will be working with, we will step the the processes to create ourdatabase. The final database is provided with this guide so you do not need to carry out thesesteps yourself, but they are presented here for your reference.

First we use MS-Access to create a new blank database by selecting File, New from the mainmenu. In the following dialog below was have given our database the name GettingStarted.mdb:

Page 96: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

96 Vulcan.NET at Warp Speed

Paul Piko, 2010

Next we import data from the original Visual Objects Getting Started Tutorial. This is done byselecting the Import option that is found under the Get External Data entry in Access' Filemenu. Initially the Import dialog shows Access related data sources:

When we change the "Files of type" combobox to "dBASE III (*.dbf)" and navigate to the VOsamples directory we can see the files we want to import:

Page 97: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

97Part IV: The .NET Way

Paul Piko, 2010

Each of the files can be imported by selecting the file name and then clicking the Importbutton. As a result we end up with three tables in our database:

We need to make some structural changes to take advantage of some of the .NET datahandling features - the most important thing to do is to explicitly mark which columns of thetables make up the primary keys. This is done by opening each table in design view,highlighting the primary key columns and selecting Primary key from the context menu. Whenthe primary key has been set a key icon is shown next to the specified columns:

Page 98: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

98 Vulcan.NET at Warp Speed

Paul Piko, 2010

The primary key of the customer table is CUSTNUM. The primary key of the orders table isCUSTNUM+ORDERNUM. The primary key of the detail table is ORDERNUM+LINENUM.

Now that we have a database, the following sections will show how Vulcan can make use of it.

7.3.7 Data Handling Basics

The .NET framework contains many classes for data handling which are found in the assemblycalled System.Data. Within System.Data is a collection of classes for using OLEDB datasources; that collection is the namespace System.Data.OleDB (remember from earlier in thisguide that a namespace is just a logical grouping of classes).

We can set up a connection to our database by using the class called OleDbConnection. Datacan be retrieved and manipulated through the OleDbDataAdapter class; in general aDataAdapter is a wrapper around the commands used to query and update a data source.

So the simplest code we can write to connect to the database is this:

#using System.Data#using System.Data.OleDB

FUNCTION Start() AS VOIDLOCAL connectString AS STRINGLOCAL commandString AS STRINGLOCAL connection AS OleDbConnectionLOCAL dataAdapter AS OleDbDataAdapter

Page 99: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

99Part IV: The .NET Way

Paul Piko, 2010

connectString := "provider=Microsoft.JET.OLEDB.4.0; data source=GettingStarted.mdb"connection := OleDbConnection{connectString}

commandString := "SELECT * from customer"dataAdapter := OleDbDataAdapter{commandString,connection}? dataAdapter

RETURN

This code is limited in its usefulness but does show how the connection is made. Note that the#using directives have let us refer to classes using their short names - instead of writingSystem.Data.OleDb.OleDbDataAdapter we were able to write just OleDbDataAdapter.

There is no Close method for dataAdapter. Any clean up that is required is triggered by thegarbage collector. When the object reference goes out of scope and the garbage collectorprocesses the object, the object's finalizer method is called and that in turn calls the Disposemethod.

The command line to compile the program above is just this:

vulcan data1

By default, Vulcan includes references to commonly used assemblies when it compiles.System.Data.dll is one of those common assemblies, and the rest can be found in the Vulcan.rsp file in the Vulcan BIN folder. If a needed assembly is not in the list then the /r compileswitch has to be used.

The next step in handling our data is a concept called DataSet. A DataSet is a copy of data inlocal memory - rows of data are not held permanently but are disconnected from the sourceuntil an update is required. So a DataSet represents our local collection of data. It contains acollection of tables which in turn contain the rows and columns of data. The previous examplecan be extended by including a dataset, and using OleDbDataAdapter's Fill method to copy thedata into the dataset. Our next sample puts two tables into the dataset: customer and orders.We then print out the names of the tables but we need to be careful because collections, suchas the tables collection, are zero-based.

Collections in .NET are zero-based.

#using System.Data#using System.Data.OleDB

FUNCTION Start() AS VOIDLOCAL connectString AS STRINGLOCAL commandString AS STRINGLOCAL connection AS OleDbConnectionLOCAL dataAdapter AS OleDbDataAdapterLOCAL dataSet AS DataSetLOCAL i AS INT

connectString := "provider=Microsoft.JET.OLEDB.4.0; data source=GettingStarted.mdb"connection := OleDbConnection{connectString}

dataSet := DataSet{}

commandString := "SELECT * from customer"dataAdapter := OleDbDataAdapter{commandString,connection}

Page 100: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

100 Vulcan.NET at Warp Speed

Paul Piko, 2010

dataAdapter:Fill(dataSet,"customer")

commandString := "SELECT * from orders"dataAdapter := OleDbDataAdapter{commandString,connection}dataAdapter:Fill(dataSet,"orders")

? dataSet:Tables:CountFOR i := 1 UPTO dataSet:Tables:Count

? dataSet:Tables[i-1]NEXT

RETURN

Now we are finally in a position to see some data from the tables. Each DataTable in theDataSet contains DataRows. The following lines can be inserted after the dataset has beenfilled and they will list out the contents of the custnum and ordernum columns:

dataTable := dataSet:Tables["orders"]FOR i := 1 UPTO dataTable:Rows:Count

dataRow := dataTable:Rows[i-1]? i,dataRow["custnum"],dataRow["ordernum"]

NEXT

In this case notice that we have been able to use names such as "orders", "custnum" and"ordernum" to retrieve the appropriate values from the collections; you are not limited toaccessing elements of a collection by number.

7.3.8 Hand-Coded Data Form

Creating a Data Handling WinFormThe following sample code shows the skeleton of our WinForm application that will displaydata:

#using System#using System.Windows.Forms#using System.Drawing

[STAThread];FUNCTION Start() AS VOID

Application.EnableVisualStyles()Application.Run(DataForm{})RETURN

CLASS DataForm INHERIT FormPROTECT loadButton AS ButtonPROTECT tableGrid AS DataGridView

CONSTRUCTOR()SUPER()

SELF:TEXT := "Data Form"SELF:Size := Size{600,350}

loadButton := Button{}loadButton:Location := Point{10,10}loadButton:TEXT := "Load"

tableGrid := DataGridView{}tableGrid:Location := Point{10,50}tableGrid:Size := Size{570,250}

SELF:Controls:Add(loadButton)

Page 101: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

101Part IV: The .NET Way

Paul Piko, 2010

SELF:Controls:Add(tableGrid)

END CLASS

There are several key things to observe in this sample code –1. we have subclassed the .NET Form class2. created two fields in the class called loadButton and tableGrid3. initialised the controls and form in the CONSTRUCTOR

The Start function creates an instance of the form and begins the execution by callingApplication.Run. The running form looks like this:

The Load button is the next thing we need to address. We can make some code executewhen a button is pressed by attaching an event handler to the Click event of the button (seethe section on Delegates and Events more information about event handling):

loadButton:Click += EventHandler{SELF,@OnLoadButton()}

This code will result in the OnLoadButton method being executed when the button is clicked.The event handler method is passed two arguments when it is called: a reference to thesending object and an EventArgs object that contains information about the event thatoccurred. Here is the stub of a method that we can use for the click of the Load button:

METHOD OnLoadButton(sender AS OBJECT, e AS EventArgs) AS VOIDRETURN

Inside the OnLoadButton method we need to connect to the database and fill ourDataGridView control with data. To support that operation we declare instance fields to holdsome of the values that might be useful in other methods. The fields should be familiar fromour earlier console examples above. This is the expanded class declaration:

CLASS DataForm INHERIT Form

Page 102: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

102 Vulcan.NET at Warp Speed

Paul Piko, 2010

PROTECT loadButton AS ButtonPROTECT tableGrid AS DataGridView

PROTECT connectString AS STRINGPROTECT connection AS OleDbConnection

PROTECT dataSet AS DataSetPROTECT dataAdapter AS OleDbDataAdapter

Now in the OnLoadButton method we can use the data handling techniques we saw earlier butinclude one extra twist; we assign a reference to our dataset table to the DataSource propertyof the DataGridView:

METHOD OnLoadButton(sender AS OBJECT, e AS EventArgs) AS VOID

connection := OleDbConnection{connectString}dataSet := DataSet{}

dataAdapter := OleDbDataAdapter{"select * from customer",connection}dataAdapter:Fill(dataSet,"customer")

tableGrid:DataSource := dataset:Tables["customer"]

RETURN

When the Load button is clicked, the event handler triggers the OnLoadButton method. Thisthen connects to the database, fills a dataset and passes the reference to the loaded table tothe DataGridView control. The resulting window follows:

The DataGridView supports editing of the attached data. The follow image shows theFirstName field of the first row being edited. Notice the pen icon in the leftmost column andthe new FirstName: "Toddy".

Page 103: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

103Part IV: The .NET Way

Paul Piko, 2010

Editing the contents of the control changes the values within the DataSet but does not persistthe changes to disk. In order to do that you need to call the Update method of the dataadapter to write out the changes. There are several places that this can be done. We could usethe row changing events and save the data after each row change but we will keep thisexample simple and just save the data when the form is closed. Once again we need to add anevent handler to the form and specify the name of the method we want to execute:

SELF:FormClosed += FormClosedEventHandler{ SELF, @DataForm_FormClosed() }

The DataForm_FormClosed method needs to setup the DataAdapter so that it can generatethe SQL statements to update the database by calling OleDbCommandBuilder. Once theadapter is correctly set the Update method can be called to save the table changes:

METHOD DataForm_FormClosed( sender AS OBJECT, e AS FormClosedEventArgs ) AS VOIDIF ! dataAdapter == NULL

OleDbCommandBuilder{dataAdapter}dataAdapter:Update(dataSet,"customer")

ENDIFRETURN

More About DataGridViewThe appearance and operation of DataGridView can be highly customised. The control'sProperties window in Visual Studio shows many of the features:

Page 104: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

104 Vulcan.NET at Warp Speed

Paul Piko, 2010

The sample program DataForm2.prg makes use of the DataGridView's CellPainting event tochange the way the cells are drawn and produces the following window:

Page 105: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

105Part IV: The .NET Way

Paul Piko, 2010

The code to assign an event handler to the CellPainting event is shown below. When theCellPainting even occurs the method tableGrid_CellPaint is called and it is passed aDataGridViewCellPaintingEvent object, containing details about the event.

tableGrid:CellPainting += DataGridViewCellPaintingEventHandler{ SELF, @tableGrid_CellPaint() }

Here is the method that handles the event:

METHOD tableGrid_CellPaint( sender AS OBJECT, e AS DataGridViewCellPaintingEventArgs ) AS VOID LOCAL rect AS Rectangle LOCAL lgb AS LinearGradientBrush

IF ! tableGrid:DataSource == NULL IF e:RowIndex >= 0 .and. ; ! _and(e:State,DataGridViewElementStates.Selected) == DataGridViewElementStates.Selected

IF e:ColumnIndex >= 0 IF e:RowIndex % 2 == 0 rect := e:CellBounds e:PaintBackground(rect,TRUE)

lgb := LinearGradientBrush{rect, Color.Red, Color.LightBlue, 0}

e:Graphics:FillRectangle(lgb, rect) e:PaintContent(e:CellBounds) e:handled := TRUE lgb:Dispose()

ENDIF ENDIF

ENDIF ENDIF

RETURN

Note that a RowIndex of -1 represents the grid's header row, and a ColumnIndex of -1 is theleftmost, non-data column that usually contains status icons such as the row pointer. Theevent's State can contain multiple values and the code above uses _and() to determine if the

Page 106: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

106 Vulcan.NET at Warp Speed

Paul Piko, 2010

Selected state is set.

Binding Other Controls

Controls other than the DataGridView can be bound to data in a different way. Most use theproperty called DataBindings which is a collections of Binding objects. A Binding objectrepresents a link between a property of an object with a property of another object. For databinding with a TextBox control we want to bind the control's Text property to a data propertyin a data source. As an example the following code binds the Text property of a TextBoxobject textBox1 to the customer.lastname propery of the dataSet.

textBox1:DataBindings:Add("Text",dataSet,"customer.lastname")

With some controls we need to bind with the control's Value property:

dateTimePicker1:DataBindings:Add("Value",dataSet,"orders.ship_date")

These examples had used the Add method of the DataBindings collection which automaticallycreates a Binding object. You can explicitly create the Bindings object yourself if you want toset some of the other properties such as FormatString.

7.3.9 Data Form Using The Form Designer

The Windows Form created in this section has more features than the one from the previoussection because it is much easier to build a complex form using the visual tools than it is towrite the code by hand. This section introduces the BindingSource and BindingNavigatorclasses that first became available in version 2 of the .NET Framework.

Adding a DataSetThe first step is to create a new Vulcan Windows application. In the example here the solutionis called DataForm3 and it contains one project, also called DataForm3. Once you have the formdesigner in front of you, take a look at the Toolbox window (if it is not currently open you canaccess it from the View menu). Scroll through the tools until you come to the Data section. Ifnecessary, expand the section by clicking on the small icon to the left of the word Data in thesection header.

Page 107: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

107Part IV: The .NET Way

Paul Piko, 2010

To add a DataSet to the form click on the DataSet tool and drag it on to the form. As yourelease the mouse over the form an Add Dataset dialog is shown:

There are two options on this dialog. The first, Typed dataset, allows more efficient coding andchecking by the compiler but takes more work to setup. Typically, Typed datasets areproduced by using the Data Designer, another of the visual tools in Visual Studio. An exampleof using a Typed dataset is provided later in this guide. The second option, Untyped dataset, is

Page 108: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

108 Vulcan.NET at Warp Speed

Paul Piko, 2010

the one we will use for the example here. When selected the form's class declaration ischanged to include a new instance field whose type is System.Data.DataSet.

Once the Add DataSet dialog has been actioned the Visual Studio form designer windowchanges, showing the newly added component in a panel below the form:

Note that the designer has allocated a name for the dataset; in this case it is dataSet1 and thecode generated for the class declaration looks like this:

CLASS Form1 INHERIT System.Windows.Forms.Form PRIVATE INSTANCE dataSet1 AS System.Data.DataSet PRIVATE INSTANCE components AS System.ComponentModel.IContainer

At this stage it is worth checking the Reference section of the project. At the time of writingthere was an issue that sometimes an extraneous entry was add to the References list andwould cause subsequent error messages and prevent the designer from opening again later. Ifthe Solution Explorer is not open you can get to it from the View menu. Our solution containsone project, DataForm3. Beneath the entry for the project is the References section. Thething to look for is an entry named System.Data.dll with a warning icon next to it:

Page 109: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

109Part IV: The .NET Way

Paul Piko, 2010

The fix for this problem is simple: right click on the System.Data.dll entry and choose Removefrom the context menu.

This problem should only occur once after adding a dataset. It does not necessarily appearimmediately but may occur when the generated code is manually changed or when theproject is closed and reopened.

Adding a BindingSourceThe next component to add to the form is a BindingSource. The BindingSource acts as a proxybetween the bound controls and the data thus providing a consistent way of accessing datafrom the controls. Rather than adjusting all the controls code for different data sources, thechanges can be handled within the BindingSource, providing a way to keep the form's code atarms length from the data. The BindingSource also provides a set of data handling events thatcan be utilised.

Dragging the BindingSource from the toolbox and dropping it on the form once again resultsin an instance field being added to the class and the component is shown by the designer inthe area below the form. The connection between the BindingSource and the DataSet will beshown a little later, when we put in the code to access the database.

Adding a BindingNavigatorThe BindingNavigator is a handy control that can team up with a BindingSource and give theuser a pleasant visual way to move through the data. When a BindingNavigator is dragged fromthe toolbox and dropped on the form the control is by default immediately shown docked tothe top of the form:

Page 110: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

110 Vulcan.NET at Warp Speed

Paul Piko, 2010

The default BindingNavigator contains:

· buttons for moving through the data,

· the number of the current row where you can manually enter the row you want to navigateto

· a display of the total number of rows

· buttons to add and delete rows

While we are looking at the BindingNavigator, note that in the form designer, many of thecontrols have an additional property window that can be displayed by clicking on the smallarrow that appears on the border when the control is selected:

Page 111: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

111Part IV: The .NET Way

Paul Piko, 2010

You can see from the previous image that the extra property window gives options controllingthe appearance and position of the control, as well as the ability to add extra Standard buttons- such as copy, paste, print etc.

At this point we will connect the BindingNavigator to the BindingSource. In the propertieswindow of the control scroll through and find the entry called BindingSource. When you clickin the field next to that heading a combobox will appear, and in it is the name of theBindingSource field, bindingSource1. Select the name and the connection will be madebetween the navigator and the source.

Adding a DataGridViewThe last tool to drop on the form is the DataGridView. In the next image the grid has beenpositioned and resized to take up most of the form. The Dock property, found in the Layoutsection of the grid's properties, has also been set to Fill so that as the form is resized the gridwill also expand or contract to use all the space within the form. When you click on thecombobox next to Dock, a small graphical display is shown, allowing you to select the dockingstyle. The central panel represents the Fill docking style, and the panels around it representoptions to dock to each of the borders:

Page 112: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

112 Vulcan.NET at Warp Speed

Paul Piko, 2010

As you can see from the properties window it is possible to configure the features that theuser has access to, such as adding, editing and deleting. From here it is also possible to controlthe columns that are displayed however for our example we will use the automatic features ofthe grid, just as the browse in Visual Objects can be set to automatic. The thing we do want toset at this time is the link between the grid and the BindingSource. This is done by selectingthe instance field name, bindingSource1, from the combobox in the Data Source entry:

Page 113: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

113Part IV: The .NET Way

Paul Piko, 2010

Bringing it togetherNow is the time to write a little code. The first thing to check is the generated code of theform. Select Code from the View menu and see if the class declaration contains the keywordPARTIAL. If it is not there then add it in. Using the PARTIAL keyword tells the compiler that thecode for this class is not just in this one PRG. The code should look like this:

PARTIAL CLASS Form1 INHERIT System.Windows.Forms.Form PRIVATE INSTANCE dataSet1 AS System.Data.DataSet PRIVATE INSTANCE bindingSource1 AS System.Windows.Forms.BindingSource PRIVATE INSTANCE bindingNavigator1 AS System.Windows.Forms.BindingNavigator PRIVATE INSTANCE bindingNavigatorAddNewItem AS System.Windows.Forms.ToolStripButton PRIVATE INSTANCE bindingNavigatorCountItem AS System.Windows.Forms.ToolStripLabel PRIVATE INSTANCE bindingNavigatorDeleteItem AS System.Windows.Forms.ToolStripButton PRIVATE INSTANCE bindingNavigatorMoveFirstItem AS System.Windows.Forms.ToolStripButton PRIVATE INSTANCE bindingNavigatorMovePreviousItem AS System.Windows.Forms.ToolStripButton PRIVATE INSTANCE bindingNavigatorSeparator AS System.Windows.Forms.ToolStripSeparator PRIVATE INSTANCE bindingNavigatorPositionItem AS System.Windows.Forms.ToolStripTextBox PRIVATE INSTANCE bindingNavigatorSeparator1 AS System.Windows.Forms.ToolStripSeparator PRIVATE INSTANCE bindingNavigatorMoveNextItem AS System.Windows.Forms.ToolStripButton PRIVATE INSTANCE bindingNavigatorMoveLastItem AS System.Windows.Forms.ToolStripButton PRIVATE INSTANCE bindingNavigatorSeparator2 AS System.Windows.Forms.ToolStripSeparator PRIVATE INSTANCE components AS System.ComponentModel.IContainer

Now we can add another PRG containing members of this class and Vulcan will merge them alltogether when it compiles the code.

Page 114: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

114 Vulcan.NET at Warp Speed

Paul Piko, 2010

Right click on the project name and choose Add, New Item from the menu. A dialog appearsshowing the items that can be added to the project:

Since we want to add some additional code for the existing class select the Code File template,enter a name of Form1 Extra.prg and click Add. This creates the file and opens it in the codeeditor.

The extra code that needs to be added to the class is a method to open the connection to thedatabase and link the data to the BindingSource. Here is the code that is put into Form1 Extra.prg, and is described in more detail below:

#using System.Data#using System.Data.OleDB#using System.Windows.Forms

PARTIAL CLASS Form1 PROTECT connectString AS STRING PROTECT connection AS OleDbConnection PROTECT dataAdapter AS OleDbDataAdapter

METHOD Configure() AS VOID SELF:FormClosed += FormClosedEventHandler{ SELF, @DataForm_FormClosed() }

connectString := "provider=Microsoft.JET.OLEDB.4.0; data source=GettingStarted.mdb" connection := OleDbConnection{connectString}

dataSet1 := DataSet{}

dataAdapter := OleDbDataAdapter{"select * from customer",connection} dataAdapter:Fill(dataSet1,"customer") SELF:dataGridView1:AutoGenerateColumns := TRUE

SELF:bindingSource1:DataSource := SELF:dataSet1 SELF:bindingSource1:DataMember := "customer"

Page 115: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

115Part IV: The .NET Way

Paul Piko, 2010

RETURN

METHOD DataForm_FormClosed( sender AS OBJECT, e AS FormClosedEventArgs ) AS VOID IF ! dataAdapter == NULL OleDbCommandBuilder{dataAdapter} dataAdapter:Update(dataSet1,"customer") ENDIF RETURN END CLASS

Since the code will be making use of classes from the System.Data, System.Data.OleDb andSystem.Windows.Forms namespaces the code starts out with three #using directives, lettingus use the short names for the classes (without the namespace prefix).

The next thing is the class declaration. The PARTIAL keyword tells Vulcan to look for parts ofthis class in separate files; Vulcan merges all the components of the class from the separatefiles before compiling it. This means it is possible to have instance fields of the class declared inseparate files and in this example we add three fields called connectString, connection anddataAdapter which are then combined with the other fields in the designer generated code.Note that the INHERIT clause was also omitted from the declaration in this file. While notnecessarily recommended practice, it shows that Vulcan will handle it, because the INHERITclause is already part of the designer generated code. If you try to INHERIT from a differentclass here, or re-declare a field, Vulcan produces an error message.

The first thing the Configure method does is assign an EventHandler for the FormClosed event,making sure the DataForm_FormClosed method is run when the window is closed.

The rest of the Configure method should look familiar from the earlier data handling examples.There are two new things in this method. The first is the setting of the DataGridView'sAutoGenerateColumns property to TRUE. This gives us the lazy way to show the data in thegrid by letting it work out the contents based on the connected data. The second new thing isthe assignment of the DataSet that we have prepared to the BindingSource's DataSourceproperty. And because a DataSet can contain multiple tables we also need to set theDataMember property of the BindingSource so that it knows what data to pick out of theDataSet.

The DataForm_FormClosed method calls the Update method of the DataAdapter so that anychanges made to the data in the window are written back to the database. Before the call tothe Update method you can see the instantiation of a OleDbCommandBuilder object. This isnecessary to register the OleDbCommandBuilder with the DataAdapter; it is theOleDbCommandBuilder that is used to generate the SQL statements that allow the changes inthe data to be written back to the database. If you leave out the OleDbCommandBuilderinstantiation, and have not explicitly assigned SQL commands to the DataAdapter, anexception will occur when the Update is attempted.

That is all we need to add to the Form1 class for now, leaving just some little changes neededto the Start function. The main change in the code below from the original Start function isthat the Form1 object is stored into a variable and then the Configure() method is called topopulate the grid:

FUNCTION Start( cmdLineArgs AS STRING[] ) AS INT LOCAL form AS Form1

Page 116: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

116 Vulcan.NET at Warp Speed

Paul Piko, 2010

LOCAL exitCode AS INT Application.EnableVisualStyles() Application.SetCompatibleTextRenderingDefault( FALSE )

form := Form1{} form:Configure() Application.Run( form ) RETURN exitCode

There is only one more thing to do before running this sample, and that is to make sure thedatabase actually exists in the location we have said it does. This code hasn't used any paths sothe program will expect the data in the current directory. Having built this project in thedefault Debug mode the executable is written to the Debug folder beneath the project folder.Before running this program make sure the GettingStart.mdb is in that folder, or change theconnection string passed to OleDbConnection to include the correct path.

Running the application gives us a resizable window with navigation controls at the top of it:

7.3.10 Master-Detail Form

For the moment we will return to a hand-coded example to concentrate on the next part ofour data form. In this section we will see how to display a master-detail relationship on a form.Our database has a customer table and an orders table and both have a CUSTNUM field. Whenwe set up the database we did not define any explicit relationships which you normally wouldwhen constructing a database. Because there is no relationship in the database we will need towrite some code to handle it. In the first part of this section we will show the master-detailrelationship using two grids. The completed form is shown below. Note that the lower

Page 117: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

117Part IV: The .NET Way

Paul Piko, 2010

DataGridView, containing the orders, is limited to showing only those that have a CUSTNUM of2 because the upper DataGridView has customer 2 selected:

To create this form the first thing we need to do is expand the one we created earlier:

CLASS DataForm INHERIT FormPROTECT loadButton AS ButtonPROTECT tableGridCustomer AS DataGridViewPROTECT tableGridOrder AS DataGridView

PROTECT connectString AS STRINGPROTECT connection AS OleDbConnection

PROTECT dataSet AS DataSetPROTECT dataAdapter AS OleDbDataAdapter

PROTECT bindingSourceCustomer AS BindingSourcePROTECT bindingSourceOrder AS BindingSource

This time we have two DataGridViews, one for the customer table and another for the orderstable. We also include a couple of BindingSources. As we saw in the previous section a

Page 118: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

118 Vulcan.NET at Warp Speed

Paul Piko, 2010

BindingSource provides an intermediary between the data and the controls on a form.

The CONSTRUCTOR of the form has some minor changes to handle the additionalDatGridView:

CONSTRUCTOR()SUPER()

SELF:TEXT := "Data Form"SELF:Size := Size{600,600}

loadButton := Button{}loadButton:Location := Point{10,10}loadButton:TEXT := "Load"

tableGridCustomer := DataGridView{}tableGridCustomer:Location := Point{10,50}tableGridCustomer:Size := Size{570,250}

tableGridOrder := DataGridView{}tableGridOrder:Location := Point{10,310}tableGridOrder:Size := Size{570,250}

SELF:Controls:Add(loadButton)SELF:Controls:Add(tableGridCustomer)SELF:Controls:Add(tableGridOrder)

loadButton:Click += EventHandler{SELF,@OnLoadButton()}SELF:FormClosed += FormClosedEventHandler{ SELF, @DataForm_FormClosed() }

connectString := "provider=Microsoft.JET.OLEDB.4.0; data source=GettingStarted.mdb"

The most important part of this example is the code that handles the click of the LoadButton.The first part of the OnLoadButton method is similar to that used in the previous examplehowever this time we add some lines to read the orders table into the dataset:

METHOD OnLoadButton(sender AS OBJECT, e AS EventArgs) AS VOID

connection := OleDbConnection{connectString}dataSet := DataSet{}

dataAdapter := OleDbDataAdapter{"select * from customer",connection}dataAdapter:Fill(dataSet,"customer")

dataAdapter := OleDbDataAdapter{"select * from orders",connection}dataAdapter:Fill(dataSet,"orders")

Now we need to set up a relationship between the two tables. We do that by adding to theRelations collection of the dataset. The following line adds a relation called CustomerToOrderand provides the linking fields in both the customer and orders tables:

dataSet:Relations:Add("CustomerToOrder",;dataSet:Tables["customer"]:Columns["CUSTNUM"],;dataSet:Tables["orders"]:Columns["CUSTNUM"])

Having set the relation we now need to set the data sources of the DataGridView controls. Inthe earlier hand-coded example we just assigned the dataset table to the grid's DataSource.This time we will use a BindingSource. To link the customer table to the BindingSource weneed to do two things: set the DataSource property to the dataSet and set the DataMemberproperty to the name of the table we want, "customer". Then we just need to assign theBindingSource to the grid's DataSource. The code looks like this:

Page 119: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

119Part IV: The .NET Way

Paul Piko, 2010

bindingSourceCustomer := BindingSource{}bindingSourceCustomer:DataSource := dataSetbindingSourceCustomer:DataMember := "customer"

tableGridCustomer:DataSource := bindingSourceCustomer

That takes care of the customer DataGridView, so now we turn to the orders DataGridView.Again we will use a BindingSource but this time we will construct it in a different way to takeinto account the relationship between the tables. The DataSource of the child table'sBindingSource is set to the parent BindingSource. So the DataSource of the ordersBindingSource is the customer BindingSource:

bindingSourceOrder := BindingSource{}bindingSourceOrder:DataSource := bindingSourceCustomer

And this time the DataMember is not the name of a table but the name of the relationship wecreated: CustomerToOrder:

bindingSourceOrder:DataMember := "CustomerToOrder"

Finally the configured BindingSource is set as the orders grid's DataSource:

tableGridOrder:DataSource := bindingSourceOrder

And that completes the code needed to produce the form shown at the start of this section.

More Traditional Master-Detail FormIn Visual Objects the more familiar layout for a master-detail form is to have a set of TextBoxesand controls showing the currently selected master record and displaying the detail within agrid. Here we will take the previous example and replace the customer grid with a fewcontrols, and add two buttons for navigation through the customer table. We will use two pushbuttons for the navigation since it will be simpler code than using a BindingNavigator.

Having removed the references to tableGridCustomer in our previous example there are just afew things to do:

Declare TextBoxes to show data from our master table, and our two "navigator" buttons

PROTECT custNum AS TextBoxPROTECT firstName AS TextBoxPROTECT lastName AS TextBox

PROTECT nextButton AS ButtonPROTECT previousButton AS Button

In the CONSTRUCTOR() these controls are initialised:

previousButton := Button{}previousButton:Location := Point{110,10}previousButton:TEXT := "Previous"

nextButton := Button{}nextButton:Location := Point{210,10}nextButton:TEXT := "Next"

custNum := TextBox{}

Page 120: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

120 Vulcan.NET at Warp Speed

Paul Piko, 2010

custNum:Location := Point{10,50}custNum:Size := Size{100,20}

firstName := TextBox{}firstName:Location := Point{10,80}firstName:Size := Size{100,20}

lastName := TextBox{}lastName:Location := Point{10,110}lastName:Size := Size{100,20}

And added to the Controls collection:

SELF:Controls:Add(previousButton)SELF:Controls:Add(nextButton)SELF:Controls:Add(custNum)SELF:Controls:Add(firstName)SELF:Controls:Add(lastName)

And event handlers are defined for the two buttons:

nextButton:Click += EventHandler{SELF,@OnNextButton()}previousButton:Click += EventHandler{SELF,@OnPreviousButton()}

Then in the OnLoadData methods we need to replace the assigning of the BindingSource tothe grid with data bindings to our TextBoxes. So this line:

tableGridCustomer:DataSource := bindingSourceCustomer

is replaced with these lines:

custNum:DataBindings:Add("Text",bindingSourceCustomer,"CUSTNUM")firstName:DataBindings:Add("Text",bindingSourceCustomer,"FIRSTNAME")lastName:DataBindings:Add("Text",bindingSourceCustomer,"LASTNAME")

The final thing that needs to be done is to write the methods handling the navigator buttonclicks:

METHOD OnNextButton(sender AS OBJECT, e AS EventArgs) AS VOIDbindingSourceCustomer:MoveNext()RETURN

METHOD OnPreviousButton(sender AS OBJECT, e AS EventArgs) AS VOIDbindingSourceCustomer:MovePrevious()RETURN

And so we end up with a more traditional looking - although not the prettiest - master-detailform shown below. When the Next and Previous buttons are pressed the customerBindingSource is moved, changing the data show in the TextBoxes and in the orders grid.

Page 121: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

121Part IV: The .NET Way

Paul Piko, 2010

7.3.11 Using Typed Datasets

Typed Datasets are usually generated using the Data Designer tool in Visual Studio. Whendatasets are typed they allow more efficient code and better checking by the compiler. Theyalso allow the visual tools such as the forms designer to provide more features because moredetail is available to it.

In this section we will create a typed dataset and use it on a form. You can compare the resultshere with the previous section that used an untyped dataset and see we have more controland options here, and tighter code generated.

At the time of writing this guide the Visual Studio Data Designer does not generate Vulcancode. That is not too much of a problem if we have a version of Visual Studio that includes C#or VB.NET because we do not want to change the generated code. We can use one of theother languages, either C# or VB.NET, to generate an assembly holding the typed dataset. Theassembly can be easily used in our Vulcan application as shown below.

Page 122: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

122 Vulcan.NET at Warp Speed

Paul Piko, 2010

To start we begin by creating a new Vulcan Windows application. Initially we leave thegenerated form untouched and go straight to the Solution Explorer, right click on the solutionname and select Add, New Project.

The Add New Project dialog is displayed. It doesn't matter which language we use to createthe typed dataset; in this example I have chosen to create a C# library, and called the newproject DataForm4Data:

We do not need to change the skeleton code that is create automatically by the New Projectwizard so the file Class1.cs can be removed immediately.

Next, make sure the project DataForm4Data is selected in the Solution Explorer and chooseData from the Visual Studio menu, and then Add New Data Source. The Data SourceConfiguration Wizard is displayed:

Page 123: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

123Part IV: The .NET Way

Paul Piko, 2010

Since we want to use the same database as our previous examples, make sure Database isselected in the dialog and click Next. The following page of the wizard is where the dataconnection details are specified:

Page 124: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

124 Vulcan.NET at Warp Speed

Paul Piko, 2010

Clicking on the New Connection button brings up the Add Connection dialog where we canBrowse for our database file:

Page 125: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

125Part IV: The .NET Way

Paul Piko, 2010

Clicking OK on the Add Connection dialog returns you to the data connection page of thewizard, and details of the specified connection are shown:

On clicking Next in the wizard, Visual Studio recognises that the database is a local file andpresents a prompt to add a link to the file into the project. If you choose to do this not only willfile appear in the project treeview but each time an application is run the file will be copied intothe output directory. This can sometimes be a useful feature but keep in mind that each testrun you start will have a new copy of the data file. When data you changed in a previous rundoes not appear, it is because the old data has been replaced with the new copy.

The next page of the wizard is an option to save the generated connection string into theapplication configuration file. The application configuration file contains XML and is called app.config. It is the alternative to storing settings in the registry or INI files.

Page 126: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

126 Vulcan.NET at Warp Speed

Paul Piko, 2010

Although we will not make direct use of the app.config in this section of the guide, thecontents of the file that is created for our connection is here:

<?xml version="1.0" encoding="utf-8" ?><configuration> <configSections> </configSections> <connectionStrings> <add name="DataForm4Data.Properties.Settings.GettingStartedConnectionString" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\GettingStarted.mdb"

providerName="System.Data.OleDb" /> </connectionStrings></configuration>

After the application configuration page comes a page where we can select which items wewant out of our database. In the following image we have chosen all of the tables. A defaultDataSet name has also been generated for us; you can change it if you like.

Page 127: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

127Part IV: The .NET Way

Paul Piko, 2010

When the Finish button is pressed the wizard generates the code for our typed dataset, andentries are added into the Solution Explorer for the files that are created:

Although we are not going to change any of the code for this example, if you double-click onthe GettingStartedDataSet.xsd entry in the Solution Explorer the Data Designer is started,

Page 128: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

128 Vulcan.NET at Warp Speed

Paul Piko, 2010

presenting our chosen database items in a visual format:

The Data Designer allows you to manipulate the properties of the dataset, create relations ifnecessary and even customise the SQL that is used to retrieve and save the data.

For our example we will keep the default settings so the Data Designer can be closed withoutmaking any changes.

To be able to use this assembly in our other project we need to build it. Right Click on theDataForm4Data project in Solution Explorer and select Build. When the build is successful, goto the original DataForm4 project, right click on References in the treeview and select AddReference from the menu. In the Add Reference dialog that appears select the Projects tab tosee a window like this:

Page 129: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

129Part IV: The .NET Way

Paul Piko, 2010

Select the DataForm4Data project and click OK. DataForm4Data will then appear in theReferences list of our Vulcan project. The Toolbox is also updated include items from ourassembly representing of dataset and its tables:

There is a quirk in Visual Studio that means that sometimes these items from the referenced

Page 130: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

130 Vulcan.NET at Warp Speed

Paul Piko, 2010

assembly disappear from the toolbox. The simplest way I have found to make them reappear isto delete the assembly from the References list, save and close the solution and reopen it. Ifyou then drop any of the assembly's tools onto a form the assembly will automatically beadded back into the References list. If you do not use any of the components on the form atthat time you will need to manually add the Reference back into the list.

For this example we drag and drop a GettingStartDateSet and a customerTableAdapter fromthe DataForm4Data section of the Toolbox and a BindingSource and a BindingNavigator fromthe Data section of the Toolbox:

We then select the bindingSource1 control and scroll through the Properties until we seeDataSource. Clicking on it brings up a window in which we can find the instance fieldgettingStartedDataSet1 that contains our dataset:

Page 131: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

131Part IV: The .NET Way

Paul Piko, 2010

Having selected the dataset we can set the DataMember property of the BindingSource; againa window is displayed, this time showing the members available in our dataset. For thisexample the customer member is selected.

Now that the data source portion has been set up we can drag and drop a DataGridView on tothe form. If you click on the arrow on the newly added control's border an extra propertywindow is displayed, from which the BindingSource for the control can be set. In our case theBindingSource should be the bindingSource1 component we configured earlier:

As soon as the BindingSource is set on the DataGridView the control immediately updates itsdisplay, showing the columns available in the BindingSource:

Page 132: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

132 Vulcan.NET at Warp Speed

Paul Piko, 2010

In the extra property window of the DataGridView, accessed by clicking in the small arrow onits border, there is an option to edit the columns. You can use this to customise theappearance of the control:

Page 133: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

133Part IV: The .NET Way

Paul Piko, 2010

Next we need to connect the BindingNavigator to the BindingSource. Select thebindingNavigator1 control on the form and find the BindingSource entry in the properties, setit to bindingSource1.

Finally we need to insert two lines of code to show and save the data; one line is for when theform is started, the other for when it is closed. Select the form itself in the form designer, go tothe Properties window and click the Events (lightning) button. Scroll through and find theFormClosed and Load entries. In the following image I have already created methods for theseevents by double clicking on them:

We need to insert one line into the method stub that is generated. The line calls the Fillmethod of the customerTableAdapter from our typed dataset. We fill the TableAdapter withdata from the customer member of the typed dataset:

PRIVATE METHOD Form1_Load( sender AS OBJECT, e AS System.EventArgs ) AS VOID SELF:customerTableAdapter1:Fill(SELF:gettingStartedDataSet1:customer) RETURN

Page 134: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

134 Vulcan.NET at Warp Speed

Paul Piko, 2010

Similarly we need a line to save any data changes in the Form1_FormClosed method:

PRIVATE METHOD Form1_FormClosed( sender AS OBJECT,; e AS System.Windows.Forms.FormClosedEventArgs ) AS VOID SELF:customerTableAdapter1:Update(SELF:gettingStartedDataSet1:customer) RETURN

Our finished form in this example looks like this:

Page 135: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

135Part IV: The .NET Way

Paul Piko, 2010

7.4 DebuggingThe debugger in .NET is very powerful. It handles multiple languages and can debuglocally or remotely. It has, of course, breakpoints, watch windows and call stacks, butis also has data visualisers and debugging hints. You can examine running threads,processes and memory. In this section we will look at some of the parts of thedebugger you will often use.

If you are not using Visual Studio you can debug using the stand-alone CLR Debugger,DBGCLR.EXE. It provides many features similar to the Visual Studio debugger and is primarilyused when programming from the command line. To start debugging a program usingDBGCLR select Debug, Program to Debug from the menu and then select the executable.

Using the DebuggerThe first thing to be able to use the debugger is to ensure that debugging is enabled whencompiling your code. When working from the command line that means compiling with the /debug switch. In Visual Studio, if you go to the project properties you will see a tabbed dialoglike the one below that has the Debug tab already selected:

Every project, by default, has two Configurations available: Debug and Release. Eachconfiguration is a group of customised settings. The Debug configuration has the "EmitDebugging Information" option set to True; in Release mode this setting is False. To allow useof the debugger this setting must be enabled, and the easiest way to do that for a project is toselect the Debug configuration when building.

The other place that contains settings that affect the way the debugger works is in the VisualStudio options accessed from the Tools menu:

Page 136: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

136 Vulcan.NET at Warp Speed

Paul Piko, 2010

These settings can be left at their default values until you find a need to change them.

If you have previously built your application in non-debug configuration and switch to debugconfiguration you should select Build, Rebuild Solution from the menu to ensure debugginginformation has been generated for your code. The debugging symbols that are created arestored in a file with a .pdb extension.

Starting the DebuggerThe Debug menu in Visual Studio looks like this:

If you select Start Debugging the application will start executing and continue until abreakpoint is found. Start Without Debugging runs the application, ignoring breakpoints. If youhave an application running already and want to debug you can use the Attach to Processoption to hook into the running application. To start debugging from the first line of code youshould choose Step Into.

Page 137: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

137Part IV: The .NET Way

Paul Piko, 2010

Another way to start the debugger is from a program that has triggered an exception. Onmachines with debugging services available the exception dialog contains a button called"Debug":

If you click Debug and you have multiple debugging engines available you see a list of then inthe Just-In-Time debugger dialog, where you can select the most appropriate engine toprocess the exception:

Selecting one of the debuggers and clicking Yes then commences the debugging process on

Page 138: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

138 Vulcan.NET at Warp Speed

Paul Piko, 2010

the exception:

We will take a closer look at the helpful dialog - the Exception Assistant - that you can see thedebugger displays a little later in this section.

BreakpointsYou can set a breakpoint on the current line in the source editor by pressing F9. Alternativelyyou can click in the area just to the left of the source editor, alongside the line you want tobreak on. When a breakpoint is set a red circle is shown in the margin:

Page 139: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

139Part IV: The .NET Way

Paul Piko, 2010

When a breakpoint is set and the application is being run in debug mode execution will halt onthe line containing the breakpoint. This allows us to examine the current status of theapplication using the various debugging tools that are available.

You can remove a breakpoint by using F9 again, or left-clicking on the red circle.

There are some very useful options for breakpoints. If you right-click on a breakpoint you areshown a menu:

You can delete or temporarily disable the breakpoint. The Location option lets you controlexactly where the break occurs:

The Condition option allows the break to be bypassed until a certain condition occurs. For

Page 140: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

140 Vulcan.NET at Warp Speed

Paul Piko, 2010

example, if we have a loop with a variable being incremented we can make the break onlyoccur when the variable reaches a certain value:

It is possible to put more complex expressions into the condition. You can even use Vulcanfunctions, although you may have to fully specify the function names for the debugger toresolve them:

Alternatively, you might want a break to occur when the code has been executed a certainnumber of times. In that situation you use the Hit Count option:

The Filter option on a breakpoint lets you restrict its behaviour to certain processes or threads:

Page 141: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

141Part IV: The .NET Way

Paul Piko, 2010

And finally the When Hit option gives you the opportunity to customise what happens whenthe breakpoint is reached:

Exception HandlingThe way debugging of exceptions is handled can be configured via the Debug, Exceptionsoption in Visual Studio. Normally the debugger will only break if an exception is unhandled butthis is controlled by the Exception dialog. You can tell the debugging to break in when an

Page 142: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

142 Vulcan.NET at Warp Speed

Paul Piko, 2010

particular exception is thrown, not just when it is unhandled:

Exceptions that you have written yourself do not appear automatically in this list however youcan include them by using the Add button, just ensure that you use the fully specified classname, including the namespace.

Stepping Once the debugger has been triggered you can use Step Into (F11) to follow each line of code.If do not want to go into a particular method you can use Step Over (F10) to execute themethod and move to the next line in the calling method. Step Out (Shift-F11) is used tocontinue execution to the end of the current method, stopping when it returns to the codethat called it.

You can also write click on a line of code in the debug and chose to Run to Cursor, executionstopping on the specified line.

Common Debugger WindowsLocalsThe Locals window shows all variables local to the current point in the code. The variable'svalue and type is displayed. If other values are contained within the variable you can drill-downinto the variable by expanding the treeview.

Some types have a "visualiser". A visualiser is a custom window to display the contents of thevariable. The presence of a visualiser is indicated by a magnifying glass icon next to the variable

Page 143: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

143Part IV: The .NET Way

Paul Piko, 2010

value. The following example shows that the dataset has a visualiser:

Clicking on the icon brings up a context menu from which you can choose to show thevisualiser:

The appearance of the visualiser depends on the type of data being displayed. The TextVisualiser looks like this:

Page 144: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

144 Vulcan.NET at Warp Speed

Paul Piko, 2010

Quick WatchRight click on a variable while you are debugging brings up a menu that has an option calledQuick Watch. If you select it a window like the following is shown, allowing you to examine thecontents of the variable:

Watch WindowsIf you want to monitor the contents of a variable over time the Watch Windows are moreconvenient than the Quick Watch window. There are four Watch Windows that you can use sothat you can group together variables as you want. You can add variables to the WatchWindows by right-clicking on the variable and selecting Add Watch. Or you can click on the AddWatch button in the Quick Watch window. You can also right click on the variable in the Localswindow and select Add Watch.

Output WindowThis window contains messages about the build and loading of assemblies. You can also writeyour own messages to the Output Window using System.Diagnostics.Debug.WriteLine().

Immediate WindowThe Immediate Window lets you evaluate expressions, accessing variables that are in scope ifyou require. You type the desired expression on a line and press return to execute it.

Call StackYou can navigate through the program's execution path using the Call Stack window. You canexamine variables at each level of execution.

Breakpoint WindowA list of all breakpoints is accessible by selecting Debug, Windows, Breakpoints from the menu.

Page 145: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

145Part IV: The .NET Way

Paul Piko, 2010

All the breakpoint options can be configured from this window.

Exception AssistantWe saw a screen shot earlier showing the Exception Assistant helping to debug an exception.Here is an example:

When you click on the "Make sure the value..." line, help specific to this exception is shown.You can view the exception object itself by clicking on the View Detail link.

The appearance of the Exception Assistant is controlled through XML files in the \Program Files\Microsoft Visual Studio 8\Common7\IDE\ExceptionAssistantContent\1033 folder (note: 1033 isfor English installations, this number will vary for other languages). The standard exceptionsare described in DefaultContent.xml. You can add help for your own exceptions by including acorrectly formatted file in this same folder; no other action is required other than restartingVisual Studio.

Here is a custom file for the Exception Assistant. The name of the file does not matter, for ourexample it is called MyCompanyException.xml:

<?xml version="1.0" encoding="utf-8" ?><AssistantContent Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdata:exception-assistant-content"> <ContentInfo> <ContentName>Supplementary Content</ContentName> <ContentID>urn:exception-content-microsoft-com:visual-studio-7-default-content</ContentID> <ContentFileVersion>1.0</ContentFileVersion> <ContentAuthor>My Company</ContentAuthor> <ContentComment>Supplementary Exception Assistant Content for Visual Studio 8.0.</ContentComment> </ContentInfo> <Exception> <Type>Debug1.MyException</Type> <Tip HelpID="http://www.grafxsoft.com"> <Description>Our custom error.</Description> </Tip> </Exception></AssistantContent>

There are a few things to note with this sample. In the ContentInfo section we can adjust thedetails to suite our own situation. The more significant changes are in the Exception section.The Type value is the fully qualified class name of our own exception type, Debug1.Exception.Then the Tip HelpID has been directed at a URL that should contain a description of ourexception. This is the destination of the link that appears within the Troubleshooting tips

Page 146: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

146 Vulcan.NET at Warp Speed

Paul Piko, 2010

portion of the Exception Assistant. Finally the Description is the link text within the tip box.When our custom exception occurs the Exception Assistant jumps in with our details to helpout:

The full code for the exception sample is shown below. The simplistic custom exception is justa subclass of System.Exception - in practice you would provide detailed information about theexception. To force the exception to fire we have used BREAK to explicitly throw theexception:

FUNCTION Start( cmdlineArgs AS STRING[] ) AS INT LOCAL retcode AS INT

BreakTest2()

RETURN retcode

FUNCTION BreakTest2() AS VOID BREAK MyException{} RETURN CLASS MyException INHERIT System.Exception END CLASS

Page 147: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

147Part IV: The .NET Way

Paul Piko, 2010

Page 148: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

148 Vulcan.NET at Warp Speed

Paul Piko, 2010

7.5 ResourcesThe following examples use an Icon resource, but you can handle some other resources in asimilar manner.

Controlling the icon shown by Windows ExplorerWindows Explorer displays the first (lowest named) Win32 icon resource from an executable.So, to provide our own icon for a .NET application, we need to create a Win32 resource and linkit into our EXE.

To create the Win32 resource we first create a text file containing statements that will beprocessed by the Win32 resource compiler, RC.EXE. For our example we will use a file calledmyapp.rc with the following contents:

1 ICON "myapp.ico"

The 1 is the identifier of the resource, the term ICON tells the resource compiler what type offile we are using and "myapp.ico" is the name of the actual icon file.

Next thing is to convert the myapp.rc file to an actual resource file (.res), output by theresource compiler:

rc myapp

So now we have a Win32 resource file called myapp.res. We can link the file into the .NETexecutable like this:

vulcan myapplication /win32res:myapp.res

The resulting, vulcan-compiled application should now appear with the myapp icon in WindowsExplorer.

Using a Win32 resource in a .NET applicationThis section assumes you added the Win32 resource to your .NET executable as described inthe step above. You can then use Win32 API functions to get a handle to the Win32 resource,and use the Icon.FromHandle method to create a .NET GDI+ Icon object. That object can thenbe assigned to the form icon property. The following code shows this in action:

#using System.Drawing#using System.Windows.Forms

FUNCTION Start() AS VOIDLOCAL oForm AS Form

oForm := Form{}

// The 1 in the following line is the identifier used in our Win32 resourceoForm:Icon := Icon.FromHandle(LoadIcon(GetModuleHandle(NULL_PSZ),PTR(1)))

oForm:ShowDialog()

RETURN

_DLL FUNC GetModuleHandle(lpModuleName AS PSZ) AS PTR PASCAL:KERNEL32.GetModuleHandle

_DLL FUNC LoadIcon( hInstance AS PTR, lpIconName AS PSZ) AS PTR PASCAL:USER32.LoadIcon

Page 149: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

149Part IV: The .NET Way

Paul Piko, 2010

Creating and using .NET managed resourcesUsing Visual StudioYou can manually add managed resources to an assembly using Visual Studio. Right click on theproject name in the Solution Explorer and select Add, New Item. In the Add New Item dialogselect the Resources File template:

You are then presented with the Resource manager window where you can maintain varioustypes of resources within your assembly:

Page 150: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

150 Vulcan.NET at Warp Speed

Paul Piko, 2010

The Add Resource button gives you the option to handle different types of resources:

Creating resource files programmaticallyYou can also programmatically create .NET managed resource files using the ResourceWriterclass. The managed resource files can then be linked into an assembly. A complete sampleapplication showing how this can be done can be found here: http://www.vulcanmindmeld.net/mindmeld/files/VulcanResources1.zip.

Once you have a managed resource file, for example myappresources.resources, you can linkit into an application:

vulcan myapplication /res:myappresources.resources

Using .NET managed resourcesWhen you have embedded, managed resources in an assembly you can use the

Page 151: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

151Part IV: The .NET Way

Paul Piko, 2010

ResourceManager class to access them. You tell Resource manager the name of theembedded resources and the assembly in which to look for them. You can then requestindividual resources from that we contained in the original .resources file:

#using System.Drawing#using System.Windows.Forms#using System.Resources#using System.Reflection

FUNCTION Start() AS VOIDLOCAL oIcon AS IconLOCAL rm AS ResourceManagerLOCAL oForm AS Form

// Need to use the ResourceManager to access the embedded resources// Use the base name of the resource file that was linked into the apprm := ResourceManager{ "myappresources", Assembly.GetExecutingAssembly() }

// This assumes there was an icon named appicon in the resourcesoIcon:=(Icon)rm:GetObject("appicon")

oForm := Form{}oForm:Icon := oIcon

oForm:ShowDialog()

Page 152: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

152 Vulcan.NET at Warp Speed

Paul Piko, 2010

7.6 Using the Command LineVulcan has many command line options. You can see a summary of them by running thefollowing:

vulcan /?

Vulcan responds with this:

Vulcan.NET Compiler version 1.0.0.122 >>> Development Build <<<Copyright (c) Grafx Database Systems, Inc. 2004-2006. All rights reserved.

Vulcan.NET Compiler Options

--- Input Files --- /i:<dir> Specify additional directories to search for #include files /lib:<dir> Specify additional directories to search for references /linkresource:<file> Create a link to a resource in the output file (short form: /linkres) /nostddefs[+|-] Do not read preprocessor directives from VulcanStdDefs.vh /reference:<file> Reference metadata in the specified assembly (short form: /r) /resource:<file> Embed a resource into the output file (short form: /res) /win32res:<file> Embed a Win32 resource (.res) file into the output file

--- Preprocessor --- /define:<name> Define preprocessor symbol /ppo Write preprocessor output to file /showIncludes List #include files in compiler output

--- Output Files --- /out:<file> Output file name (default is base name of first source file) /snk:<file> Sign assembly with strong name key pair in <file> /target:exe Build a console executable (default) (short form: /t:exe) /target:library Build a library (short form: /t:library) /target:winexe Build a Windows executable (short form: /t:winexe)

--- Code Generation --- /az[+|-] Arrays are 0-based instead of 1-based /cs[+|-] Identifiers are case-sensitive /debug[+|-] Emit debugging information (short form: /d) /di[+|-] Debug _INIT procedures /id[+|-] Integer divisions return FLOAT type /ns:<name> Namespace name /ovf[+|-] Generate exceptions on integer overflows /fovf[+|-] Generate exceptions on float overflows /unsafe[+|-] Allow unsafe code

--- Visual Objects Compatibility --- /lb[+|-] Allow late binding /vo[+|-] Enable / disable all VO compatibility options /vo1[+|-] Use VO semantics for Method 'Init' and 'Axit' /vo2[+|-] Initialize STRING variables and DIM array elements to "" /vo3[+|-] All class instance methods are virtual /vo4[+|-] Allow implicit conversions between signed / unsigned integer types /vo5[+|-] Allow implicit CLIPPER calling convention /vo6[+|-] Allow implicit return values

--- Errors and Warnings --- /w<num>[+|-] Enable or disable warning <num> /wp64[+|-] Enable or disable 64-bit portability warnings /wx[+|-] Treat warnings as errors

--- Miscellaneous --- @<file> Read compiler options from response file /batch[+|-] Compile each source file individually /fullpaths Generate fully qualified paths in error messages and debug output

Page 153: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

153Part IV: The .NET Way

Paul Piko, 2010

/noconfig Do not read options from VULCAN.RSP /nologo Suppress copyright message /recurse:<dir> Recurse through <dir> and compile all .prg files /s Syntax check only, no compile /v Verbose progress output

--- Development Builds Only --- /a[+|-] Generate AST output /cf[+|-] Enable constant folding (default=on) /ild[+|-] Run ILDASM on output /pev[+|-] Run PEVerify on output

File and directory names containing spaces or other special characters must be enclosed within double quotes. Options that require arguments may use ':' or a space between the option and the argument.

These compiler options are all discussed in detail in the Vulcan.NET Reference file.

The following pages contain information on creating and building Vulcan programs from thecommand prompt.

7.6.1 Creating Applications

You can use any text editor, even Notepad, to create source code files for Vulcan.NET.

In a simple case you can write Hello.prg containing the following:

FUNCTION Start AS VOID? "Hello"RETURN

We compile this from the command prompt as follows:

vulcan hello

If you want to use a debugger on this program you need to compile with the /debug switch:

vulcan hello /debug

If you have more than one PRG file to compile you can include all the file names on thecommand line:

vulcan hello hello1 hello2

If you often need to use a particular set of switches you can put them into a compiler responsefile. In the response file you can put each of the arguments to the compiler on a separate line,e.g. the following could be the contents of a response file

hellohello1/debug/ vo/target:library

Page 154: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

154 Vulcan.NET at Warp Speed

Paul Piko, 2010

If the response file name is hello.rsp you compile as follows:

vulcan @hello.rsp

Vulcan has a series of default compiler settings contained in the file Vulcan.rsp, found in theVulcan BIN folder. These settings include references to commonly use assemblies, such asSystem.DLL. If you do not want these default settings to be used you need to enable the /noconfig switch when compiling, e.g.

vulcan @mysettings.rsp /noconfig

For example, the standard, common assemblies referred to by Vulcan.rsp are not requiredwhen your target assembly is destined for a PDA running the Compact Framework. In that caseyou want the Compact Framework version of the Forms assembly in your custom response file,e.g.:

/r:"d:\Program Files\Microsoft.NET\SDK\CompactFramework\v2.0\WindowsCE\System.Windows.Forms.dll"

You can use the CLR debugger, DBGCLR.EXE, from the command line to debug applicationswithout running Visual Studio. DBGCLR was discussed in an earlier section.

7.6.2 MSBuild

MSBuild is a command line utility that is use to build projects and solutions. It actually readsproject files to determine what needs to be compiled and built. If you do not explicitly pass aproject file name to MSBuild it search for a project file in the current directory.

When you use Visual Studio it automatically maintains solution and project files. You can build aVisual Studio project without it running by executing MSBuild in the project directory.

The project file is am XML file and contains element described each item that needs to be built,along with all configuration settings.

Writing a project file by hand is not a simple task but it is possible. The following is the mostbasic file that can be used by MSBuild to build hello.exe from hello.prg:

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Compile Include="hello.prg"> <SubType>Code</SubType> </Compile> </ItemGroup> <Import Project="$(MSBuildExtensionsPath)\Vulcan.NET\1.0\Vulcan.targets" /></Project>

The Vulcan.targets file you can see referenced here contains the essential rules for the buildprocess. If you do want to tackle hand-crafting project files for MSBuild you should refer to thissection of the MS Developer Network: http://msdn2.microsoft.com/en-us/library/ms171452.aspx

Page 155: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

155Part IV: The .NET Way

Paul Piko, 2010

7.7 InteroperabilityThis section discusses ways that software and components external to .NET can be usedwithin a Vulcan application. It also shows how features within Vulcan assemblies can be madeaccessible to standard Windows 32 applications such as those produced by Visual Objects.

7.7.1 Using COM from .NET

For this section we will create a simple COM component using VO and then write a Vulcanapplication that calls the component.

Creating a COM component in VOThe simplest way to create a COM component in VO, if you are unfamiliar with the process, isto open the New Application gallery, go to the OLE Server tab, and choose “OLE InprocServer”:

The code that is generated creates a class called SimpleAutoServer that inherits fromAutoServer. For our purposes here we can delete this initial class and create one of our own:

CLASS MyVOAutoServer INHERIT AutoServer

METHOD AddNumbers(x,y) CLASS MyVOAutoServerRETURN x + y

METHOD UpdateString(c) CLASS MyVOAutoServerRETURN c + " from VO"

Page 156: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

156 Vulcan.NET at Warp Speed

Paul Piko, 2010

METHOD RetrieveLogic() CLASS MyVOAutoServerRETURN TRUE

In addition to the class code there is also a global variable, an Init procedure and a fewDEFINEs. The DEFINEs are extraneous and can be deleted.

The global variable is typed as SimpleAutoServer. Since we have created our own class we canchange this reference to our class name, MyVOAutoServer. The Init procedure also creates aninstance of SimpleAutoServer – once again we substitute our own class name. These changesyield the following code:

GLOBAL goAutoServer AS MyVOAutoServer

PROCEDURE InitProc() _INIT 3goAutoServer := MyVOAutoServer{}

The remaining changes required are found in the application properties. First change theexecutable name to something more meaningful. In this example we use MyVOAutoServer.DLL.

Next move to the OLE Server tab. The two things to change here are the ProgId, used toidentify the component, and the Automation class. The ProgId can be anything, here we useMyVOAutoServer.Application. The Automation class should be the class we wrote,MyVOAutoServer:

Accessing a COM component from .NETThis example of accessing a VO-authored COM component in .NET is a simple consoleapplication. We begin by creating a new project in Visual Studio, and make sure ConsoleApplication is the selected template, as seen below.

Page 157: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

157Part IV: The .NET Way

Paul Piko, 2010

In order to make use of the COM component in the console application we need to add areference to it. When the Add Reference option is selected from the Solution Explorer'scontext menu, a dialog similar to the one below is displayed:

Page 158: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

158 Vulcan.NET at Warp Speed

Paul Piko, 2010

Select the COM component and press OK. Visual Studio examines the component andautomatically creates a library – a DLL containing a wrapper class around the COM server. TheSolution Explorer is also updated and shows the new library in the References section:

This generated DLL is called an Interop assembly, and in this case is named Interop.MyVOAutoServerLib.DLL. When an Interop assembly is strongly signed, using a strong namekey - there is a compiler option for this - it is called a Primary Interop assembly.

If .NET can find an existing Interop assembly for aCOM component on the computer, it will notgenerate the wrapper again, and it will use the pre-existing one.

To examine the contents of the library you can right click on this new entry and select View inObject Browser:

Page 159: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

159Part IV: The .NET Way

Paul Piko, 2010

From the Object Browser we can determine that the automatically generated namespace isMyVOAutoServerLib. We can also see that the class name is MyVOAutoServerClass. This namewas generated by adding the suffix "Class" to our COM Server name, "MyVOAutoServer".However, courtesy of a short-cutting feature, we can actually drop the class suffix when theclass represents a COM component and Vulcan will still be able to resolve the name.

Vulcan, like C#, allows you to drop the Class suffix forCOM components and it will still be able to resolvereferences to the class.

To make use of this library the example code has to include the following line:

Note that the class name generated is actually MyVOAutoServerClass, which is obtained byappending “Class” to the name of the COM server “MyVOAutoServer”. C# has a feature thatlets you drop the class suffix and it will still be able to resolve references to the class.

So the code to call our automation server looks like this:

#using MyVOAutoServerLib

FUNCTION Start( cmdlineArgs AS STRING[] ) AS INT LOCAL retcode AS INT LOCAL o AS MyVOAutoServer ? "Using the COM server..." o := MyVOAutoServer{} ? o:UpdateString("Hello") ? o:AddNumbers(1,2) RETURN retcode

And it produces this output:

Page 160: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

160 Vulcan.NET at Warp Speed

Paul Piko, 2010

Using the COM server...Hello from VO3

Creating the Interop Assembly ManuallyYou can use the command line utility TlbImp.EXE to manually generate an Interop DLL:

tlbimp MyVOAutoServer.DLL

This creates a file MyVOAutoServerlib.DLL just like the DLL produced by Visual Studio. Usingthe command line gives you more options on how the assembly is created such as thenamespace to use.

7.7.2 Using .NET Components via COM

In this section we create a COM component that allows non-.NET applications call .NET code.

Create new project in Visual StudioWe do not currently have a template for creating COM components in Visual Studio withVulcan.NET. But, with a few easy steps, we can make up for that.

We start with a Vulcan Class Library:

When we click OK on this dialog Visual Studio creates a new solution and project, and provides

Page 161: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

161Part IV: The .NET Way

Paul Piko, 2010

a very basic class for us to customise. In this case we can delete the supplied class and replaceit with our own:

CLASS Application

CONSTRUCTOR() RETURN

METHOD GetALogic() AS LOGIC RETURN TRUE

END CLASS

If we built this solution as it is, all we would end up with is a regular .NET assembly. To makethis assembly accessible via COM we need to enlist the help of the RegAsm.EXE command lineutility. RegAsm reads the information in the assembly and works out the updates that areneeded to the registry to use the assembly via COM. Now, even though RegAsm is a commandline utility, we do not have to manually run it. Visual Studio has the capability to execute taskswhen assemblies are built, and we can use that capability to execute RegAsm. If you go to theBuild Events tab of the project properties you will see that we can specify pre- and post-buildevents. In our case we want a post-build command line as follows:

regasm $(TargetFileName) /tlb

The $(TargetFileName) is the file name of the primary output file of the build. You can findmore macros and their values in the MSDN help in the section titled "Pre-build Event/Post-build Event Command Line Dialog Box". The /tlb tells RegAsm to create a type library for theassembly.

Now if we build the assembly it will also be registered with COM. But if you take a look inAssemblyInfo.prg that was generated when the project was created you will see the followinglines:

// Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type.[assembly: ComVisibleAttribute( FALSE )]

This assembly attribute is set to FALSE, meaning none of the types (classes) within theassembly will be visible to COM. We need to set this to TRUE to allow all types to be visible, orwe can set this attribute for individual types. This attribute resides in System.Runtime.InteropServices, so it can help readability to put it in a #using directive, as we have in thefollowing code where our Application class is made visible via COM:

#using System.Runtime.InteropServices

[ComVisible(TRUE)] ;CLASS Application

CONSTRUCTOR() RETURN

METHOD GetALogic() AS LOGIC RETURN TRUE

END CLASS

Page 162: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

162 Vulcan.NET at Warp Speed

Paul Piko, 2010

Note that the attribute's name is ComVisibleAttribute. We can shorten the name of theattribute, discarding the "Attribute" at the end, and Vulcan can still understand what attributewe mean.

Vulcan, like C#, allows you to drop the Attribute suffixfor attributes and it will still be able to resolve thereferences.

So now we have a COM registered assembly, and have a class that is visible through COM.

But there is still a little more we need to do. While the class is visible, the default COM interfacedoes not contain any members. To create an automatic COM interface from the class we needto use another attribute, ClassInterface:

#using System.Runtime.InteropServices

[ClassInterface(ClassInterfaceType.AutoDual)] ;[ComVisible(TRUE)] ;CLASS Application

CONSTRUCTOR() RETURN

METHOD GetALogic() AS LOGIC RETURN TRUE METHOD AddNumbers(x AS INT, y AS INT) AS INT RETURN x+y METHOD UpdateMessage(c AS STRING) AS STRING RETURN c + "from Vulcan"

END CLASS

In this example we are getting an automatic, default COM interface. It is preferential to controlthe appearance of the COM interface, which will be possible using Vulcan's INTERFACEfeature. An example will be provided when this feature is complete.

Accessing a .NET COM component from VOIn Visual Objects the .NET COM component can be accessed like other COM components.Note that, unless you use the /codebase option of RegAsm.exe, no pathing information isstored in the registry for the .NET COM component. In that situation you may need to copy theCOM assembly to a folder where the calling application can find it.

Late boundWhen a COM component is late bound the information about the properties and methods isdetermined at runtime.

Here is the VO code to create a late bound version of our example .NET COM component:

LOCAL oLate AS OBJECTLOCAL x AS USUAL

Page 163: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

163Part IV: The .NET Way

Paul Piko, 2010

oLate := OLEAutoObject{"VulcanComponent.Application"}IF oLate:fInit x := oLate:GetALogic() InfoBox{,"Late bound",AsString(x)}:show()ELSE ErrorBox{,"Could not create late bound component"}:show()ENDIF

Note the parameter passed to OLEAutoObject is the COM ProgId which identifies thecomponent we want to instantiate. The ProgId of our .NET sample is made up from thenamespace (VulcanComponent) and the class name (Application) which yieldVulcanComponent.Application.

Early boundTo use a COM component early bound in VO code is generated from the component. This isdone by selecting Automation Server from the VO Tools menu:

As you can see from the image, VulcanComponent appears in the list of available servers,courtesy of the registration performed by RegAsm.exe when we built the component. If youhighlight the server entry and then press the Show Interfaces button the interfaces listbox,which was empty, now has an entry called _Application. This actually comes from ourApplication class in our .NET component – VO adds the underscore at the front to avoid a nameconflicts. If you click on the _Application interface, the Class name field, which was empty, isfilled with interface name. You can change this class name if you desire.

Clicking on the Generate source button instructs VO to interrogate the component and

Page 164: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

164 Vulcan.NET at Warp Speed

Paul Piko, 2010

produce class code in the current module.

In addition to a GetALogic() method arising from the member we wrote in Vulcan there aresome other methods in the VO generated code: ToString, Equals, GetHashCode, GetType.These methods appear because the default class interface of the component actually inheritsfrom .NET’s System.Object and these methods come from that class.

The component can be used early bound as follows:

LOCAL oEarly AS OBJECTLOCAL x AS USUAL

oEarly := _Application{}IF oEarly:fInit x := oEarly:GetALogic() InfoBox{,"Early bound",AsString(x)}:show()ELSE ErrorBox{,"Could not create early bound component"}:show()ENDIF

Data ExchangeThe standard data types can be passed to and from the .NET component. For example we canadd two methods to our sample component, one to handle numbers, another to handle astring:

METHOD AddNumbers(x AS INT, y AS INT) AS INT RETURN x+y METHOD UpdateMessage(c AS STRING) AS STRING RETURN c + " from Vulcan"

These can then be successfully called from the VO application, passing and receiving data:

x := oLate:AddNumbers(40,2)x := oLate:UpdateMessage("Hello")

Note that any methods of the component that are expecting to receive a complex value, suchas a .NET object, cannot be easily called from the VO application. It is simpler to keep anycreation of .NET objects within the component, so it may be necessary to create extramethods for the component that can perform these tasks. The VO application can then callthese worker methods to handle any .NET objects.

Changing ProgId and GUIDYou can explicitly define the ProgId and GUID to be used for the COM component you arecreating.

To do this include lines like the following before the class definition:

[GuidAttribute("1C15D9C7-A3EF-3485-0000-156524C461A1"), ;ProgId("VulcanComponent.Manager")] ;[ComVisible( TRUE )] ;CLASS Application

Page 165: Vulcan.NET at Warp Speed · 8 Vulcan.NET at Warp Speed Paul Piko, 2010 3.1 Introduction T he famous book by Douglas Adams, "The Hitchhiker's Guide To The …

165Part IV: The .NET Way

Paul Piko, 2010

7.7.3 Platform Invoke

Code that executes outside of the control of the .NET runtime is called unmanaged code. Youcan call external, unmanaged functions using the _DLL FUNC declaration as is used in VO:

_DLL FUNCTION Beep( utype AS DWORD ) AS LOGIC PASCAL:USER32.MessageBeep

Vulcan has additional keywords that can be used at the end of the _DLL FUNC statement:

· ANSI

· UNICODE

· AUTO

ANSI means that strings will be handled as 8 byte ANSI strings. UNICODE means strings arehandled as UTF-16 Unicode strings. AUTO, the default if no explicit string handling isrequested, will determine the method used depending on the operating system. On WindowsME and below AUTO will result in ANSI handling, on NT and above AUTO handles strings asUNICODE.

Note: The Compact Framework does not support ANSIstrings

Because of the manner in which Windows 32 functions are called from the .NET frameworkyou cannot use the Win32 GetLastError function (in kernel32.dll) to determine if the functionproduced any error. To solve this problem you need to call the System.Runtime.InteropServices.Marshal.GetLastWin32Error method to retrieve the error code set by the callto the _DLL function.