FireStats error : Database error: Table './cromis/wp_firestats_pending_data' is marked as crashed and should be repaired

MySQL Version: 5.5.35-0+wheezy1
SQL Query:
INSERT DELAYED INTO `wp_firestats_pending_data` ( `timestamp`, `site_id` , `url` , `referrer` , `useragent` , `ip`, `type` ) VALUES ( NOW(), '1', 'http://www.cromis.net/blog/', '', 'Mozilla/5.0 (Windows NT 6.1; rv:6.0) Gecko/20110814 Firefox/6.0 Google favicon', '66.249.84.103', NULL )

Multi-touch: touched control and relative coordinates

by Iztok Kacin in Coding

This, I hope, should be the last article on multi-touch support for mobile devices. All that was missing in my implementation was support for detecting the control that was touched and getting relative coordinates inside that control along side with screen coordinates that I was already exposing. Today I saw this SO post. Someone was using my code, but was unable to get the local coordinates and control that was being touched. So I took the challenge and threw together some support for this, on all supported devices. Basically, what changed, is the TTouchPoint record. It now looks like this.

  TTouchPoint = record
    ID: Integer;
    Control: TFmxObject;
    Position: TPointF;
    RelPosition: TPointF;
    History: array of TPointF;
  end;

I added the control and relative position. If you are interested how I did that its simple.

  if Screen.ActiveForm <> nil then
  begin
    for I := 0 to Length(Event.Points) - 1 do
    begin
      Control := Screen.ActiveForm.ObjectAtPoint(Event.Points[I].Position);
 
      if Control <> nil then
      begin
        Event.Points[I].Control := Control as TFmxObject;
        Event.Points[I].RelPosition := Control.ScreenToLocal(Event.Points[I].Position);
      end
      else
      begin
        Event.Points[I].Control := Screen.ActiveForm;
        Event.Points[I].RelPosition := Screen.ActiveForm.ScreenToClient(Event.Points[I].Position);
      end;
    end;
  end;

You get the active form (I suppose there is a theoretical possibility that multi-touch is spreed over more then one form, but I discarded that situation as it seems very unlikely), then you get the object at the touch point coordinates. Finally you get the relative coordinates for that object. If no object is found then the form was touched. I will go no further with this as I spent to much time on it already. If you see some holes in the approach or you have improvements, feel free to tell me so. The code can be downloaded from the downloads section as usual.

Patch free Multi-touch iOS support for XE5

by Iztok Kacin in Coding

In my last post I wrote about the Multi-touch support for Android and iOS under Delphi XE5. The article received more attention then I anticipated, so I was surprised as it seems that this is something that people need. I was happy with the Android support but far from content on the iOS. Patching official Delphi units is always bad. You have to re-patch each and every new version that comes out. Even updates can cause problems as you still use the old patched units and so you can miss the fixes in the original.

That bothered me and when something bothers me I try to fix that. I am the kind of person that does not quit easily when I set my mind upon something. So I went back to the drawing board and tried to think of something that would let me enter through the back door. I did not believe that objectiveC is so badly designed that all you have is delegation to implement interfaces with actual classes and objects. As it turned out after digging around the internet and inside EMB code objectiveC is quite elegant, far more then Delphi in that respect. I found out that not only it supports subclassing (to no surprise) but it also supports dynamic method adding and more important a technique called swizzling. This is a tool that enables you to make detours from the original method, to your own, and back to the original. Exactly what I needed. Here I have to tell you, that I never programmed in objectiveC, I never even looked at objectiveC code. So this was completely new to me with no prior knowledge. All I had was the internet and Delphis own source code.

I put together something, that should in theory capture all touch calls in every UIView in the application, so that I could intercept all touch events in a single place. It looked ok, it compiled, but then it failed with exception in runtime when my detour methods were called. After a lot of documentation reading and experimentation I was no closer to a working solution and had no clue where I was making a mistake. So I tried to ask what is wrong on StackOverflow. But as it always happens when I ask a hard question, there was no answer. SO is great for mainstream simple questions, but ask a hard one and you can bet there will be no answer. It happened to me now to many times. The next step was to try official EMB forums. As I expected again no luck. As a last resort I turned to Marco Cantu for help. I saw they use this technique in one or two places in FMX code. So I hoped someone inside EMB could help with some advice. After all they would help the community this way. I received a fast reply from Marco who told me he will get my mail to the correct person inside.

Ok so I waited. But as there was no response I went back to my code. I am very persistent :) To shorten this, after a lot more digging around I found where the problem was. My parameters should be pointers and later converted to correct interfaces with “Wrapping”. Simple mistake, but hard to detect if you are not at home in objectiveC. From there on it was a smooth ride. I proved to myself it can be done. Let me show you how. You may find this useful to extend FMX code for iOS.

First you have to extend the original class with your own detour methods. Then you have to get both methods and finally you exchange their implementation. This is called swizzling.

constructor TTouchEventListener_IOS.Create;
var
  ViewClass: Pointer;
begin
  inherited;
 
  // get the UIView class
  ViewClass := objc_getClass('UIView');
 
  // get the touchesBegan and hook it
  class_addMethod(ViewClass, sel_getUid('touchesBeganDetour:withEvent:'), @touchesBeganDetour, 'v@:@@');
  touchesBeganOrig := class_getInstanceMethod(ViewClass, sel_getUid('touchesBegan:withEvent:'));
  touchesBeganRepl := class_getInstanceMethod(ViewClass, sel_getUid('touchesBeganDetour:withEvent:'));
  method_exchangeImplementations(touchesBeganOrig, touchesBeganRepl);
 
  class_addMethod(ViewClass, sel_getUid('touchesEndedDetour:withEvent:'), @touchesEndedDetour, 'v@:@@');
  touchesEndedOrig := class_getInstanceMethod(ViewClass, sel_getUid('touchesEnded:withEvent:'));
  touchesEndedRepl := class_getInstanceMethod(ViewClass, sel_getUid('touchesEndedDetour:withEvent:'));
  method_exchangeImplementations(touchesEndedOrig, touchesEndedRepl);
 
  class_addMethod(ViewClass, sel_getUid('touchesMovedDetour:withEvent:'), @touchesMovedDetour, 'v@:@@');
  touchesMovedOrig := class_getInstanceMethod(ViewClass, sel_getUid('touchesMoved:withEvent:'));
  touchesMovedRepl := class_getInstanceMethod(ViewClass, sel_getUid('touchesMovedDetour:withEvent:'));
  method_exchangeImplementations(touchesMovedOrig, touchesMovedRepl);
 
  class_addMethod(ViewClass, sel_getUid('touchesCancelledDetour:withEvent:'), @touchesCancelledDetour, 'v@:@@');
  touchesCancelledOrig := class_getInstanceMethod(ViewClass, sel_getUid('touchesCancelled:withEvent:'));
  touchesCancelledRepl := class_getInstanceMethod(ViewClass, sel_getUid('touchesCancelledDetour:withEvent:'));
  method_exchangeImplementations(touchesCancelledOrig, touchesCancelledRepl);
 
  {
  class_addMethod(ViewClass, sel_getUid('loadViewDetour:'), @loadViewDetour, 'v@:');
  loadViewOrig := class_getInstanceMethod(ViewClass, sel_getUid('loadView:'));
  loadViewRepl := class_getInstanceMethod(ViewClass, sel_getUid('loadViewDetour:'));
  method_exchangeImplementations(loadViewOrig, loadViewRepl);
  }
end;

Then you declare your own detour methods and write the implementation

procedure DoNotifyTouchEvent(const touches: NSSet;
                             const withEvent: UIEvent;
                             const EventType: TTouchEventType);
var
  I: Integer;
  Touch: UITouch;
  Event: TTouchEvent;
begin
  // do the event begin notify
  if TouchEventListener &lt;&gt; nil then
  begin
    SetLength(Event.Points, touches.allObjects.count);
    Event.EventType := EventType;
 
    // notify our global touch handler
    for I := 0 to touches.allObjects.count - 1 do
    begin
      Touch := TUITouch.Wrap(touches.allObjects.objectAtIndex(I));
      Event.Points[I].ID := Integer(touches.allObjects.objectAtIndex(I));
      Event.Points[I].Position.X := Touch.locationInView(Touch.View).x;
      Event.Points[I].Position.Y := Touch.locationInView(Touch.View).y;
 
      SetLength(Event.Points[I].History, 1);
      Event.Points[I].History[0].X := Touch.previousLocationInView(Touch.View).x;
      Event.Points[I].History[0].Y := Touch.previousLocationInView(Touch.View).y;
    end;
 
    TouchEventListener.Notify(Event);
  end;
end;
 
procedure touchesBeganDetour(self: id; _cmd: SEL; touches: Pointer; withEvent: Pointer); cdecl;
begin
  DoNotifyTouchEvent(TNSSet.Wrap(touches), TUIEvent.Wrap(withEvent), teDown);
end;
 
procedure touchesEndedDetour(self: id; _cmd: SEL; touches: Pointer; withEvent: Pointer); cdecl;
begin
  DoNotifyTouchEvent(TNSSet.Wrap(touches), TUIEvent.Wrap(withEvent), teUp);
end;
 
procedure touchesMovedDetour(self: id; _cmd: SEL; touches: Pointer; withEvent: Pointer); cdecl;
begin
  DoNotifyTouchEvent(TNSSet.Wrap(touches), TUIEvent.Wrap(withEvent), teMove);
end;
 
procedure touchesCancelledDetour(self: id; _cmd: SEL; touches: Pointer; withEvent: Pointer); cdecl;
begin
  DoNotifyTouchEvent(TNSSet.Wrap(touches), TUIEvent.Wrap(withEvent), teCanceled);
end;
 
procedure loadViewDetour(self: id; _cmd: SEL); cdecl;
begin
  UIView(TUIView.Wrap(self)).setMultipleTouchEnabled(True);
end;

This is basically all there is to it. I am not sure if I have to call the original methods explicitly. It seems they get called anyway. I suspect the “method_exchangeImplementations” takes care of that. You also have to enable multi-touch support for each view you use under iOS, as it is disabled by default. I tried to do that with hooking “loadView”, but I cannot get the method. This returns nil:

  loadViewOrig := class_getInstanceMethod(ViewClass, sel_getUid('loadView:'));

If anyone knows how the selector is correctly written let me know. For now you have to enable multi-touch for each form yourselves.

procedure TfMain.FormShow(Sender: TObject);
{$IFDEF IOS}
var
  V: UIView;
{$ENDIF}
begin
{$IFDEF IOS}
  V := WindowHandleToPlatform(Handle).View;
  V.setMultipleTouchEnabled(True);
{$ENDIF}
end;

Anyway I updated the demo and all the units on my blog. You can download the files from the same location as last time. No need for patching anymore. For iOS you now enable it the same way as you do for Android. There is still some work to be done on letting the use know which view or component fired the touch event and to distinguish between global and in-component coordinates. But you can also play with that yourselves. Maybe I will update the code some more, if there is enough demand. Windows implementation is not planned for now as I have no need for it and I have no Windows enabled multi-touch device. If there is interest and I am provided with the device I can try to support that to.

Multitouch

True multi-touch support for Delphi XE5

by Iztok Kacin in Coding

Recently I had a project where I had to somehow get the touch points for Android and IOS. I needed coordinates of all touch points at any time, with the correct event and movements. After a short research it turned out that Delphi XE5 has no such support. The internals of FMX framework does support that to some degree because it needs that to properly do multi-touch gestures. But that is of no help, because gestures are fired only when complete. Here I needed raw data to get the touch points or coordinates.

After seeing that there is no other way but to do it myself or to use another development tool, I decided I will do it myself. One afternoon later the support was done. I managed to support IOS and Android which is all I am interested in at the moment. Android is supported without any ugly hacks, but IOS needed a change of FMX.Platform.IOS, which is bad, but there is no other way. I just don’t understand why EMB choose to close the access to such important pieces of information. Under IOS there is no way to get that data, but to patch the FMX.Platform.IOS.

I have added the code to my SVN with the example that works on IOS and Android. But because I cannot distribute the Delphi source code I did not add FMX.Plarform.IOS. If EMB allows me to I will upload it, otherwise you are on your own there. I can only tell you how to do it yourselves.

To start using the code just add Cromis.Multitouch.Custom to uses clause and then declare the OnTouchEvent like this:

function TForm1.PointsToString(const Event: TTouchEvent): string;
var
  I: Integer;
begin
  Result := '';
 
  for I := 0 to Length(Event.Points) - 1 do
  begin
    if I = 0 then
      Result := Format('[%f:%f]', [Event.Points[I].Position.X,
                                   Event.Points[I].Position.Y])
    else
      Result := Result + ' ' + Format('[%f:%f]', [Event.Points[I].Position.X,
                                                  Event.Points[I].Position.Y]);
  end;
end;
 
procedure TForm1.OnTouchEvent(const Event: TTouchEvent);
begin
  lbMultiTouch.Items.BeginUpdate;
  try
    case Event.EventType of
      teDown: lbMultiTouch.Items.Add(Format('DOWN: %s', [PointsToString(Event)]));
      teMove: lbMultiTouch.Items.Add(Format('MOVE: %s', [PointsToString(Event)]));
      teUp: lbMultiTouch.Items.Add(Format('UP: %s', [PointsToString(Event)]));
    end;
  finally
    lbMultiTouch.Items.EndUpdate;
  end;
end;

And register it like this:

procedure TForm1.FormCreate(Sender: TObject);
begin
  InitializeTouchListener;
  TouchEventListener.AddHandler(OnTouchEvent);
end;

That is all there is to it. Be carefull because the events are global and not tied to any control on the screen. It just reports all the events in global coordinates. The event is a record:

  TTouchEventType = (teDown, teMove, teUp, teCanceled);
 
  TTouchPoint = record
    ID: Integer;
    Position: TPointF;
    History: array of TPointF;
  end;
 
  TTouchEvent = record
    Points: array of TTouchPoint;
    EventType: TTouchEventType;
  end;

So you get all the touch points and the event type. And for each point you have ID which stays the same when the same finger moves over the screen, the current position and the history of positions.

If anyone is interested how it was done, look at the source code for Android or ask here in the comments. You can download the code HERE or go to the Downloads page. Also note that I only used this code in one of my projects to solve the issues there. So there may be bugs in the code or the code may not work to you expectations. Please let me know how it works for you and if you need something that is not there.

EDIT:

For those that wish to patch the IOS code do the following:

  • Make a copy of FMX.Platform.IOS and put it somwhere where you can then use it in the uses clause. Just make sure its on the search path
  • Under implementation section add Cromis.Multitouch.Custom
  • Search for these  in the TFMXViewBase:
procedure touchesBegan(touches: NSSet; withEvent: UIEvent); cdecl;
procedure touchesCancelled(touches: NSSet; withEvent: UIEvent); cdecl;
procedure touchesEnded(touches: NSSet; withEvent: UIEvent); cdecl;
procedure touchesMoved(touches: NSSet; withEvent: UIEvent); cdecl;
  • In each of them add this as the first thing after begin and try. Use appropriate event type for each one. teMove is for touchesMoved.
DoNotifyTouchEvent(touches, withEvent, teMove);
  •  The procedure looks like this:
procedure TFMXViewBase.DoNotifyTouchEvent(touches: NSSet; withEvent: UIEvent; const EventType: TTouchEventType);
var
  I: Integer;
  Touch: UITouch;
  Event: TTouchEvent;
begin
  // do the event begin notify
  if TouchEventListener <> nil then
  begin
    SetLength(Event.Points, touches.allObjects.count);
    Event.EventType := EventType;
 
    // notify our global touch handler
    for I := 0 to touches.allObjects.count - 1 do
    begin
      Touch := TUITouch.Wrap(touches.allObjects.objectAtIndex(I));
      Event.Points[I].ID := Integer(touches.allObjects.objectAtIndex(I));
      Event.Points[I].Position.X := Touch.locationInView(UIView(Super)).x;
      Event.Points[I].Position.Y := Touch.locationInView(UIView(Super)).y;
 
      SetLength(Event.Points[I].History, 1);
      Event.Points[I].History[0].X := Touch.previousLocationInView(UIView(Super)).x;
      Event.Points[I].History[0].Y := Touch.previousLocationInView(UIView(Super)).y;
    end;
 
    TouchEventListener.Notify(Event);
  end;
end;

That is all. I am currently looking for some way to do it without changing this unit as I got some fresh ideas. But I will see if it can be done. I have no deep knowledge of objectiveC. I have almost no knowledge in fact :)

Developers Environment: Part 1 – Network Attached Storage

by Iztok Kacin in Coding, Developing

Disclaimer

Please note that this series of articles is not based on any scientific fact sheet and I do not claim that my view of things is the correct one. Also I am not coercing anyone into anything. I am merely sharing my view on setting up a development environment. You are invited to disagree and debate it, but please do that in a civilized manner. I want no flame wars.  :)

Preamble

We usually talk a lot about code and tools we use, to make that code and maintain it. We talk a lot about different OS and cross platform and how all that impacts our code. We talk about code-bases and portability, we talk about code formatting and code quality. We talk about patterns and algorithms and data structures.

We talk about a lot of things, but rarely I see that we talk about our technical environments which enables us to develop code in the first place. And environments go beyond that. They store our personal data, host our operating systems, stream media and do a lot of other things not directly related to development. But if there is no environment there is no development. And good environment is critical to good, fast, efficient and quality development. If the environment is not optimized then you will spend more time developing because you are preoccupied with small and larger tasks in order to develop, that you are not supposed to do in a properly set environment. Good environment is there without you even knowing it, it does not get in your way and on the other hand keeps your data safe and enables you to work in a higher gear.

I wanted to write about this for a long time. I will make a series of articles about my environment because I feel it has matured over the years, into something that is a very good environment for serious development. Writing about it I can present it in a fashion that also covers the general approach to setting up a good environment.

Environment parts

If I first look at the development environment as a collection of logical parts then I would describe it as:

  • Storage units
  • Processing units
  • Display units
  • I/O units
  • Networking units
  • Supporting HW

Maybe I could include something more or leave something out. But from the developers perspective this list should cover the major parts. Lets say your environment is a minimal one. This could be a single computer and so I could then assign the HW parts to the logical parts from the list:

  • Storage units: HDD
  • Processing units:  The CPU
  • Display units: One or more monitors
  • I/O units: Keyboard, mices, optical drives, USB devices etc…
  • Networking units: The ethernet card
  • Supporting HW: Maybe just a printer, or nothing

I will start with the Storage units because I feel it can be one of the most diverse and complicated parts and on the other hand it is very important for development and for other parts of the computing environment. It holds all the permanent data (By storage I meant hard drives, solid state drives, any permanent storage. This does not include RAM and other volatile storage).

Your storage sytem can be a simple HDD in your computer. But not only that is not convenient, as I will show later, it is also not safe if you not backup it regularly, or you do not have a RAID 1 array or something similar done. I intend to talk about NAS here and why it is so good, that you should always use it, if you have a chance.

Network Attached Storage

ad_1

Hard drives and computer parts in particular are not reliable. I have seen to many people rely blindly on their hard drives not even once thinking they can fail. And they do fail. And they failed in some of that cases resulting in years of work and personal data lost. I have seen an executive in a big firm loosing 7 years of data because in 7 years he never made a single backup. Sad, but true. But that is not the point of this article. Developers know that and they do backups.

YOU DO BACKUP YOUR DATA DON’T YOU?

The point here is NAS storage. Wikipedia says this:

“Network-attached storage (NAS) is file-level computer data storage connected to a computer network providing data access to a heterogeneous group of clients. NAS not only operates as a file server, but is specialized for this task either by its hardware, software, or configuration of those elements. NAS is often manufactured as a computer appliance – a specialized computer built from the ground up for storing and serving files – rather than simply a general purpose computer being used for the role.

 The advantages I see in NAS are:

  • One point where all the data from all your systems is stored
  • Centralized storage means easier backups and easier security and safety of data
  • Different operating systems can access it seamlessly over SAMBA
  • You can abstract your data away from your computers meaning you can make your data “portable”

Cons are in my view:

  • NAS is single point of failure if there is no redundancy (and in home environments there usually is none)
  • You need some expertise to set it up yourself if you do not use premade NAS boxes
  • Even on gigabit network there is slower data transfer then from local drives

But in my mind there is no doubt, pros are so big, and I talk from practice, that they far outweighs the cons. And if you do backups then you still have data if the main NAS fails.

A good NAS setup

I would like to present in my opinion a good NAS setup consisting of two NAS servers. You can substitute one server with remote location storage or with local external drive or something similar. Important thing here is that there are no definitive correct solutions. There are better and worse solutions,  each solution has its cons and pros but there may be many viable solutions. This not only applies to NAS but to the development environment as a whole. So do not take my words as sacred, or as the only correct setup. Take them just for what they are. Only one of the possible solutions, but that I happen to use :)

I have two physical boxes for storage. Here I could replace them with virtual boxes, but I choose not to for two reasons

  1. I want good NAS performance and the VM server I use already has enough VMs use for other purposes
  2. Those two boxes need to be as far apart as possible in case of some disaster. We want one of them to survive.

Those two boxes are nothing special. One is custom made with a celeron and 12 GB RAM (because I use ZFS and it eats RAM like candy) and a bunch of drives, with 3 of them in ZFS (equivalent of RAID 5). So this box has the exact setup like this

  1. Dual core celeron
  2. Cheap motherboard
  3. 12 GB RAM
  4. 3x 1.5 TB drives in ZFS
  5. 1x 320 GB drive for sharing, torrents and other temporary stuff
  6. 8GB USB strick for FreeNAS setup (the OS)

The other box is a HP microserver bought recently:

HP_ProLiant_MicroServer

and the interior

HP-MicroServer

 

It is a turion based server with 2GB ram and 4 HD slots. I then put in 4x 3TB drives and made 2x RAID 1 array out of that 4 drives which nets a total of 6TB. Now you may ask what the heck I need all that space for and why 2 servers. Well the first server is my primary NAS, that Is why a lot of RAM. It is is faster then the HP. It also has RAID 5 which is fast for reads but is not so reliable. If your HD RAID fails or your SW RAID fails you may loose the data. It happened and it will happen again. You cannot rely on your RAID 5 to be bullet proof.

While the first server is a NAS workhorse with all the active data, the second one (HP), is slower and has less RAM. But it uses less power, is quieter and has way more storage. This one is for archiving and for the timeline incremental backups of active data. For each there is 3TB space available. And while you think that that is way to much free space I can tell you I have a lot of data, also weekly whole VM backups take a lot of space. Storage is cheap these days and the need for space will only increase. This way I am covered for the near future. Also I work from home, so this is basically my office setup and home setup in one. Additionally my wife’s parents also use the same NAS for backups and data.

It may seem an overkill but in my opinion it is not. You can make NAS server very cheaply and if you pay attention it will consume very little power. For me data safety has no price, more so in these days, that everything is moving to digital distribution. Movies, music, books, mails, IM history, code, photos etc…

I would like to point out that there are a lot of combinations, by which you can set this up (all assume that you have a primary NAS).

  • online cloud backup for backup system
  • external HD drive for backup system
  • backup system is an additional drives array, in the same NAS box
  • VM as a secondary backup system
Wrap up

I think I was long enough for the first post in the series. In the next one I will look into actual software and solutions that I use for those two servers and the HW that uses them. I hope I told something new or interesting at least for some of you out there. Developers can be a tough audience. Anyway I think it is good to talk a little broader from time to time. If you have questions about this article or wishes for the next ones, please do drop a comment.

 

Library and site updates…

by Iztok Kacin in Coding

After being quiet for quite some time (but extremely busy), I am now posting updates about what is new in the “Cromis Library” and on the page itself.

Page updates

In the past I already worked with TRAC, a great open source project management tool written in Python. I fiddled with it a little, even used it for one of my internal projects, but that was more or less it. Now after a few years, I upgraded my Debian VM, where the blog runs and decided that I upgrade and use TRAC again. So I put up a project management for “Cromis Library”. It features:

You can find the page here: http://www.cromis.net/trac/cromis. It is also accessible from the blog top navigation under “DOCS”. Why did I decide to do this? Well I want to run my projects in a more structured manner. Yes, I write them in my spare time and when I can, but that does not mean, I can’t have a road-map, a ticket system and a forum. It took me very little time to set up and I think I will benefit from it. Also the users of “Cromis Library” will have a lot of info at hand. More and more people use my library and I get a lot of e-mails regarding how to use something, etc… Lots of content in these e-mails  is overlapped and I think its a shame, that the content is not available online. As of now it is! Furthermore I will benefit from bug tracking tickets and from tasks that I will assign to myself. This way I have a clear picture what I intend to do and how are things progressing. But please do not take the road-map as sacred. After all I have a family and a job among other things and I will update the road-map and change dates if needed.

The documentation is currently not there yet, but it will dribble in slowly. Also the code, is for reasons I will not discuss here right now, not ultra clean and organized at that moment. But downloads are always stable snapshots when they are made. This means that using SVN code directly, is being on the bleeding edge.

I am open to criticism, suggestions and most of all participation on the site itself. Welcome to it :)

Library updates

  1. Cromis.IPCBoth IPC and IMC went through some serious redesigns, to allow further code development and to incorporate new features. All the changes are listed on the download page, I will sum here
    • New events have been added, OnClientConnect, OnClientDisconnect, OnServerError
    • Improved error handling and notifications, especially the server side
    •  Unit renamed to Cromis.Comm.IPC
    • Server now holds a list of connected clients
    • Clients can specify their class that holds the data for each client
  2. Cromis.IMC - Similar changes as IPC
    • New events have been added, OnClientConnect, OnClientDisconnect, OnServerError
    • Improved error handling and notifications, especially the server side
    •  Unit renamed to Cromis.Comm.IMC
    • Server now holds a list of connected clients
    • Clients can specify their class that holds the data for each client
    • Exposed bindings for TCP server
  3. Cromis.Scheduler - Scheduler has been optimized and new funcionality has been added
    • LastEvent propery for schedule
    • OnScheduleAdd and OnScheduleRemove handlers added to events list
    • stQueue added as signal type, this allows more modern approach then Sychronize
    • Improved thread stopping and freeing
  4. Cromis.AnyValue - Very important change here. Safe mode code has been added, that does not use hooks. Under x64 it is automatically enabled and under x86 you can enable it if you fear for the stability. But do not worry it is rock solid anyway :)
    • “AnyValue_HookingOn” and “AnyValue_HookingOff” defines added
    • Under x64 automatically swithces to safe mode. Manual control over hooking

Here I would like to appeal for help.  Cromis.AnyValue uses System.pas hooks to be as fast as it is and as memory efficient. But that means, I have to use Cromis.Detours. And while it is rock solid under x86, the code it is not x64 safe. Although it works just fine in my tests, that does not mean it will work fine anywhere. I lack the assembler knowledge to make it x64 safe and I also lack time to do so. So if any of you has the skills and want’s to help, I will be more then happy and that person will have my eternal gratitude :)