fbpx
Welcome, Guest
Username: Password: Remember me

TOPIC: VO Application ported to X#

VO Application ported to X# 1 year 11 months ago #2121

  wriedmann's Avatar Topic Author wriedmann Away Posts: 1573
Hello,

yesterday I was able to migrate my Dictionary Editor to X#.(it is a tool to design databases and maintain the string tables for translations)

This is a screeshot of the VO version:

and this of the X# version:


Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
This email address is being protected from spambots. You need JavaScript enabled to view it.
www.riedmann.it - docs.xsharp.it
Attachments:

Please Log in or Create an account to join the conversation.

VO Application ported to X# 1 year 11 months ago #2127

  Chris's Avatar Chris Offline Posts: 1181
Hi Wolfgang,

Thanks for sharing! Personally I already know the answer, since we've talked also by email, but maybe you could share also here your experience with porting the app to x#?

Obviously porting a VO app to x# is not a click and go thing, it requires preparation, effort and some patience for sure! But I think that after you gain some experience with this, it becomes much easier. If you'd like please share some of this, so other people know what to expect as well. When/if you have some time to do this of course.

btw, of course this goes also for everybody else who have ported their VO apps (or some of them)!

TIA,
Chris
XSharp Development Team
chris(at)xsharp.eu

Please Log in or Create an account to join the conversation.

VO Application ported to X# 1 year 11 months ago #2137

  wriedmann's Avatar Topic Author wriedmann Away Posts: 1573
Hi Chris,

So, if this migration interests someone, I'll post a few articles about it in this thread (a too long article is hard to read and hard to write).

First, let me explain the structure of my VO applications:
  • The base library is the wLib2, that is about 20 years old and is enhanced when needed, at least once a month. It contains the base classes for servers, controls and windows and a lot of other functions and classes. This library contains only handwritten code and is shared between different projects through external modules.
  • Then there is the BasicMapi lib, that contains basic mail functionality and DynMenu, the basic classes for dynamic menus (I don't use the menu editor because most menus are to build depending on the current user
  • The next library is wLibDlg, that uses the first three libraries and contains the most used dialogs, like LookupDialog, ChoiceDialog and about 20 others.
  • Next in the list is wStdBrowser, that uses bBrowser 4, defines my bBrowser base class and the standard databrowser window from which nearly all databrowser windows are inherited, and the relative filter functionality.
  • And then, as last in the list, I have wErrorsys, my base error handler.
There are much more libraries, but they are loaded either dynamically like the Zip (using Compression Plus) or the report classes (using VPE), or used only by a few applications like the Vo2Ado or the MySql lib.

As you can immagine, first candidate in the migration process was the wLib2 library.

Since my libraries and my applications are living, I need the possibility to repeat the migration often, until all of my VO applications (about 50) are migrated to X#.
And the basic rule is to not change anything in the X# version of the library that is not changed also in the VO version.

And as last note: I have licenses to Vulcan 4 (as I'm currently subscribed also to VPS) and to the bBrowser4.NET.

Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
This email address is being protected from spambots. You need JavaScript enabled to view it.
www.riedmann.it - docs.xsharp.it

Please Log in or Create an account to join the conversation.

Preparations and first migration of wLib 1 year 11 months ago #2138

  wriedmann's Avatar Topic Author wriedmann Away Posts: 1573
Before starting the migration of my most important library, I have imported the source code of the Vulcan version of the VO class libraries into my XIDE projects.
Then I have changed the names of the libraries from VulcanVO* to XSVO*, changed the compiler from Vulcan to X#/Vulcan dialect and compiled them.

Another note: on my C drive, I have a folder called DevNET\Libs, where I put all compiled versions of my libraries:

Upon my request, Chris has added a special function in XIDE to copy the binaries of a project to a directory, and I use this funtionality to maintain my c:\devnet\libs directory content up to date:

When using then the libraries in an application references, I select them from the relative c:\devNET\libs folder.

Back to the migration process itself: I created a new XIDE project, called VO to X# migration, using the folder C:\XSharp\XIDE\Projects\VO_XS_Migration\.

Then I fired up the VO-xPorter, selected the most recent version of my wLib2 AEF and used the following settings:

Two settings are very important:
  • the output folder points to the Applications directory of the new project
  • and the "do not overwrite project files" is checked
These settings are important so I can repeat the migration process how often as I like without the need to reconfigure the projects settings after each run.

After xPorting the AEF, I added the application through the Project - Add application context menu:

After this, the application was ready to be compiled, and I can assure that I was shocked about the number of compilation errors and warnings I received.

Please read the next message about some solutions I have adopted.
Wolfgang Riedmann
Meran, South Tyrol, Italy
This email address is being protected from spambots. You need JavaScript enabled to view it.
www.riedmann.it - docs.xsharp.it

Please Log in or Create an account to join the conversation.

Errors and fixes - Part 1 1 year 11 months ago #2139

  wriedmann's Avatar Topic Author wriedmann Away Posts: 1573
After porting my library the first time and fixing the references (replacing the VulcanVO* libraries by the XSVO* libraries), I was really surprised how few errors I had:



The 2 errors were only delegates added by xPorter:
delegate DictClose_delegate() as void pascal
Easily changed to
delegate DictClose_delegate() as void

and
delegate EnumWindowsProc_delegate( hWnd as ptr, aWindows as array ) as word callback
to
delegate EnumWindowsProc_delegate( hWnd as ptr, aWindows as array ) as word
These two issues will be fixed soon in xPorter.

Fixed these two, on the next compile the errors changed (with warnings hidden as I would concentrate on errors first):


I will list every type of error only once - and all changes were made on both the VO and the X# side, so I had code synchronized. Larger changes were only made on the VO side, and then moved to X# with a new xPorter run.
error XS0029: Cannot implicitly convert type 'Vulcan.Codeblock' to 'string'
in this part of code:
if cValidBlock == NULL_STRING
  cValidBlock := MCompile( cValidString )
endif
change to
#ifndef __XSHARP__
if cValidBlock == NULL_STRING
  cValidBlock := MCompile( cValidString )
endif
uResult := MExec( cValidBlock )
#else
if oValidBlock == null
  oValidBlock := MCompile( cValidString )
endif
uResult := MExec( oValidBlock )
#endif
as MCompile has another definition in the Vulcan runtime. This correction fixed the first two errors.

Next error after recompile:
error XS0619: 'Functions._RegisterExit(void*)' is obsolete: ''_RegisterExit()' is not supported.  Use an event handler added to the AppDomain.CurrentDomain:ProcessExit event instead'
on this code part
if lInit == false     
#warning Callback function modified to use a DELEGATE by xPorter. Please review.
// _RegisterExit( @AxitGlobal() )
static local oAxitGlobalDelegate := AxitGlobal as AxitGlobal_Delegate
_RegisterExit( ;
System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(oAxitGlobalDelegate) )
  lInit := true
endif
This code was changed by the xPorter, and since I don't think the .NET runtime needs the RegisterExit anymore, changed to:
#ifndef __XSHARP__
if lInit == false
  _RegisterExit( @AxitGlobal() )
  lInit := true
endif
#endif

Next error:
error XS0619: 'Functions.Buffer(dword)' is obsolete: ''Buffer()' is not supported, use MemAlloc() and MemFree() instead'
on
cBuffer:= Buffer( 4096 )
easily changed to
#ifdef __XSHARP__
cBuffer := Space( 4096 )
#else
cBuffer := Buffer( 4096 )
#endif

The next error
error XS9035: The first argument to PCall must be a 'typed function pointer'.
on
PCall( ptrFunction, @strWinOsVersionInfo )
was changed to
#ifdef __XSHARP__
PCallNative<int>( ptrFunction, @strWinOsVersionInfo )
#else 
PCall( ptrFunction, @strWinOsVersionInfo )
#endif

Next series of errors:
error XS0246: The type or namespace name '_GCDUMP' could not be found (are you missing a using directive or an assembly reference?)
in a function that dumped the current memory for diagnosis. Since the .NET garbage collector is totally, different, I decided to remove the entire function by adding an #ifndef __XSHARP__ before and a #endif after.
The same proceeding was used then on the error
error XS0619: 'Functions.Memory(int)' is obsolete: ''Memory()' is not supported'

Next (and last error for this article):
error XS0619: 'Functions._VOLoadLibrary(string)' is obsolete: ''_VOLoadLibrary()' is not supported, use VulcanLoadLibrary() instead.'
repeated several times on various dynamic loads of DLLs:
hDLL := _VOLoadLibrary( cDLLName )
if hDLL == null_PTR
  ErrBox( oWindow, StrTran( 'library %1 not found", "%1", cDLLName ) )
  return false
else
  hProc	:= GetProcAddress( hDLL, String2Psz( "CPPlusInitDLL" ) )
  if hProc == null_ptr
    ErrBox( oWindow, "error on initialization" =
    return false
  endif
  PCall( hProc )                                                             
  if IsClass( #ZipClass )
    lRetCode := true
  else
    ErrBox( oWindow, "error on initialization of " + cDLLName )
    return false
  endif
endif
Since this code cannot work with X# as .NET works in a completely different manner, and DLLs are to be loaded with Reflection, I decided to not implement this for the moment, so my code was changed to:
#ifdef __XSHARP__
ErrBox( oWindow, "error on initialization of " + cDLLName )
return false		// TODO 
#else
... remainder of code
#endif
Wolfgang Riedmann
Meran, South Tyrol, Italy
This email address is being protected from spambots. You need JavaScript enabled to view it.
www.riedmann.it - docs.xsharp.it
Attachments:

Please Log in or Create an account to join the conversation.

Errors and fixes - Part 1 1 year 11 months ago #2140

  wriedmann's Avatar Topic Author wriedmann Away Posts: 1573
Hello,

since the writing of this posts is very time consuming, please don't expect posts in too short periods.

At the same time, I will prepare a PDF that has not only the same content as these posts, but will be kept updated and enhanced, adding better explanations where needed. An example would be the different behavior of the VO garbage collector and the .NET one: .NET calls always the destructor, whereas in VO you need to register for it with RegisterAxit()

Thank you very much to Chris Pyrgas for pointing this out!

Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
This email address is being protected from spambots. You need JavaScript enabled to view it.
www.riedmann.it - docs.xsharp.it

Please Log in or Create an account to join the conversation.

Errors and fixes - Part 1 1 year 11 months ago #2141

  Chris's Avatar Chris Offline Posts: 1181
Hi Wolfgang,

Thanks a lot for posting your experience with porting and for explaining the actions and changes you had to make to your code to compile it in X#. I think such information is very helpful, so others will be also prepared about what they will need to do when they also port their apps.

It is also very rewarding for us devtem members to see that our efforts have paid off, it's great seeing and hearing more and more about VO apps that have been already ported to X#. And yes, we will be further improving the procedure in the coming builds.

Chris
XSharp Development Team
chris(at)xsharp.eu

Please Log in or Create an account to join the conversation.

Errors and fixes - Part 1 1 year 11 months ago #2142

  wriedmann's Avatar Topic Author wriedmann Away Posts: 1573
Hi Chris,

I'm very surprised how you guys have done a such compatible compiler (ok, sometimes the error messages could be better or more precise :)). The VO language and runtime are very different from other development systems, and they allowed us programmers to be very productive. The .NET environment may have several of these things already (like the garbage collector), but there are a lot of specialities remaining.

My base library may be a good example for very old code (its origins are in the pre-release of VO 1.0 under Windows 3.1) and several constructs that are simply not allowed in a .NET language and even some pieces of code that should never have compiled even in VO.

And I have to say that the major part of adjustments were to make in my base library - the other libraries and the Dictionary Editor needed only very few adjustments. And I have started to use the X# version of the Dictionary Editor in my daily VO development.

Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
This email address is being protected from spambots. You need JavaScript enabled to view it.
www.riedmann.it - docs.xsharp.it

Please Log in or Create an account to join the conversation.

Errors and fixes - Part 1 1 year 11 months ago #2152

  wriedmann's Avatar Topic Author wriedmann Away Posts: 1573
Hi,

if someone is awaiting the next post: I'm currently working on a (more extensive) version of the first 3 articles in PDF format, and I hope to publish the next article tomorrow, together with the relative PDF version (that contains more background information and will be kept up to date).

Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
This email address is being protected from spambots. You need JavaScript enabled to view it.
www.riedmann.it - docs.xsharp.it

Please Log in or Create an account to join the conversation.

XIDE Support for migration 1 year 11 months ago #2162

  wriedmann's Avatar Topic Author wriedmann Away Posts: 1573
Hi,

since I need to move my application often, I have added a function to my XIDE plugin: Tools - Copy application folder name.
This function copies the name of the application folder name to the clipboard so you can paste it in the VO xPorter output folder input control.

In the attached zip you will find both the sources (you need to change the references to your own XIDE path if you wish to compile itself) and the executable (simply copy to the XIDE\Plugins directory and restart XIDE).

Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
This email address is being protected from spambots. You need JavaScript enabled to view it.
www.riedmann.it - docs.xsharp.it
Attachments:

Please Log in or Create an account to join the conversation.

XIDE Support for migration 1 year 11 months ago #2199

  wriedmann's Avatar Topic Author wriedmann Away Posts: 1573
I have now completed the first version of my PDF document about the migration of my basic library to X#.

You can find it here:

https://www.riedmann.it/download/wlib2_to_xs.pdf

I will try to keep it updated.

Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
This email address is being protected from spambots. You need JavaScript enabled to view it.
www.riedmann.it - docs.xsharp.it

Please Log in or Create an account to join the conversation.

XIDE Support for migration 1 year 11 months ago #2200

  lorenzi@moduline.ch's Avatar lorenzi@moduline.ch Offline Posts: 25
Hi Wolfgang

congratulations for this great document. This will help a lot of us guys too.

Markus

Please Log in or Create an account to join the conversation.

XIDE Support for migration 1 year 11 months ago #2201

  wriedmann's Avatar Topic Author wriedmann Away Posts: 1573
Hi Markus,

Thank you!

"gut Ding braucht gut Weile" - unfortunately it took a lot of time to write it because I added some backgrounds too (it was a suggestion by Chris).

And this document will be enhanced in the next days and weeks - I have several things to add from my other libraries (and have several problems yet to fix).
Therefore I don't added this document to my message, but put it on my webserver, so I can replace it every time I need to add or change something.

Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
This email address is being protected from spambots. You need JavaScript enabled to view it.
www.riedmann.it - docs.xsharp.it

Please Log in or Create an account to join the conversation.

Last edit: by wriedmann.

XIDE Support for migration 1 year 11 months ago #2202

  Chris's Avatar Chris Offline Posts: 1181
Hi Wolfgang,

Thank you very much! This is great, showing various ways to overcome several incompatibilities between the VO and .Net world. Guys, thanks a lot for all your effort in doing this, it will help others a lot!

Some comments:

- MCompile in VO returns the compiled version of the code in a STRING variable, sort of as a binary buffer. This wouldn't work in .Net, instead the return type in the vulcan implementation is simply CODEBLOCK.

- I think Don did not implement the Buffer() function because this is very commonly used in code that uses the return string as an 8 bit binary buffer to be used with Win32 API functions. It would have been possible to define the Buffer(dwSize) function just so that it returns Space(dwSize), but since strings are unicode in .Net, this would result to a buffer double the size of the same code running in VO, and not to mention other potential issues when using a string var as binary buffer in .Net. So maybe it is a good idea to not implement Buffer() in X# either, thus prompting the user to review and adjust the code accordingly.

- My fault, when you asked me about the GC, I thought you were talking about RegisterAxit(), but I see in your VO code you are using _RegisterExit(). This registers "clean up" functions to be called on application exit and as the error message says, you can implement it in .Net by using such code:

AppDomain.CurrentDomain:ProcessExit += AxitGlobal

FUNCTION AxitGlobal(o AS OBJECT , e AS EventArgs) AS VOID
...

but from what I see in your code, you use those to keep the garbage collector of VO happy be NULLifying yourself several objects before exiting, while normally in .Net this is not needed. But I see you are also closing some DBServers in the Exit functions, would be better to do that also in the X# version of your code, close them manually than wait for them to be auto-closed when the app exits.

- It is very nice that you show how to use extension methods for "external" code added to the SDK classes in VO, together with showing things that need to be considered when using this method. But in your case you are already compiling your own version of the SDK, so I think the easier and most straightforward way is to just add that extra code directly in your version of the SDK code. I suspect you don't do that because you want to keep it simple moving to newer versions of the SDK, but you can simply include all the "new" methods of the SDK in a single .prg per library, containing partial classes with the code that extends each class, this will make it very easy to manage everything.

Chris
XSharp Development Team
chris(at)xsharp.eu

Please Log in or Create an account to join the conversation.

XIDE Support for migration 1 year 11 months ago #2203

  FFF's Avatar FFF Away Posts: 577
Chris,

but from what I see in your code, you use those to keep the garbage collector of VO happy be NULLifying yourself several objects before exiting, while normally in .Net this is not needed. But I see you are also closing some DBServers in the Exit functions, would be better to do that also in the X# version of your code, close them manually than wait for them to be auto-closed when the app exits.

Not sure this says what you want to say ;)
I think you recommend to write:
myServer:Close()
but _not_ followed by
myServer := Null_Object

Is this correct? If so, does that mean, that the chain of destruction might fail, if the holding "masterobject" is directly killed, while subobjects still exist?

IMO the whole topic of safely removing complex objects is somewhat fishy, too many urban myths abound ;)

Please Log in or Create an account to join the conversation.

XIDE Support for migration 1 year 11 months ago #2204

  wriedmann's Avatar Topic Author wriedmann Away Posts: 1573
Hi Chris,

thank you very much for your comments - I will add them to the document as appropriate. In this forum messages there is so much written down knowledge (and also in email messages) so it would be a real pity to loose it.

Regarding the VO SDK: mine is the Vulcan version, but I don't think I will continue to use this version when you release your runtime - I plan to switch to a version xPorted from the VO version.
Maybe I'll take your recommendation and change the SDK - until now I have tried to remain compatible to the VO version, but since there will be no newer version, it will be worth a tought.

Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
This email address is being protected from spambots. You need JavaScript enabled to view it.
www.riedmann.it - docs.xsharp.it

Please Log in or Create an account to join the conversation.

XIDE Support for migration 1 year 11 months ago #2205

  wriedmann's Avatar Topic Author wriedmann Away Posts: 1573
Hi Chris,

and regarding assigning null to my objects after use: I have started this type of coding early in the VO 1.0 days, but I prefer to keep it to help the garbage collector - normally I'm doing that when I don't need an object anymore.

The work of the GC is hard enough, so a bit of help cannot hurt, I think. And after all it is the programmer that knows when an object is not more needed, specially if working with objects referencing each other.

Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
This email address is being protected from spambots. You need JavaScript enabled to view it.
www.riedmann.it - docs.xsharp.it

Please Log in or Create an account to join the conversation.

XIDE Support for migration 1 year 11 months ago #2206

  Chris's Avatar Chris Offline Posts: 1181
Hi Karl and Wolfgang,

I know, always when it gets too hot for too long, my messages start to not make a lot of sense :-)

What I meant, is that I saw that in Wolfgang's code that he is manually closing some dbfs in a function that is registered by _RegisterExit(). If this function is not called in the X# version of his app, then the dbfs will not be closed gracefully by his own code, but they will be closed automatically by the runtime when it shut downs, at the moment the app is terminated. While normally there's nothing bad about that, in my opinion it is better to handle dbf closing by own code, same as the VO version of the code does. So my suggestion was to make sure that his "exit" functions get called also in the X# version of his app.

Chris
XSharp Development Team
chris(at)xsharp.eu

Please Log in or Create an account to join the conversation.

XIDE Support for migration 1 year 11 months ago #2207

  wriedmann's Avatar Topic Author wriedmann Away Posts: 1573
Hi Chris,

ok, I have now modified my code to call AxitGlobal as follows:
if lInit == false     
    #ifdef __XSHARP__   
        AppDomain.CurrentDomain:ProcessExit += AxitGlobalNET
    #else
        _RegisterExit( @AxitGlobal() )
    #endif
    lInit: = true
endif

And added a new function:
function AxitGlobalNET( o as object, e as EventArgs ) as void
	
    FunGlobal( NULL_SYMBOL, nil, #AXIT )
	
    return

This code now compiles in X#, but not more in VO, as VO does not knows about an EventArgs datatype.
Since #ifdef in VO cannot span entity borders, I have added the following definition to my VO-only module VOInt27:
class EventArgs

and now my code compiles also in VO.

I'll add this to my PDF document as hint.

Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
This email address is being protected from spambots. You need JavaScript enabled to view it.
www.riedmann.it - docs.xsharp.it

Please Log in or Create an account to join the conversation.

XIDE Support for migration 1 year 11 months ago #2208

  Chris's Avatar Chris Offline Posts: 1181
Wolfgang, that looks good to me!

Chris
XSharp Development Team
chris(at)xsharp.eu

Please Log in or Create an account to join the conversation.