How to call an existing VB6 function and pass parameters or execute a statement utilizing some defined objects dynamically? E.g.
Private Const KONST = 123.45
Private Function First()
Dim var1 As String
Dim var2 As Date
Dim var3 As Integer
...
var3 = Second(var1) 'LINE 1
...
var2 = var2 + IIf(var3 > KONST, 1, -1) 'LINE 2
...
var2 = var2 * KONST 'LINE 3
...
End Function
Private Function Second(ByVal str As String) As Integer
Second = CInt(str)
End Function
At line 1: Name of the function Second could be dynamic while using var1 and returning value
At line 2: The whole IIf should be dynamic using var3 and KONST
At line 3: Whole var2 * KONST should be dynamic i.e. here i may write var2 + KONST or var3 / KONST or var3 + 222 or 1 + 2 or myCollection.Item("item_Key").
All such dynamic configuration will be in a config file.
Edit
I am trying to make grid layout and data population dynamic. By grid layout i mean number of columns, their title, order, format, etc. And by population i mean loading data into the grid, in doing so, sometimes we resolve a database value with some of our Enums, we apply some logic on data before showing it, value of one column is based on value of other column, etc. Though, upto some extent, this can be achieved via databases views, but to have all such logic in a central location we do such things from source code. Therefore i need some way to call my vb6 code dynamically and define the calling (function name, parameters, enums, types, statement) in a config file.
Well, you could use CallByName (see http://support.microsoft.com/kb/186143 for one of many easily found examples) to invoke methods and properties on an object dynamically.
But I think you want entire composed statements to be executed dynamically. For that you can use the Script control (as in VBScript). See http://support.microsoft.com/kb/184740 for a sample. In particular, it has a Eval function that runs arbitrary statements.
Related
1st year coding student and have a project in my visual basics class.
Create a simple calculator that will multiply, divide, subtract and add. Thing is we are not allowed to use any decision structures or loops, only sequential style coding structure.
I am struggling with storing, passing, and utilizing the selected mathematical operator later in the program.
When coding equations, what data type are operators considered?
For example in 4-1=3 is - considered a string?
How would one go about storing this value and passing it to another section of the program then converting that to a form you could plug into a formula, all without using a decision structure or loop?
for example:
1) User clicks on "1" button a string value of 1 is stored in a label as a string.
2) The user clicks the the "+" button and a + is stored (not sure what data type to use here for later needs) in a label.
3) Then user clicks "1" button a 1 is stored in a label as a string.
4) User clicks the "=" button.
5) The = button event handler executes code converting both the "1" strings to integer variables and the formula should represent IntResult= IntvariableOne + intVariableTwo. but since the operator may not always be + and no decision structure can be used. how can this be coded in a way that uses a variable to store the operator and complete the processing correctly in a formula?
In the most simple terms it would be equivalent to something like:
intResult= intvariableOne, Operatorvarible, intVariableTwo
Like I said I am new to coding so I apologize if this is a dumb question or completely wrong approach.
any info is appreciated.
thanks
It's a cheat, but try using Eval:
Eval("4-1") ' returns 3
Reading your post I was thinking about using the "CallByName" function.
But you can also try something more elegant with some kind of "oop" (reaching some of the limits offered by the old VB6) :
Create a file "ICalculator.cls" :
'
' Defines the "ICalculator" interface.
'
Option Explicit
Public Function CalcProcess(value1 As Integer, value2 As Integer)
End Function
Create a file named "CalculatorAdd.cls" that will take "additions" in charge:
'
' This "class" will implement "ICalculator" inteface to manage additions.
'
Option Explicit
Implements ICalculator
Private Function ICalculator_CalcProcess(value1 As Integer, value2 As Integer)
ICalculator_CalcProcess = value1 + value2
End Function
An then, an example of how it works :
Sub Test()
Dim value1 As Integer
Dim value2 As Integer
value1 = 1
value2 = 2
' Global object :
Dim objCalculator As ICalculator
...
' The object is set to "Addition" in the onclick event of the "add" button :
Set objCalculator = New CalculatorAdd
...
' The process is done in the onclick event of the "equal" button
value1 = objCalculator.CalcProcess(value1, value2)
...
' You can also have :
'Set objCalculator = New CalculatorSub
'value1 = objCalculator.CalcProcess(value1, value2)
'etc...
End Sub
You can create classes for each operation "add, sub, divide, multiply" and set your global variable objCalculator according to the button pressed by the user.
That's just a beginning, you'll have to put the whole logic of a calculator in place...
I have a doubt about sorting logic. For explanation, I am providing a scenario here
I have 3 datasets and want to remove duplicate between the datasets and the final result should NOT be a single combined dataset , instead the result datasets should be seperate but without duplicates. like
TEST1 , TEST2, TEST3. Each of the dataset contains duplicates. After removing duplicates, still the datasets should be TEST1, TEST2, TEST3, but without any duplicates between the 3 datasets
Logic Used:
data
enter code herefinal;
set test1 test2 test3 indsname=dsn;
memnm=dsn;
run;
proc sort data=final nodupkey; by var var2; run;
data
test1 test2 test3;
set
final;
if memnm = 'test1' then output test1;
if memnm = 'test2' then output test2;
if memnm = 'test3' then output test3;
run;
I want to know whether the order of the rows of the datasets(test1,2,3) will be still preserved in the final dataset and even after the sorting procedure completion. Like as I am ordering the datasets while setting them in final dataset, will that order be changed during the sort procedure, or NOT
Note: The order of datasets(test1,2,3) will NOT be changed in the SET statement
Please provide a suggestion on this.
As far as I have tested this code, I have not seen any order change. But really want to confirm on it. If someone has any idea or document related to the ordering logic of sort step, it will be very helpful
Thanks in advance
The sort procedure will sort the rows in final by var and var2 and therefore your result datasets test1,test2 and test3 will also each be sorted by var and var2. If you want to preserve the order of your test datasets as it was before your program, you could for instance store the _N_ variable in your final dataset and sort on it after splitting your data based on memnm.
Though if your datasets contain other variables that var and var2, be aware that you are removing duplicate keys (var,var2), not duplicate records. proc sort nodupkey will keep the first record it encounters with a specific key in the order that they appear in final and discard the other regardless of the values variables other than var and var2.
For instance if you had test1:
var var2 var3
---------------
one two foo
and test2:
var var2 var3
---------------
one two bar
After your proc sort, you would have table final:
var var2 var3
---------------
one two foo
and the bar record would be gone.
To remove duplicate records you can use option noduprec instead of nodupkey
PROC SORT will preserve the relative order of observations within the BY groups.
If you want to combine three datasets that are already sorted then you can use the BY statement in combination with the SET statement. So if you wanted to combine three datasets and keep the first observation found in each BY group and also record which dataset contributed that observation you could use code like this.
data final ;
set test1 test2 test3 indsname=dsn;
by var var2;
if first.var2;
memnm=dsn;
run;
I'm new to VBScript and I am running into some trouble. The script is making an API call and pulling account information, placing the data into a CSV file. I'm pulling the data into an array, looping through each account and, if certain properties qualify, assigning them to a variable to be written to the CSV. The problem I am having is if one account qualifies for a property, it sets the variable and if the next account doesn't qualify, the variable is still retaining the value, giving false results in the CSV.
Set SFTPServer = WScript.CreateObject("SFTPCOMInterface.CIServer")
accounts = SFTPServer.AdminAccounts
For each admin in accounts
adminName = admin.Login
Dim count : count = admin.GetPermissionsCount()
For i = 0 To CInt(count )- 1
Set permission = admin.GetPermission(i)
' AdminPermissionsPolicy:
' ServerManagement = 0,
' SiteManagement = 1,
' STManagement = 2,
' UserCreation = 3,
' ChangePassword = 4,
' COMManagement = 5,
' ReportManagement = 6,
Select case permission.Permission
case 0:
serverAdmin = "Server Admin"
case 1:
site = permission.SiteName
case 2:
stMan = "2"
case 3:
userCreate = "3"
case 4:
chPassword = "4"
case 5:
comMan = "5"
case 6:
report = "6"
End Select
Next
WriteStuff.WriteLine""+adminName+"|"+site+"|"+stMan+"|"+userCreate+"|"+chPassword+"|"+comMan+"|"+report+"")
Next
Unfortunately variables in VBScript are either at global, or function scope.
So you'll need to reset each of the variables on each iteration of the for loop.
One way would be to write Dim dummy at the top of your script, and just before the Select Case, write serverAdmin = dummy, site = dummy etc.
It's good practice to Dim explicitly all your variables, and to use Option Explicit at the top of the module to enforce that.
Here's an alternate way to do what you need without having to empty each variable on each iteration. You've already documented what each value means in your code. Instead of using comments for that purpose, define them as constants at the top of your scope block:
' AdminPermissionsPolicy:
Const ServerManagement = 0
Const SiteManagement = 1
Const STManagement = 2
Const UserCreation = 3
Const ChangePassword = 4
Const COMManagement = 5
Const ReportManagement = 6
Then you can declare an array to hold the values:
Dim a(6)
And then in your loop you can empty the array on each iteration using the Erase function. You can use the constant names instead of 0/1/2/etc and, when it comes time to write the values, you can use Join() to combine your array values into a string instead of having to concatenate 7 variables.
For each admin in accounts
adminName = admin.Login
Erase a ' Empty the Permissions array for each new account
Dim count : count = admin.GetPermissionsCount()
For i = 0 To CInt(count )- 1
Set permission = admin.GetPermission(i)
Select case permission.Permission
case ServerManagement: ' Now you can use the constant instead of "0"
a(ServerManagement) = "Server Admin"
case SiteManagement:
a(SiteManagement) = permission.SiteName
...
End Select
Next
WriteStuff.WriteLine Join(a, "|") ' Use Join() to combine array values
Next
Let's start with the output. You want to print a list of items (some of them possibly Empty) separated by "|". That should be done like this:
WriteStuff.WriteLine Join(aOut, "|")
Advantages:
You don't need to know that VBScript's concatenation operator is &, not +, because you can't even use the wrong one with Join.
You don't need to repeat the separator.
No useless pre/ap-pending of the empty string "".
Works with any number of items.
aOut needs to be initalized in the loop. That is easy with ReDim - without Preserve.
Advantages:
You don't need to know that Empty is the literal for empty/uninitialzed in VBScript.
You don't need to repeat an assignment for each variable.
Works with any number of items.
Demo code:
Option Explicit
Const cnUB = 3
Dim nTest
For nTest = 0 To cnUB
ReDim aOut(cnUB)
Select Case nTest
Case 0
aOut(0) = "A"
Case 1
aOut(1) = "B"
Case 2
aOut(2) = "C"
Case 3
aOut(3) = "D"
End Select
WScript.Echo Join(aOut, "|")
Next
output:
cscript 31565794.vbs
A|||
|B||
||C|
|||D
Disadvantage:
Putting the data into the array anonymously (just known by number/index) may be more errorprone than using distinct variable( name)s. If you need the elements for further computations it may be a good idea to define constants
wtf
Const ciReport = 1
...
aOut(ciReport) = "B"
I have a requirement to check all text fields in a Database schema for any Illegal XML characters and replace them with a predefined set of acceptable values. This is to form part of a Data transformation rule, than can be called from other functions. So this function could be asked to called over a billion times on our dataset, so I need it to operate really efficiently.
i.e. & = AND ,
' = APOS
An example of what needs to be achieved by the function should be:
Update sometable set somefield = functioncall('f&re'd');
should result in
somefield having the value of ' fANDreAPOSd'
This is to carried out by a generic type PL/SQL function that takes an input of a text field and iterate through that field and replace all illegal values.
I have had a look at http://asktom.oracle.com/pls/asktom/f?p=100:11:0::NO::P11_QUESTION_ID:2612348048
http://decipherinfosys.wordpress.com/2007/11/27/removing-un-wanted-text-from-strings-in-oracle/
For some ideas, but I have my concerns over efficiency and the flexibility of these soltuions.
The way the client wants to handle the solution is to have a table configured to contain an illegal character and it's prefered replacement. The function then uses the values selected from this table to preform the replacements.
well, not exactly what you want, but consider this:
create type xmltest is object (s clob);
select XMLTYPE.createXml(xmltest('a& and ''')) from dual;
XMLTYPE.CREATEXML(XMLTEST('A&'''))
-------------------------------------------------------------------------------------
<XMLTEST>
<S>a& '</S>
</XMLTEST>
However the list of predefined of XML entities is quite small, so there wouldn't be an issue replacing them with replace
If this is because of XML I'll support hal9000 - you should let Oracle do that for you. E.g. XML functions do it automatically:
SQLPLUS> set define off
SQLPLUS> select xmlelement("e", 'foo & bar <> bar "hemingway''s"') from dual;
XMLELEMENT("E",'FOO&BAR<>BAR"HEMINGWAY''S"')
--------------------------------------------------------------------------------
<e>foo & bar <> bar "hemingway's"</e>
I wonder if there is a way to unduplicate records WITHOUT sorting?Sometimes, I want to keep original order and just want to remove duplicated records.
Is it possible?
BTW, below are what I know regarding unduplicating records, which does sorting in the end..
1.
proc sql;
create table yourdata_nodupe as
select distinct *
From abc;
quit;
2.
proc sort data=YOURDATA nodupkey;
by var1 var2 var3 var4 var5;
run;
You could use a hash object to keep track of which values have been seen as you pass through the data set. Only output when you encounter a key that hasn't been observed yet. This outputs in the order the data was observed in the input data set.
Here is an example using the input data set "sashelp.cars". The original data was in alphabetical order by Make so you can see that the output data set "nodupes" maintains that same order.
data nodupes (drop=rc);;
length Make $13.;
declare hash found_keys();
found_keys.definekey('Make');
found_keys.definedone();
do while (not done);
set sashelp.cars end=done;
rc=found_keys.check();
if rc^=0 then do;
rc=found_keys.add();
output;
end;
end;
stop;
run;
proc print data=nodupes;run;
/* Give each record in the original dataset and row number */
data with_id ;
set mydata ;
_id = _n_ ;
run ;
/* Remove dupes */
proc sort data=with_id nodupkey ;
by var1 var2 var3 ;
run ;
/* Sort back into original order */
proc sort data=with_id ;
by _id ;
run ;
I think the short answer is no, there isn't, at least not a way that wouldn't have a much bigger performance hit than a method based on sorting.
There may be specific cases where this is possible (a dataset where all variables are indexed? A relatively small dataset that you could reasonably load into memory and work with there?) but this wouldn't help you with a general method.
Something along the lines of Chris J's solution is probably the best way to get the outcome you're after, but that's not an answer to your actual question.
Depending on the number of variables in your data set, the following might be practical:
data abc_nodup;
set abc;
retain _var1 _var2 _var3 _var4;
if _n_ eq 1 then output;
else do;
if (var1 eq _var1) and (var2 eq _var2) and
(var3 eq _var3) and (var4 eq _var4)
then delete;
else output;
end;
_var1 = var1;
_var2 = var2;
_var3 = var3;
_var4 = var4;
drop _var:;
run;
Please refer to Usage Note 37581: How can I eliminate duplicate observations from a large data set without sorting, http://support.sas.com/kb/37/581.html . Usage Note 37581 shows how PROC SUMMARY can be used to more efficiently remove duplicates without the use of sorting.
The two examples given in the original post are not identical.
distinct in proc sql only removes lines which are fully identical
nodupkey in proc sort removes any line where key variables are identical (even if other variables are not identical). You need the option noduprecs to remove fully identical lines.
If you are only looking for records having common key variables, another solution I could think of would be to create a dataset with only the key variable(s) and find out which one are duplicates and then apply a format on the original data to flag duplicate records. If more than one key variable is present in the dataset, one would need to create a new variable containing the concatenation of all the key variable values - converted to character if needed.
This is the fastest way I can think of. It requires no sorting.
data output_data_name;
set input_data_name (
sortedby = person_id stay
keep =
person_id
stay
... more variables ...);
by person_id stay;
if first.stay > 0 then output;
run;
data output;
set yourdata;
by var notsorted;
if first.var then output;
run;
This will not sort the data but will remove duplicates within each group.