Thanks for a link, dreammanor. That can be very usefull for vb6 developers. As for me - for my projects I have my own private framework lib called FLib, just did not share it yet because guess it will not be something new.
For FTypes I really can note that core idea was to bring some kind of VB.NET style. Of course only for base data types - no filesystem, registry or other routines that are not part of project mainstream.
P.S. Will be glad to have a feedback or maybe get reports of some issues in FTypes. Project is and will be supported and extended Thinking about ArrayEx subtype called ListEx for single-dimensioned arrays only ...
Here's a thought for the StringEx class: Expand the Case options to include more than just Upper and Lower. Other common case types I regularly use are: Sentence Case, Title Case and less frequently CamelCase, snake_case, kebab-case. See this Wikipedia entry on the various options: https://en.wikipedia.org/wiki/Letter_case#Sentence_case
So here's a proposed list of case related methods:
touppercase
tolowercase
tosentencecase
totitlecase
tocamelcase
tosnakecase
tokebabcase
I know that the last three are a bit less common but i include them primarily for completeness.
Thanks for sharing. I haven't used it yet, but it looks pretty good, especially ArrayEx and StringEx. When I have time, I'll test it.
I have seen a MinFrameWork(Vibian) on PsCode. It is a simple but powerful COM library for VB6 which emulates/bring some VB.NET functions. Here is its link, may be helpful to you and others: http://www.planet-source-code.com/vb...01715423264095
I guess maybe someone will use VB6 to simulate all .NET class libraries. That would be a very interesting thing.
Here's a thought for the StringEx class: Expand the Case options to include more than just Upper and Lower. Other common case types I regularly use are: Sentence Case, Title Case and less frequently CamelCase, snake_case, kebab-case. See this Wikipedia entry on the various options: https://en.wikipedia.org/wiki/Letter_case#Sentence_case
So here's a proposed list of case related methods:
touppercase
tolowercase
tosentencecase
totitlecase
tocamelcase
tosnakecase
tokebabcase
I know that the last three are a bit less common but i include them primarily for completeness.
Hey. Thank for extension ideas. That is not going to overload a project, opposite - direct enhancment.
VS6 with SP& return: "Unable to set component compatible with version: ...\bin\dll\FTypes.dll". It's right? What's wrong?
You need to open FTypes project properties and go to "Component" tab. Within "Version Compatibility" settings enable "No compatibility" option. Do save. Compile project. Go back to settings and now choose "Binary Compatibility" and set appropriate path to just compiled DLL.
You might want to add support for Enumeration (IEnumVARIANT) to your ArrayEx class.
I believe Olaf posted an example using a lightweight COM Objects. I also can post an example, but it requires a typelib for IEnumVARIANT, and patching an interface pointer.
You might want to add support for Enumeration (IEnumVARIANT) to your ArrayEx class.
I believe Olaf posted an example using a lightweight COM Objects. I also can post an example, but it requires a typelib for IEnumVARIANT, and patching an interface pointer.
Thank you. You are welcom to post it ) I thought about enum. Yet I have a solution of .ForEach (not included into project) that requires a pointer to a custom function (callback) in a module. But I do not like this actually.
You're going to need some sort of callback to implement an Enumerator Class. That's kind of what the IEnumVARIANT interface is. I've attached my implementation, which is adapted from .NET.
It uses my typelib, to provide the interface definitions, and pointer functions.
In the example project, the enumerator class must implement IEnumerator. I use an Enumerator class that wraps IEnumerator, and implements IEnumVARIANT. That class that also patches IEnumVARIANT::Next with a static function so that it can return S_FALSE to end the enumeration.
If you were going to add this to your lib, you would have to expose an IEnumerator type of interface/callback as well. The actual implementation of IEnumVARIANT however would need to be done by a lightweight com object, or using a typelib assisted approach.
edit: actually you wouldn't need to expose the IEnumerator interface unless you wanted to allow users to also piggyback on your implementation, with their custom enumerators. You wouldn't even need an IEnumerator interface, you could implement IEnumVARIANT directly on ArrayEX allowing you For Each on your array class, without cluttering up your object model. You don't even need a seperate class to do the enumeration, just put it all in ArrayEx.
(feel free to decompile the typelib using OLE Viewer. I haven't released the source due to the fact that some of the assisting files are copyright MS)
edit2: I believe this can be done without any typelib, so I'll post an example you can adapt when I get a chance.
Last edited by DEXWERX; Oct 25th, 2017 at 07:03 AM.
Here's a minimal implementation of a custom Enumerator that enables the use of For Each in VB6 without a typelib. I created a Light Weight COM Object. I'll post a full implementation to the code bank at some point, but this should be enough to get you started.
You're Enumerable object (ArrayEx for example) must have a NewEnum function with the Dispatch ID set to -4 (DISPID_NEWENUM)
1) Paste this function into ArrayEx:
Code:
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' IEnumerable
Public Function GetEnumerator() As IEnumVARIANT
' The ProcedureID must be set to -4 (DISPID_NEWENUM)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Set GetEnumerator = NewEnumerator(Me, Length - 1, 0)
End Function
2) Put your edit cursor in the function
3) Click the menu "Tools-->Procedure Attributes..."
4) Make sure it says "Name: GetEnumerator"
5) Click Advanced>>
6) Put -4 for the Procedure ID.
7) Click OK
8) Add the following Module.
NOTE: the IEnumVARIANT_Next() calls your enumerable collection's default property with an Index value, so make sure the default property is set, or adapt the method to properly grab your object's value by Index.
Here's a minimal implementation of a custom Enumerator that enables the use of For Each in VB6 without a typelib. I created a Light Weight COM Object. I'll post a full implementation to the code bank at some point, but this should be enough to get you started.
Thank you DEXWERX. That is exactly what I need) Sorry - I mentioned your post here only yesterday - somehow did not get email notification =(.
1.9.2 versioon of FTypes will include your implementation.
Project sources are now located at GitHub (https://github.com/hwoarang84/FTypes). Source code here won't be updated any more. See all related links at the begining of the thread.
It looks like you're really trying to make some classes that'll be useful under certain circumstances. I just took a look at your latest source code. Didn't try to run it because of some DLL it needed, but I still perused it.
One thing I noticed was the occasional use of "On Error Resume Next". I certainly use that occasionally, but I've learned to always terminate a block using it with "On Error Goto 0". The reason for this is that the Err object is left "dirty" if you get an error. Here's an example of what I mean:
Just throw into Form1:
Code:
Option Explicit
Private Sub Form_Load()
test1
MsgBox Err
End Sub
Sub test1()
On Error Resume Next
Dim a As Long
a = 1 / 0
End Sub
If a procedure higher up the call chain is monitoring for possible errors (possibly also using On Error Resume Next), returning from one of your procedures with an error set can cause havoc.
For instance, here are a couple of procedure where I use it:
Code:
Public Function NaN() As Double
' Math can be done on these, but nothing changes.
' They can NOT be used in "if NaN = NaN Then", or an overflow will result.
On Error Resume Next
NaN = 0 / 0
On Error GoTo 0
End Function
Code:
Public Function IsDimmedLng(TheArray() As Long, Optional FailOnZeroNegOne As Boolean = True) As Boolean
On Error Resume Next
If FailOnZeroNegOne Then ' Some arrays can be 0 to -1.
IsDimmedLng = (LBound(TheArray) <= UBound(TheArray)) ' Will error (leaving IsDimmedLng = False) if not dimensioned.
Else
IsDimmedLng = (LBound(TheArray) = LBound(TheArray)) ' Will error (leaving IsDimmedLng = False) if not dimensioned.
End If
On Error GoTo 0
End Function
As you can see, I've actually gotten into the habit of indenting between an "On Error Resume Next" and "On Error Goto 0" block. Also, I must mention that Bonnie West was who brought this to my attention a while back.
Also, if you're looking for more enhancements, how about adding the LongLong type, and also adding your bit-shifting to both the Decimal and LongLong type. Also, bit-shifting in the Currency will be useful to some.
Swapping Endianness may also be useful to some people. This could apply to any of the types (excluding Strings and Bytes, I suppose).
Best Regards,
Elroy
EDIT1: Also, some other ideas would be a SafeMult and SafeDiv, possibly returning NaN if it fails. Also, adding the NaN may be a good idea, but that'll only be available for Singles and Doubles. I've also got an IsNaN function...
Code:
Public Function IsNan(v As Variant) As Boolean
' This is just for "Single" and "Double" IEEE floating point.
Dim iType As Long
Dim s As String
iType = VarType(v)
If iType <> vbSingle And iType <> vbDouble Then Exit Function
s = CStr(v)
If InStr(s, "#IND") Or InStr(s, "#QNAN") Or InStr(s, "#SNAN") Then IsNan = True
End Function
Public Function IsInfinity(v As Variant) As Boolean
' This is just for "Single" and "Double" IEEE floating point.
Dim iType As Long
Dim s As String
iType = VarType(v)
If iType <> vbSingle And iType <> vbDouble Then Exit Function
s = CStr(v)
If InStr(s, "#INF") Then IsInfinity = True
End Function
Also, another idea that comes to mind for Longs (and LongLongs if you implement them), is an UnsignedAdd. Many might call this a PtrAdd. It would effectively treat a Long (and LongLong) as unsigned.
EDIT2: Also, if it were me, I'd tend to build Array options into each one of them. Here's an example where I've recently done that with a UDT:
Code:
Option Explicit
'
Dim VecArray() As VecType
Dim TheLabel As String
'
Friend Function Count() As Long
Count = UBound(VecArray) - LBound(VecArray) + 1
End Function
Friend Function LoBound() As Long
LoBound = LBound(VecArray)
End Function
Friend Function HiBound() As Long
HiBound = UBound(VecArray)
End Function
Friend Property Get Label() As String
Label = TheLabel
End Property
Friend Property Let Label(sLabel As String)
TheLabel = sLabel
End Property
Friend Function IsDimmed() As Boolean
On Error Resume Next
IsDimmed = (LBound(VecArray) <= UBound(VecArray))
On Error GoTo 0
End Function
Friend Sub RedimData(lo As Long, hi As Long)
ReDim VecArray(lo To hi)
End Sub
Friend Sub EraseData()
Erase VecArray
End Sub
Friend Property Get Frame(i As Long) As VecType
Frame = VecArray(i)
End Property
Friend Property Let Frame(i As Long, vec As VecType)
VecArray(i) = vec
End Property
Friend Property Get X(i As Long) As Double
X = VecArray(i).X
End Property
Friend Property Let X(i As Long, X As Double)
VecArray(i).X = X
End Property
Friend Property Get Y(i As Long) As Double
Y = VecArray(i).Y
End Property
Friend Property Let Y(i As Long, Y As Double)
VecArray(i).Y = Y
End Property
Friend Property Get Z(i As Long) As Double
Z = VecArray(i).Z
End Property
Friend Property Let Z(i As Long, Z As Double)
VecArray(i).Z = Z
End Property
And here's the UDT declaration for that:
Code:
Public Type VecType
' This is used for both 3D spatial vectors, and Euler angles as well.
X As Double
Y As Double
Z As Double
End Type
But I'm mainly just showing the RedimData, EraseData, Count, LoBound, HiBound, & IsDimmed functions. When all done in this way, you have to put your array index in a slightly different place in the code, but it's certainly useful under certain circumstances. Also, if each of your classes was optionally an array, you could have an IsArray function.
Also, something else I noticed is that you make absolutely no use of the Friend declaration, but I also see that you have this set to be compiled as an ActiveX.dll. If I were actually considering using these, I'd certainly just compile them into my main project, and not mess with an ActiveX.dll. And, in that case, I'd want all the exposed class methods declared as Friend. Just a note about that might be warranted.
Last edited by Elroy; Jan 13th, 2018 at 10:20 AM.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Thank you for you attension to the project. I will try to point basics concening why it was done that way but not another.
1) FTypes project seems to ask only for stdole2.tlb at buid time. No other referencies are needed. There can only be one confusion, because source code project settings have backward compatibility enabled. But when you just download sources you of course do not have any DLL builded before - so you have to temporary disable compatibility, build and then enable this back;
2) I do not agree about your statements of dirty Err object. First, I use On Error Resume Next by design - FTypes should not produce any errors in normal way. Second, FTypes is handled as DLL that of course have own treatment of Err object that do not intersect with Err object in client application. To pass any info about error to the client you need to add "static" classes and use its methods in client.
3) I agree about bitwise shifting for rest classes - but I've just made it for Integer and Long - so next enhancement is planned
4) As you've noticed already - FTypes have ArrayEx and ListEx classes. Second one is a generic single dimensioned array that can hold any type. First one is multi. You can't predict what count of dims it will be - you can write any array that OLE safaarray supports there. Then you are free to select a range from one dim and convert it to List - for example.
I do not like to introduce any custom types without need and particulary types that assign any borders to planned or implemented project functonality. That is why i use ParamArray arguments in ArrayEx.Item property.
5) You can use spesial ToList method of each class to convert it to array. ArrayEx itself have BoundU/L, Destroy and Redim (as well as ListEx)...
6) No Friend declares is the answer why there in no Error Goto 0 actually. There should be no conserns to use Active DLLs in VB6 at all i think. And FTypes was designed to be this. There is no big sense to put all in you APP like built-in stuff
Hopefuly, I understood you correctly If you have other concerns - let me know. I'm glad to communicate with all users of the project and help them with any issues or plan future implementation with your help.
Unfortunatly, for now it is pretty rare case to see such informative replies as yours (( And I'm happy to read and answer this =)
Last edited by hwoarang; Jan 13th, 2018 at 11:59 AM.
- ListEx: fix missing checks for array items count (f.e. caused Distinct to add new item by accident);
- ListEx: fix not inherited Sorted flag after Clone method using.