I have a problem with porting VBA code to Lazarus - freepascal

Sub ListaDokumentow()
On Error GoTo ErrHandler
Dim oSubGT As InsERT.Subiekt
Dim oListaDok As InsERT.SuDokumentyLista
Dim oDok As InsERT.SuDokument
Dim sNapis As String
Set oSubGT = UruchomSubiekta()
Set oListaDok = oSubGT.Dokumenty.Wybierz()
oListaDok.FiltrTypOpcje = gtaFiltrSuDokumentOpcjeZam
oListaDok.FiltrTyp = gtaFiltrSuDokumentZam
oListaDok.FiltrOkres = gtaFiltrOkresNieokreslony
oListaDok.MultiSelekcja = True
oListaDok.Wyswietl
sNapis = "Zaznaczono nastęujące dokumenty: " & vbCrLf
For Each oDok In oListaDok.ZaznaczoneDokumenty
sNapis = sNapis & oDok.NumerPelny & "ID:" & oDok.Identyfikator & vbCrLf
Next
MsgBox sNapis
Exit Sub
ErrHandler:
MsgBox "Wystąpił błąd: " & Err.Number & " - " & Err.Description
End Sub
I wrote such a code in VBA but I can not transfer it to Lazarus, it is about returning the invoice id and the invoice number
unit sm_testy;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, wps_u, LCLType,Comobj,variants,ActiveX;
type
TOleCollectionEnumClass = class(TObject);
TEkSmTesty = class(TForm)
private
public
end;
var
EkSmTesty: TEkSmTesty;
implementation
{$R *.lfm}
var
aSubGT,oSubGT:OleVariant;
oListGT,gtaFiltrOkresNieokreslony,gtaFiltrSuDokumentOpcjeZam,gtaFiltrSuDokumentZam:OleVariant;
oDok: OleVariant;
Reply, BoxStyle: Integer;
begin
BoxStyle := MB_ICONQUESTION + MB_YESNO;
//Reply := Application.MessageBox(PChar(IntToStr(PROG_VER_NUM_RC)),'Test', BoxStyle);
wpsConnect(oSubGT,true);
oListGT:=oSubGT.Dokumenty.Wybierz;
oListGT.FiltrTypOpcje:=15;
//oListGT.FiltrTyp:=gtaFiltrSuDokumentZam;
oListGT.FiltrOkres:=gtaFiltrOkresNieokreslony;
oListGT.MultiSelekcja:= True;
oListGT.Wyswietl;
end. // eof
I stopped at the display of window of "subiekt" with the list, and I do not know how to enumerate the oleVariant object
Maybe someone would at least lead me on the right path
I can't enumerate the oDok object in Lazarus, which in my opinion should look something like this
oDok: = CreateOleObject ('InsERT.SuDokument');

I use this code in a separate utility unit:
Type
TEatenType = {$ifdef fpc} {$ifdef ver3_0}pulong{$else}Ulong{$endif}{$else}Integer{$endif}; // type for eaten parameter MkParseDisplayName
oEnumIterator = record
mainobj: OleVariant;
oEnum : IEnumVariant;
IterItem : OleVariant;
IterVal : LongWord;
function Enumerate(v:olevariant):oEnumIterator;
function GetEnumerator :oEnumIterator;
function MoveNext:Boolean;
property Current:OleVariant read iteritem;
end;
Implementation
{ oEnumIterator}
function oEnumIterator.getenumerator :oEnumIterator;
begin
result:=self;
end;
Function oEnumIterator.Enumerate(v :olevariant):oEnumIterator;
begin
mainobj:=v;
oEnum := IUnknown(mainobj._NewEnum) as IEnumVariant;
result:=self;
end;
Function oEnumIterator.MoveNext:boolean;
begin
result:=(oEnum.Next(1, iteritem, iterval) = s_ok);
end;
and then enumerate using
var oEnum : oEnumIterator;
colItem,
colItems : Olevariant
..
colitems:=objWMIService.ExecQuery('Select * from Win32_OperatingSystem');
for colItem in oEnum.Enumerate(colItems) do
memo1.lines.add('Version: ',colitem.Version);

Related

Parse JSON with VBA (Access 2010) subscript out of range error

I'm parsing a JSON string similar to the solution at this link: Parse JSON with VBA (Access 2010). However, I'm getting the "subscript out of range" error.
Public Sub GetValues()
Dim s As String, rates(), i As Long
s = "{""id"":""14acfa60-c0e1-47fb-8f80-ca0831bf3b52"",""class"":""us_equity"",""exchange"":""ARCA"",""symbol"":""UVXY"",""name"":"""",""status"":""active"",""tradable"":true,""marginable"":true,""shortable"":false,""easy_to_borrow"":false}"
rates = Array("id", "class", "exchange", "symbol", "name", "status", "tradeable", "marginable", "shortable", "easy_to_borrow")
For i = LBound(rates) To UBound(rates)
Debug.Print rates(i) & ":" & GetRate(s, rates(i))
Next i
End Sub
Public Function GetRate(ByVal s As String, ByVal delimiter As String) As String
GetRate = Replace(Split(Split(s, delimiter & Chr$(34) & Chr$(58))(1), Chr$(44))(0), Chr$(125), vbNullString)
End Function
You have a typo in your code:
Public Sub GetValues()
Dim s As String, rates(), i As Long
'Just for better reading.
's = "{""id"":""14acfa60-c0e1-47fb-8f80-ca0831bf3b52"", _
""class"":""us_equity"", _
""exchange"":""ARCA"", _
""symbol"":""UVXY"", _
""name"":"""", _
""status"":""active"", _
""tradable"":true, _
""marginable"":true, _
""shortable"":false, _
""easy_to_borrow"":false}"
'""tradable"":true, _ <<<<< ERROR in s var. In your rate array you say: "tradeable"
' "tradeable", _ <<<<< rate Array! (I just change it to run the code)
s = "{""id"":""14acfa60-c0e1-47fb-8f80-ca0831bf3b52"",""class"":""us_equity"",""exchange"":""ARCA"",""symbol"":""UVXY"",""name"":"""",""status"":""active"",""tradable"":true,""marginable"":true,""shortable"":false,""easy_to_borrow"":false}"
rates = Array("id", _
"class", _
"exchange", _
"symbol", _
"name", _
"status", _
"tradable", _
"marginable", _
"shortable", _
"easy_to_borrow")
For i = LBound(rates) To UBound(rates)
Debug.Print rates(i) & ":" & GetRate(s, rates(i))
Next i
End Sub
Public Function GetRate(ByVal s As String, ByVal delimiter As String) As String
'Chr$(34) = "
'Chr$(58) = :
'Chr$(125) = }
'Again... better reading.
Dim A: A = Split(s, delimiter & Chr$(34) & Chr$(58))(1)
Dim B: B = Split(A, Chr$(44))(0)
Dim C: C = Chr$(125)
GetRate = Replace(B, C, vbNullString)
End Function
First of all the issue in your code is that you have a typo: In your JSON you have tradable but your rate is called tradeable.
I recommend to include a proper error handling in your function. So if something gets wrong there you don't get stuck but a error message instead.
I also recommend not to have everything in one line in your function like Replace(Split(Split(… because if something gets wrong you don't know in which part it went wrong: First or second Split or the Replace. So if you do that in multiple lines (see below) then you can return a more useful error message.
Shorter code is not necessarily faster and better. But code that is easily readable, debugable and maintainable is very good code because you will make less errors and find them quicker.
I highly recommend to use meaningful variable names. Names like s for example are very bad names. If you use Json instead you always immediately see that this variable contains your JSON string.
Meaningful variables make your code better because it is more human readable and VBA doesn't care about the extra 3 characters.
Finally I would declare variables as close as possible to their first use.
So the code below is a bit longer but has much more improved readability and an error handling that gives at least a proper info if the key word you were looking for did not exist in your JSON.
Option Explicit
Public Sub GetValues()
Dim Json As String
Json = "{""id"":""14acfa60-c0e1-47fb-8f80-ca0831bf3b52"",""class"":""us_equity"",""exchange"":""ARCA"",""symbol"":""UVXY"",""name"":"""",""status"":""active"",""tradable"":true,""marginable"":true,""shortable"":false,""easy_to_borrow"":false}"
Dim Rates() As Variant
Rates = Array("id", "tradeable", "class", "exchange", "symbol", "name", "status", "tradeable", "marginable", "shortable", "easy_to_borrow")
Dim i As Long
For i = LBound(Rates) To UBound(Rates)
Debug.Print Rates(i) & ":" & GetRate(Json, Rates(i))
Next i
End Sub
Public Function GetRate(ByVal Key As String, ByVal Delimiter As String) As String
On Error GoTo RETURN_ERR
Dim SplitKey() As String
SplitKey = Split(Key, Delimiter & Chr$(34) & Chr$(58))
If UBound(SplitKey) = 0 Then
GetRate = "KEY NOT FOUND"
Exit Function
End If
Dim ValueOfKey As String
ValueOfKey = Split(SplitKey(1), Chr$(44))(0)
'remove } from value
ValueOfKey = Replace(ValueOfKey, Chr$(125), vbNullString)
'return
GetRate = ValueOfKey
Exit Function
RETURN_ERR:
GetRate = "Unknown error while extracting value. Check the JSON syntax."
End Function

Not in List Error after replacing Chr(), yet added to list correctly

I have some combo boxes with code for adding new items to the source table with a form when it doesn't exist.
The code will replace Chr(47) / and Chr(92) \ with Chr(45) - if present. This is done because a file name is created using concatenation later.
The problem is if a character is replaced, I get an Access error that the item is not in the list. This does not happen if a character is not replaced. In both instances the correct items are added to the corresponding tables.
I have tried replacing the character before passing it to OpenArgs, AfterUpdate, on the form after it opens, etc. The error does not break so the program is working, I just want to eliminate a unnecessary pop-up message.
Any help is greatly appreciated.
Private Sub cboManual_NotInList(NewData As String, Response As Integer)
Dim MyMessage As String
Dim myButtons As Integer
Dim myTitle As String
Dim strSQL As String
On Error GoTo ErrHandler
MyMessage = "This Manual does not exist. Create it?"
myButtons = vbYesNo + vbDefaultButton1 + vbQuestion + vbApplicationModal
myTitle = "Add Manual?"
MyChoice = MsgBox(MyMessage, myButtons, myTitle)
If MyChoice = 6 Then
If Not DBAuthority = "Admin" And Not DBAuthority = "Data Entry" Then
Response = acDataErrContinue
MsgBox "Sorry, authorized access only", _
vbOKOnly, "Important Information"
Exit Sub
Else
Response = acDataErrAdded
CallerField = "Manual"
CallerForm = "NewDocument"
NewData = Replace(NewData, Chr(47), Chr(45))
NewData = Replace(NewData, Chr(92), Chr(45))
DoCmd.OpenForm "AddManual", windowmode:=acDialog, OpenArgs:=NewData
Me.cboManual.RowSource = Me.cboManual.RowSource
Me.cboManual.value = strAddManual
strManual = Me.cboManual.value
strAddManual = vbNullString
Me.cboSection.value = strAddSection
strSection = Me.cboSection.value
strAddSection = vbNullString
Me.cboEngine.value = strAddEngine
strEngine = Me.cboEngine.value
strAddEngine = vbNullString
End If
ElseIf MyChoice = 7 Then
Response = acDataErrContinue
MsgBox "Select Manual from list.", vbOKOnly, "Select Manual"
Me.cboManual.Undo
Me.cboManual.SetFocus
Exit Sub
End If
Exit Sub
ErrHandler:
If Err = 20 Then
Response = acDataErrContinue
ElseIf Err = 94 Then
Response = acDataErrContinue
Resume Next
ElseIf Err = 2237 Then
Response = acDataErrContinue
Resume Next
ElseIf Err = 0 Then
Response = acDataErrContinue
Else
MsgBox "cboManual.NotInList Err = " & Err.Number & " :" & Err.Description
Exit Sub
End If
Exit Sub
End Sub
Option one
Replace while typing
Select Case KeyCode
Case vbKeyDown
Me![cboNewPart].Dropdown
Case 220, 191 ' / and \
KeyCode = 189 ' with -
Case Else
End Select
Option two
after adding the new value to the table. do
me.combo.undo, me.combo.requery. me.combo.value = newValue
followed by acDataErrContinue
this way you won't get error message but the list will flicker a and it's purely a hack.
Try using a different variable name (other than NewData) to store the modified version of the value passed to the NewData argument, i.e.:
Dim NewString as String
NewString = NewData
NewString = Replace(NewString, Chr(47), Chr(45))
NewString = Replace(NewString, Chr(92), Chr(45))
DoCmd.OpenForm "AddManual", windowmode:=acDialog, OpenArgs:=NewString
Since VBA arguments are passed ByRef unless otherwise stated, any modification to the argument value will be modifying the original value passed to your cboManual_NotInList event handler.
Given the above, you could alternatively try changing the NewData argument to be passed by value (ByVal):
Private Sub cboManual_NotInList(ByVal NewData As String, Response As Integer)

Run time error '5': while using global variables

i declared the global variable in the Module1 and when i was trying to use it in another module it is showing the runtime error '5':\invalid procedure call or argument. i was unable to find the problem please provied the solution for this problem
Declaring global variable:
Function getFilePath() As String
getFilePath = FilePath
Set FilePath = "C:\quadyster\R3AgreementDetails"
End Function
Implementing of globalvariable:
Private Sub SendAgreement_Click()
If (Not IsNull(Me.RequestFrom) And Not IsNull(Me.RequestReference)) Then
Call AttachR3ServiceAgreement(Module1.FilePath, tripObjectFormation, "Agreement")
Me.AgreementDate = Now()
Else
MsgBox "Please provide 'RequestFrom' and 'RequestReference' to proceed." & vbNewLine & vbNewLine & _
"Press Ok to continue.", vbOKOnly, "Alert!!!"
End If
End Sub
this is the calling function
Public Function AttachR3ServiceAgreement(FilePath As String, tripData As
tripDetails, requestType As String)
Here error is occured:
Set objStream = objFSO.OpenTextFile(fileHTML, ForReading)
You have a syntax error there: Set can only be used with objects.
Public FilePath As String
Function getFilePath() As String
FilePath = "C:\quadyster\R3AgreementDetails"
getFilePath = FilePath
End Function
Private Sub SendAgreement_Click()
If (Not IsNull(Me.RequestFrom) And Not IsNull(Me.RequestReference)) Then
Call AttachR3ServiceAgreement(Module1.FilePath, tripObjectFormation, "Agreement")
Me.AgreementDate = Now()
Else
MsgBox "Please provide 'RequestFrom' and 'RequestReference' to proceed." & vbNewLine & vbNewLine & _
"Press Ok to continue.", vbOKOnly, "Alert!!!"
End If
End Sub

WScript Command - Run Minimized? (MSAccess/VBA)

I am performing a quick PING against the user-selected server IP to confirm it is reachable.
The following code does exactly what I need, except I would like to avoid the quick flash of the Command Shell window.
What do I need to modify to minimize that pesky CMD window?
SystemReachable (myIP)
If InStr(myStatus, "Reply") > 0 Then
' IP is Confirmed Reachable
Else
' IP is Not Reachable
End If
''''''''''''''''''''''
Function SystemReachable(ByVal strIP As String)
Dim oShell, oExec As Variant
Dim strText, strCmd As String
strText = ""
strCmd = "ping -n 1 -w 1000 " & strIP
Set oShell = CreateObject("WScript.Shell")
Set oExec = oShell.Exec(strCmd)
Do While Not oExec.StdOut.AtEndOfStream
strText = oExec.StdOut.ReadLine()
If InStr(strText, "Reply") > 0 Then
myStatus = strText
Exit Do
Else
myStatus = ""
End If
Loop
End Function
This question may be a little old but I figure that this answer may still be able to help.
(Tested with Excel VBA, have not been able to test with Access)
The WshShell.Exec Method enables the use of .StdIn, .StdOut, and .StdErr functions to write to and read from the consol window.
The WshShell.Run Method does not allow this functionality so for some purposes using Exec is required.
While it's true that there is no built in function to start the Exec method minimized or hidden you can use API's to quickly find the Exec window hwnd and minize/hide it.
My below script takes the ProcessID from the Exec object to find the window's Hwnd. With the Hwnd you can then set the window's show state.
From my testing with Excel 2007 VBA, in most cases I never even see the window... In some cases it might be visible for a few milliseconds but would only appear a quick flicker or blink... Note: I had better results using SW_MINIMIZE than I did with SW_HIDE, but you can play around with it.
I added the TestRoutine Sub to show an example of how to use the 'HideWindow' function.
The 'HideWindow' function uses the 'GetHwndFromProcess' function to get the window hwnd from the ProcessID.
Place the below into a Module...
Option Explicit
' ShowWindow() Commands
Public Const SW_HIDE = 0
Public Const SW_MINIMIZE = 6
'GetWindow Constants
Public Const GW_CHILD = 5
Public Const GW_HWNDFIRST = 0
Public Const GW_HWNDLAST = 1
Public Const GW_HWNDNEXT = 2
Public Const GW_HWNDPREV = 3
Public Const GW_OWNER = 4
' API Functions
Public Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Public Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Public Declare Function GetDesktopWindow Lib "user32" () As Long
Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Sub TestRoutine()
Dim objShell As Object
Dim oExec As Object
Dim strResults As String
Set objShell = CreateObject("WScript.Shell")
Set oExec = objShell.Exec("CMD /K")
Call HideWindow(oExec.ProcessID)
With oExec
.StdIn.WriteLine "Ping 127.0.0.1"
.StdIn.WriteLine "ipconfig /all"
.StdIn.WriteLine "exit"
Do Until .StdOut.AtEndOfStream
strResults = strResults & vbCrLf & .StdOut.ReadLine
DoEvents
Loop
End With
Set oExec = Nothing
Debug.Print strResults
End Sub
Function HideWindow(iProcessID)
Dim lngWinHwnd As Long
Do
lngWinHwnd = GetHwndFromProcess(CLng(iProcessID))
DoEvents
Loop While lngWinHwnd = 0
HideWindow = ShowWindow(lngWinHwnd, SW_MINIMIZE)
End Function
Function GetHwndFromProcess(p_lngProcessId As Long) As Long
Dim lngDesktop As Long
Dim lngChild As Long
Dim lngChildProcessID As Long
On Error Resume Next
lngDesktop = GetDesktopWindow()
lngChild = GetWindow(lngDesktop, GW_CHILD)
Do While lngChild <> 0
Call GetWindowThreadProcessId(lngChild, lngChildProcessID)
If lngChildProcessID = p_lngProcessId Then
GetHwndFromProcess = lngChild
Exit Do
End If
lngChild = GetWindow(lngChild, GW_HWNDNEXT)
Loop
On Error GoTo 0
End Function
ShowWindow function:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms633548%28v=vs.85%29.aspx
GetWindow function:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms633515%28v=vs.85%29.aspx
GetDesktopWindow function:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms633504%28v=vs.85%29.aspx
GetWindowThreadProcessId function:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms633522%28v=vs.85%29.aspx
If you need more information on how the API's work, a quick google search will provide you with a ton of information.
I hope that this can help... Thank You.
Found a very workable and silent approach:
Dim strCommand as string
Dim strPing As String
strCommand = "%ComSpec% /C %SystemRoot%\system32\ping.exe -n 1 -w 500 " & myIP & " | " & "%SystemRoot%\system32\find.exe /i " & Chr(34) & "TTL=" & Chr(34)
strPing = fShellRun(strCommand)
If strPing = "" Then
MsgBox "Not Connected"
Else
MsgBox "Connected!"
End If
'''''''''''''''''''''''''''
Function fShellRun(sCommandStringToExecute)
' This function will accept a string as a DOS command to execute.
' It will then execute the command in a shell, and capture the output into a file.
' That file is then read in and its contents are returned as the value the function returns.
' "myIP" is a user-selected global variable
Dim oShellObject, oFileSystemObject, sShellRndTmpFile
Dim oShellOutputFileToRead, iErr
Set oShellObject = CreateObject("Wscript.Shell")
Set oFileSystemObject = CreateObject("Scripting.FileSystemObject")
sShellRndTmpFile = oShellObject.ExpandEnvironmentStrings("%temp%") & oFileSystemObject.GetTempName
On Error Resume Next
oShellObject.Run sCommandStringToExecute & " > " & sShellRndTmpFile, 0, True
iErr = Err.Number
On Error GoTo 0
If iErr <> 0 Then
fShellRun = ""
Exit Function
End If
On Error GoTo err_skip
fShellRun = oFileSystemObject.OpenTextFile(sShellRndTmpFile, 1).ReadAll
oFileSystemObject.DeleteFile sShellRndTmpFile, True
Exit Function
err_skip:
fShellRun = ""
oFileSystemObject.DeleteFile sShellRndTmpFile, True
End Function
the run method of wscript already contains argumewnts to run minimized. So without all that effort shown above simply use
old code
oShellObject.Run sCommandStringToExecute & " > " & sShellRndTmpFile, 0, True
new code
oShellObject.Run sCommandStringToExecute & " > " & sShellRndTmpFile, 7, True
see Microsoft help for using the run method in wscript.
regards
Ytracks

VbScript: Function not getting executed fully

I am trying to call a function. Inside function I am reading an xml file and changing value to one of the nodes. But its exiting from function after the line sXmlFile = OpenXMLFile("\\common_automation\common_bin\" & sXmlFileName & ".xml")
The functionality inside the function when tested separately is working fine. But how I do make the control go to the entire function without exiting. Before executing the statements in function fully for the 1st call, its taking the 2nd call to the function.
x=replace_instrument_id(strIp,"newFund")
y=replace_instrument_id(strIp,"newBlock")
z=replace_instrument_id(strIp,"newSecRef")
Function replace_instrument_id(sCusip,sXmlFileName)
WScript.Echo"sCusip:" & sCusip
WScript.Echo"sXmlFileName:" & sXmlFileName
sXmlFile = OpenXMLFile("\\common_automation\common_bin\" & sXmlFileName & ".xml")
WScript.Echo "sXmlFile" & sXmlFile
strCusip = sCusip
Dim sNS : sNS = "xmlns:xs='http://www.w3.org/2001/XMLSchema' xmlns:msdata='urn:schemas-microsoft-com:xml-msdata'"
Dim oXDoc : Set oXDoc = CreateObject( "Msxml2.DOMDocument.6.0" )
Dim sXPath
if(sXmlFileName="newSecRef") Then
sXPath = "/NewDataSet/ReturningDataSet/live_ins_id"
Else
sXPath = "/NewDataSet/ReturningDataSet/ins_id"
End If
oXDoc.setProperty "SelectionLanguage", "XPath"
oXDoc.setProperty "SelectionNamespaces", sNS
oXDoc.async = False
oXDoc.loadXml sXmlFile
If 0 = oXDoc.ParseError Then
oXDoc.selectSingleNode(sXPath).text = strCusip
oXDoc.save "\common_automation\common_bin\"& sXmlFileName &".xml"
WScript.Echo oXDoc.selectSingleNode(sXPath).text
Else
WScript.Echo oXDoc.parseError.reason
End If
End Function
Function OpenXMLFile (filename)
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(filename, 1)
thisline = objFile.ReadAll
objFile.Close
OpenXMLFile = thisline
End Function
The output I am getting is
sCusip:02R99BET7
sXmlFileName:newFund
sCusip:02R99BET7
sXmlFileName:newBlock
sCusip:02R99BET7
sXmlFileName:newSecRef