Replacing FUNCky FSetTime FSetDate for low level File control

Public support forum for peer to peer support with related to the Visual Objects and Vulcan.NET products
Post Reply
User avatar
Neil
Posts: 11
Joined: Tue Mar 15, 2016 10:15 pm

Replacing FUNCky FSetTime FSetDate for low level File control

Post by Neil »

I have a large project that I am looking at Xsharp for but starting on some of the smaller utilities. All in VO 2.8b4

One of the issues I face is replacing some FUNCky functionality that I need to either rewrite into VO/X# in both is better to have less to deal with on the VO Converter for the next project so something like their old NumTokens is really just Occurs( ). I'm planning to rewrite most of the other string manipulation functionality I need like Token functionality that I need and Julian date handing, but the lowlevel file function is the challenge that I might have to consider an external DLL in C/C++/C#

But the things I'm looking at are dealing with low level file access. As part of what has been used and still required to be done is to manipulate the file date/time stamps. It's s simple check that was done for speed to not call an index( ) on a DBF on startup if we don't need to, so we set the .IDX file date/time to match the DBF.

Has anyone made X# versions of some of these or plans to add to the core language?

Thanks,
Neil
User avatar
wriedmann
Posts: 3644
Joined: Mon Nov 02, 2015 5:07 pm
Location: Italy

Replacing FUNCky FSetTime FSetDate for low level File control

Post by wriedmann »

Hi Neil,
the .NET Framework itself is the largest function library ever.
Please have a look here:
https://docs.microsoft.com/en-us/dotnet ... mework-4.8
Wolfgang
P.S. if you need to use X# libraries in VO applications you could have a look here: https://docs.xsharp.it/doku.php?id=com_module_sample
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am

Replacing FUNCky FSetTime FSetDate for low level File control

Post by Karl-Heinz »

Hi Neil,

In VO you can use the function SetFDateTime(). The same function is also available in X#.

https://www.xsharp.eu/runtimehelp/html/ ... teTime.htm

regards
Karl-Heinz
User avatar
Neil
Posts: 11
Joined: Tue Mar 15, 2016 10:15 pm

Replacing FUNCky FSetTime FSetDate for low level File control

Post by Neil »

Hi Neil,
the .NET Framework itself is the largest function library ever.
Please have a look here:
docs.microsoft.com/en-us/dotnet/api/syst...iew=netframework-4.8
Wolfgang
P.S. if you need to use X# libraries in VO applications you could have a look here: docs.xsharp.it/doku.php?id=com_module_sample
Thanks. I didn't really want to try to play with .Net inside VO. I've created some C# libs and tied into VO before and it can be "fun". But definitely appreciate the pointer as I might do this as a temporary thing to help and would convert easier.

FWIW...
I have come across some things in 26 year old code that was migrated from Clipper to Clip4Win to VO... I just found a function written that reads INIs to get section headers via fOpen and locating "[" instead of just using built in GetPrivateProfileString with a NULL... so it's a task of figuring out what the original code was trying to do and that some now basic functionality didn't exist back then, some of this code should've been redone at least 20 years ago. :lol:

Thanks,
Neil
User avatar
Neil
Posts: 11
Joined: Tue Mar 15, 2016 10:15 pm

Replacing FUNCky FSetTime FSetDate for low level File control

Post by Neil »

In VO you can use the function SetFDateTime(). The same function is also available in X#.
Thanks Karl-Heinz , I just found this after Wolfgang's reply and checked X# help B) . The problem with using some of the old library methods was as far as I can deduce the last luncky was built with VC6, so has no awareness of modern file access (SMB1 vs SMB2 even), at least VO 2.8 is closer and this will be a no brainer to use for the next conversion run.

Thanks for the direct function name.
-Neil
User avatar
Neil
Posts: 11
Joined: Tue Mar 15, 2016 10:15 pm

Replacing FUNCky FSetTime FSetDate for low level File control

Post by Neil »

I was going to write that I'll have to try something else in VO for now as it still wasn't working in VO. Haven't tried X# yet.

This reply is now for anyone having the same issue I did with VO's function to be ready for X# just passing on that I realized was a core VO bug. aka "share what you learned".

SetFDateTime() doesn't seem to quite work in VO.
DBF was
04/04/2019 | 15:50:58

Index before calling it SetFDateTime
08/27/2021 | 01:24:24

it sets the date but not the time
04/04/2019 | 15:51:52

At first I thought it was not doing it at all since I have so over 200 index files of various create/last write date/time when I look at my logs I noticed something odd, that it seemed to double the seconds and a little math shows that the :58 from the above was being doubled when taken into account

Desired :08/20/2020|18:49:08
Written :08/20/2020|18:49:16

Desired :08/27/2021|02:08:10
Written :08/27/2021|02:08:20

I found Karl-Heinz's thread for his creation of SetFDateTime( ) in X# https://www.xsharp.eu/forum/public-product/1264-setfdatetime-is-missing#9155
And was clearly the modern way, but VO was Win32API, so I I do believe X# would be fine but I noticed that the system library implementation in VO has some visible code for SetFDateTime( )

After reading more and more into the VO win32 help file and MS online docs. I noticed that the system library implementation in VO has a flaw,
it had

Code: Select all

		nHour   := Val( SubStr3(cTime, 1,2) )
		nMinute := Val( SubStr3(cTime, 4,2) )
		nSecond := Val( SubStr3(cTime, 7,2) ) 
but based on DosDateTimeToFileTime ( ) should've been seconds halved.

Code: Select all

wFatTime - 
Specifies the MS-DOS time. The time is a packed 16-bit value with the following format:

Bits        Contents
0-4     Second divided by 2
5-10    Minute (0-59)
11-15   Hour (0-23 on a 24-hour clock)
 
		nHour   := Val( SubStr3(cTime, 1,2) )
		nMinute := Val( SubStr3(cTime, 4,2) )
		nSecond := Val( SubStr3(cTime, 7,2) ) /2
so indeed the seconds we being doubled as the seconds we not being halved.
Made my own version of the VO sys that I can easily excise it later after conversion instead of a project that calls X# outside of itself unnecessarily.


Regards,
Neil
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am

Replacing FUNCky FSetTime FSetDate for low level File control

Post by Karl-Heinz »

Hi Neil,

In the X# version of SetFDateTime() the seconds problem doesn't exist. With VO, try this modified SetFDateTime().

Code: Select all

FUNCTION SetFDateTime(cFile AS STRING, d AS DATE, cTime AS STRING) AS LOGIC PASCAL
	LOCAL struFT IS _WINFILETIME   
	LOCAL struST IS _winSYSTEMTIME
	LOCAL lRet      AS LOGIC
	LOCAL hf        AS PTR
	LOCAL cDate     AS STRING
	LOCAL nHour     AS WORD
	LOCAL nMinute   AS WORD
	LOCAL nSecond   AS WORD
	LOCAL nYear   AS WORD
	LOCAL nMonth  AS WORD
	LOCAL nDay    AS WORD

	hf := FOpen2(cFile, OF_READWRITE)

	IF hf != F_ERROR
		IF d == NULL_DATE
			d := Today()
		ENDIF
		cDate  := DToS(d) 
	
		nYear  := Val( SubStr3(cDate, 1,4) ) 
		nMonth := Val( SubStr3(cDate, 5,2) )
		nDay   := Val( SubStr3(cDate, 7,2) ) 
		
		struST.wYear := nYear
		struST.wMonth := nMonth
		struST.wDay := nDay


		IF Secs(cTime) == 0
			cTime := Time()
		ENDIF

		nHour   := Val( SubStr3(cTime, 1,2) )	
		nMinute := Val( SubStr3(cTime, 4,2) )          
		nSecond := Val( SubStr3(cTime, 7,2) )  
		
		struST.wHour := nHour
		struST.wMinute := nMinute
		struST.wSecond := nSecond


  		IF SystemTimeToFileTime(@struST, @struFT) 

			IF LocalFileTimeToFileTime(@struFT, @struFT)
				
				lRet := SetFileTime(hf, NULL_PTR, NULL_PTR, @struFT)
				
			ENDIF
			
  		ENDIF
  		
		FClose(hf)
		
	ENDIF

	RETURN lRet
BTW. I tried your approach of dividing the seconds by 2. Are you aware that this doesn´t help if you want to set odd seconds like "00:02:11"?

regards
Karl-Heinz
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am

Replacing FUNCky FSetTime FSetDate for low level File control

Post by Karl-Heinz »

In Germany we say 'no answer is also an answer' ;-)

My earlier posted modified VO function SetFDateTime() doesn´t work properly when the datetime to set is either inside the range of the summer- or wintertime. Here is a modified SetFDateTime() that distinguishes whether a summer or winter time is used - at least I hope so. What´s missing in VO is the declaration of the required win api function TzSpecificLocalTimeToSystemTime(). Just run this code with a valid file. i ´m not sure, but do you see the expected dates and always the same time stamp "14:00:01" ? About the used GetFDateTime() function: Such a function doesn´t exist in VO, but i created it to verify the written datetime stamp.

Just to be clear: That´s plain VO code ;-)


Code: Select all

_DLL FUNC TzSpecificLocalTimeToSystemTime(lpTimeZoneInformation AS _WINTIME_ZONE_INFORMATION,;
	lpLocaltime AS _winSYSTEMTIME,;
	lpUniversalTime AS _WINSYSTEMTIME);

FUNCTION Start()
LOCAL cTime, cFile AS STRING
LOCAL dDate AS DATE

cFile := "c:testAnsi.txt"     

? SetFDateTime(cFile , ConDate ( 2020 , 6 , 12 ), "14:00:01")   // datetime is inside the summer time 
? GetFDateTime ( cFile , @dDate , @cTime ) 
? dDate , cTime

? SetFDateTime(cFile , ConDate ( 2020 , 12 , 12 ), "14:00:01")  // datetime is inside the winter time
? GetFDateTime ( cFile , @dDate , @cTime ) 
? dDate , cTime


FUNCTION SetFDateTime(cFile AS STRING, d AS DATE, cTime AS STRING) AS LOGIC PASCAL
	LOCAL struFT IS _winFILETIME   
	LOCAL struLocalST, struST IS _winSYSTEMTIME
	LOCAL lRet      AS LOGIC
	LOCAL hf        AS PTR
	LOCAL cDate     AS STRING


	hf := FOpen2(cFile, OF_READWRITE)

	IF hf != F_ERROR
		IF d == NULL_DATE
			d := Today()
		ENDIF
		cDate  := DToS(d) 
	
	
		struLocalST.wYear := Val( SubStr3(cDate, 1,4) )  
		struLocalST.wMonth := Val( SubStr3(cDate, 5,2) ) 
		struLocalST.wDay := Val( SubStr3(cDate, 7,2) )  


		IF Secs(cTime) == 0
			cTime := Time()
		ENDIF

		
		struLocalST.wHour := Val( SubStr3(cTime, 1,2) )	 
		struLocalST.wMinute := Val( SubStr3(cTime, 4,2) )   
		struLocalST.wSecond := Val( SubStr3(cTime, 7,2) )    
		
		
		IF TzSpecificLocalTimeToSystemTime( NULL_PTR , @struLocalST , @struST ) 
		
			IF SystemTimeToFileTime(@struST, @struFT) 
		
				lRet := SetFileTime(hf, NULL_PTR, NULL_PTR, @struFT)
		
		   ENDIF 
		   
		ENDIF
				

		FClose(hf)
		
	ENDIF

	RETURN lRet


FUNCTION GetFDateTime ( cFile AS STRING ,dDate REF DATE , cTime REF STRING ) AS LOGIC PASCAL 
LOCAL struFindData IS _winWIN32_FIND_DATA 
LOCAL struST, struSTLocal IS _winSYSTEMTIME
LOCAL hFile AS PTR
LOCAL lOK AS LOGIC
  

	IF ( hFile := FindFirstFile( String2Psz ( cFile ) , @struFindData) )  != INVALID_HANDLE_VALUE
		
		
		IF FileTimeToSystemTime ( @struFindData.ftLastWriteTime , @struST )   
			
	
			IF SystemTimeToTzSpecificLocalTime ( NULL_PTR , @struST , @struSTLocal )
				
				lOK := TRUE
				 
	 			dDate := ConDate( struSTLocal.wYear, struSTLocal.wMonth, struSTLocal.wDay )
 			 			
				cTime := ConTime ( struSTLocal.wHour , struSTLocal.wMinute , struSTLocal.wSecond ) 
          
			ENDIF 
		
		ENDIF      			
		
	
		FindClose ( hFile ) 		
		
	ENDIF 	
 
 	
 	RETURN lOK  
No matter if you are interested on this topic: Still happy VOing / X#ing - and especially VFPing::-)


regards
Karl-Heinz
User avatar
Neil
Posts: 11
Joined: Tue Mar 15, 2016 10:15 pm

Replacing FUNCky FSetTime FSetDate for low level File control

Post by Neil »

Thanks! I haven't had a chance to get back into testing it. But plan to.
My old code was able to set the seconds properly as it was via the FUNCky library not in VO itself, but I had also had encountered some systems that couldn't set the date/time at all so it was clear that these needed to be updated.

for quick conversion I was doing the quick VO way to get the date and time. I had creating surface functions as so many usages wanted a string data type back and wanted to not disturb the dust in some of these places to change data types to match (at least for now)

Code: Select all

func _fGetTime( sFileName as STRING ) as STRING 
	local sRet as  STRING
    
	if ( FFirst( sFileName, FC_NORMAL ) )
		sRet := FTime( )
	else
		sRet := ""
	endif		

    return sRet

//////////////
func _fGetDate( sFileName as STRING ) as STRING 
	local sRet as  STRING
    
	if ( FFirst( sFileName, FC_NORMAL ) )
		sRet := Dtoc( FDate( ) )
	else
		sRet := ""
	endif		
				
    return sRet



But I might switch to something close to yours (or yours) just because it's using the same API not the VO version of them

I do appreciate the followup.
Post Reply