Access VBA and Smart Cards - what's the trick? - vba

I'm trying to play with a smart card using Windows 10/Access 2016 and VBA, and I have come across just about every example I could possibly find of how to make this happen, including:
https://www.utteraccess.com/forum/Acccess-Card-Readers-t1986575.html
Getting started with smartcard & ISO 7816 in excel vba ( SCardEstablishContext )
https://learn.microsoft.com/en-us/windows/win32/api/winscard/ (for function reference), and
Authentication Return Values and System Error Codes just to figure out what's going sideways.
The issue that I'm having is that SCardEstablishContext is returning 0x0 - SCARD_S_SUCCESS, but when I pass the SCARDCONTEXT over to SCardIsValidContext, it's returning 0x6 - ERROR_INVALID_HANDLE.
Here's the relevant parts of the code that I'm using (ignore AuthDict and SCardAuthCode as those are just helper functions to decode whatever status the other functions return)
Public AuthDict As Scripting.Dictionary
Public Const SCARD_SCOPE_USER As Long = &H0
Public Const SCARD_SCOPE_SYSTEM As Long = &H2
Public Const SCARD_SHARE_SHARED As Long = &H2
Public Const SCARD_SHARE_EXCLUSIVE As Long = &H1
Public Const SCARD_SHARE_DIRECT As Long = &H3
Public Const SCARD_PROTOCOL_T0 As Long = &H1
Public Const SCARD_PROTOCOL_T1 As Long = &H2
Public Const SCARD_DEFAULT_READERS As String = "SCard$DefaultReaders\000"
Public Const SCARD_ALL_READERS As String = "SCard$AllReaders\000"
Public Type SCARDCONTEXT
CardContext1 As Long
ReaderName As String
End Type
Public Declare PtrSafe Function SCardEstablishContext Lib "winscard.dll" ( _
ByVal dwScope As Long, _
ByVal pvReserved1 As Long, _
ByVal pvReserved2 As Long, _
ByRef phContext As SCARDCONTEXT _
) As Long
Public Declare PtrSafe Function SCardIsValidContext Lib "winscard.dll" ( _
ByRef hContext As SCARDCONTEXT _
) As Long
Public Sub GetContext()
Dim lreturn As Long
Dim RSVD1 As Long, RSVD2 As Long
Dim myContext As SCARDCONTEXT
Set AuthDict = New Scripting.Dictionary
Debug.Print "-----------------------------------------------------------------------------"
lreturn = SCardEstablishContext(SCARD_SCOPE_USER, RSVD1, RSVD2, myContext)
SCardAuthCode lreturn
Debug.Print "SCardEstablishContext:" & vbCrLf & _
" Return = " & AuthDict("hr") & vbCrLf & _
" Value = " & AuthDict("hc") & vbCrLf & _
" Description = " & AuthDict("hd") & vbCrLf & _
" myContext.CardContext1 = " & myContext.CardContext1 & vbCrLf & _
" myContext.ReaderName = " & Chr(34) & myContext.ReaderName & Chr(34) & vbCrLf
lreturn = SCardIsValidContext(myContext)
SCardAuthCode lreturn
Debug.Print "SCardIsValidContext:" & vbCrLf & _
" Return = " & AuthDict("hr") & vbCrLf & _
" Value = " & AuthDict("hc") & vbCrLf & _
" Description = " & AuthDict("hd") & vbCrLf
If lreturn <> 0 Then GoTo GetContextExit
GetContextExit:
Debug.Print "-----------------------------------------------------------------------------" & vbCrLf
End Sub
Run the Sub, here's the output:
-----------------------------------------------------------------------------
SCardEstablishContext:
Return = 0x00000000
Value = SCARD_S_SUCCESS
Description = No error was encountered.
myContext.CardContext1 = -855572480
myContext.ReaderName = ""
SCardIsValidContext:
Return = 0x00000006
Value = ERROR_INVALID_HANDLE
Description = The handle is invalid.
-----------------------------------------------------------------------------
It seems that I'm not setting myContext correctly, but I'm at a loss for what it should actually look like.
Also, here's the code for SCardAuthCode if you want the pretty return:
'https://learn.microsoft.com/en-us/windows/win32/secauthn/authentication-return-values?redirectedfrom=MSDN#smart_card_return_values
'https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-?redirectedfrom=MSDN
Public Function SCardAuthCode(lreturn As Long)
AuthDict.RemoveAll
Dim hreturn As String, hc As String, hd As String
hreturn = "0x" & Right("0000000" & Hex(lreturn), 8)
Select Case hreturn
Case "0x00000000": hc = "SCARD_S_SUCCESS": hd = "No error was encountered."
Case "0x00000006": hc = "ERROR_INVALID_HANDLE": hd = "The handle is invalid."
Case "0x00000109": hc = "ERROR_BROKEN_PIPE": hd = "The client attempted a smart card operation in a remote session, such as a client session running on a terminal server, and the operating system in use does not support smart card redirection."
Case "0x80100001": hc = "SCARD_F_INTERNAL_ERROR": hd = "An internal consistency check failed."
Case "0x80100002": hc = "SCARD_E_CANCELLED": hd = "The action was canceled by an SCardCancel request."
Case "0x80100003": hc = "SCARD_E_INVALID_HANDLE": hd = "The supplied handle was not valid."
Case "0x80100004": hc = "SCARD_E_INVALID_PARAMETER": hd = "One or more of the supplied parameters could not be properly interpreted."
Case "0x80100005": hc = "SCARD_E_INVALID_TARGET": hd = "Registry startup information is missing or not valid."
Case "0x80100006": hc = "SCARD_E_NO_MEMORY": hd = "Not enough memory available to complete this command."
Case "0x80100007": hc = "SCARD_F_WAITED_TOO_LONG": hd = "An internal consistency timer has expired."
Case "0x80100008": hc = "SCARD_E_INSUFFICIENT_BUFFER": hd = "The data buffer for returned data is too small for the returned data."
Case "0x80100009": hc = "SCARD_E_UNKNOWN_READER": hd = "The specified reader name is not recognized."
Case "0x8010000A": hc = "SCARD_E_TIMEOUT": hd = "The user-specified time-out value has expired."
Case "0x8010000B": hc = "SCARD_E_SHARING_VIOLATION": hd = "The smart card cannot be accessed because of other outstanding connections."
Case "0x8010000C": hc = "SCARD_E_NO_SMARTCARD": hd = "The operation requires a smart card, but no smart card is currently in the device."
Case "0x8010000D": hc = "SCARD_E_UNKNOWN_CARD": hd = "The specified smart card name is not recognized."
Case "0x8010000E": hc = "SCARD_E_CANT_DISPOSE": hd = "The system could not dispose of the media in the requested manner."
Case "0x8010000F": hc = "SCARD_E_PROTO_MISMATCH": hd = "The requested protocols are incompatible with the protocol currently in use with the card."
Case "0x80100010": hc = "SCARD_E_NOT_READY": hd = "The reader or card is not ready to accept commands."
Case "0x80100011": hc = "SCARD_E_INVALID_VALUE": hd = "One or more of the supplied parameter values could not be properly interpreted."
Case "0x80100012": hc = "SCARD_E_SYSTEM_CANCELLED": hd = "The action was canceled by the system, presumably to log off or shut down."
Case "0x80100013": hc = "SCARD_F_COMM_ERROR": hd = "An internal communications error has been detected."
Case "0x80100014": hc = "SCARD_F_UNKNOWN_ERROR": hd = "An internal error has been detected, but the source is unknown."
Case "0x80100015": hc = "SCARD_E_INVALID_ATR": hd = "An ATR string obtained from the registry is not a valid ATR string."
Case "0x80100016": hc = "SCARD_E_NOT_TRANSACTED": hd = "An attempt was made to end a nonexistent transaction."
Case "0x80100017": hc = "SCARD_E_READER_UNAVAILABLE": hd = "The specified reader is not currently available for use."
Case "0x80100018": hc = "SCARD_P_SHUTDOWN": hd = "The operation has been aborted to allow the server application to exit."
Case "0x80100019": hc = "SCARD_E_PCI_TOO_SMALL": hd = "The PCI receive buffer was too small."
Case "0x8010001A": hc = "SCARD_E_READER_UNSUPPORTED": hd = "The reader driver does not meet minimal requirements for support."
Case "0x8010001B": hc = "SCARD_E_DUPLICATE_READER": hd = "The reader driver did not produce a unique reader name."
Case "0x8010001C": hc = "SCARD_E_CARD_UNSUPPORTED": hd = "The smart card does not meet minimal requirements for support."
Case "0x8010001D": hc = "SCARD_E_NO_SERVICE": hd = "The smart card resource manager is not running."
Case "0x8010001E": hc = "SCARD_E_SERVICE_STOPPED": hd = "The smart card resource manager has shut down."
Case "0x8010001F": hc = "SCARD_E_UNEXPECTED": hd = "An unexpected card error has occurred."
Case "0x80100020": hc = "SCARD_E_ICC_INSTALLATION": hd = "No primary provider can be found for the smart card."
Case "0x80100021": hc = "SCARD_E_ICC_CREATEORDER": hd = "The requested order of object creation is not supported."
Case "0x80100022": hc = "SCARD_E_UNSUPPORTED_FEATURE": hd = "This smart card does not support the requested feature."
Case "0x80100023": hc = "SCARD_E_DIR_NOT_FOUND": hd = "The specified directory does not exist in the smart card."
Case "0x80100024": hc = "SCARD_E_FILE_NOT_FOUND": hd = "The specified file does not exist in the smart card."
Case "0x80100025": hc = "SCARD_E_NO_DIR": hd = "The supplied path does not represent a smart card directory."
Case "0x80100026": hc = "SCARD_E_NO_FILE": hd = "The supplied path does not represent a smart card file."
Case "0x80100027": hc = "SCARD_E_NO_ACCESS": hd = "Access is denied to the file."
Case "0x80100028": hc = "SCARD_E_WRITE_TOO_MANY": hd = "An attempt was made to write more data than would fit in the target object."
Case "0x80100029": hc = "SCARD_E_BAD_SEEK": hd = "An error occurred in setting the smart card file object pointer."
Case "0x8010002A": hc = "SCARD_E_INVALID_CHV": hd = "The supplied PIN is incorrect."
Case "0x8010002B": hc = "SCARD_E_UNKNOWN_RES_MNG": hd = "An unrecognized error code was returned."
Case "0x8010002C": hc = "SCARD_E_NO_SUCH_CERTIFICATE": hd = "The requested certificate does not exist."
Case "0x8010002D": hc = "SCARD_E_CERTIFICATE_UNAVAILABLE": hd = "The requested certificate could not be obtained."
Case "0x8010002E": hc = "SCARD_E_NO_READERS_AVAILABLE": hd = "No smart card reader is available."
Case "0x8010002F": hc = "SCARD_E_COMM_DATA_LOST": hd = "A communications error with the smart card has been detected."
Case "0x80100030": hc = "SCARD_E_NO_KEY_CONTAINER": hd = "The requested key container does not exist on the smart card."
Case "0x80100031": hc = "SCARD_E_SERVER_TOO_BUSY": hd = "The smart card resource manager is too busy to complete this operation."
Case "0x80100032": hc = "SCARD_E_PIN_CACHE_EXPIRED": hd = "The smart card PIN cache has expired."
Case "0x80100033": hc = "SCARD_E_NO_PIN_CACHE": hd = "The smart card PIN cannot be cached."
Case "0x80100034": hc = "SCARD_E_READ_ONLY_CARD": hd = "The smart card is read-only and cannot be written to."
Case "0x80100065": hc = "SCARD_W_UNSUPPORTED_CARD": hd = "The reader cannot communicate with the card, due to ATR string configuration conflicts."
Case "0x80100066": hc = "SCARD_W_UNRESPONSIVE_CARD": hd = "The smart card is not responding to a reset."
Case "0x80100067": hc = "SCARD_W_UNPOWERED_CARD": hd = "Power has been removed from the smart card, so that further communication is not possible."
Case "0x80100068": hc = "SCARD_W_RESET_CARD": hd = "The smart card was reset."
Case "0x80100069": hc = "SCARD_W_REMOVED_CARD": hd = "The smart card has been removed, so further communication is not possible."
Case "0x8010006A": hc = "SCARD_W_SECURITY_VIOLATION": hd = "Access was denied because of a security violation."
Case "0x8010006B": hc = "SCARD_W_WRONG_CHV": hd = "The card cannot be accessed because the wrong PIN was presented."
Case "0x8010006C": hc = "SCARD_W_CHV_BLOCKED": hd = "The card cannot be accessed because the maximum number of PIN entry attempts has been reached."
Case "0x8010006D": hc = "SCARD_W_EOF": hd = "The end of the smart card file has been reached."
Case "0x8010006E": hc = "SCARD_W_CANCELLED_BY_USER": hd = "The action was canceled by the user."
Case "0x8010006F": hc = "SCARD_W_CARD_NOT_AUTHENTICATED": hd = "No PIN was presented to the smart card."
Case "0x80100070": hc = "SCARD_W_CACHE_ITEM_NOT_FOUND": hd = "The requested item could not be found in the cache."
Case "0x80100071": hc = "SCARD_W_CACHE_ITEM_STALE": hd = "The requested cache item is too old and was deleted from the cache."
Case "0x80100072": hc = "SCARD_W_CACHE_ITEM_TOO_BIG": hd = "The new cache item exceeds the maximum per-item size defined for the cache."
Case Else: hc = "UNKNOWN VALUE": hd = "Unknown value."
End Select
AuthDict.Add "hr", hreturn
AuthDict.Add "hc", hc
AuthDict.Add "hd", hd
End Function

SCARDCONTEXT is not a type, it's a handle. I don't know where that type comes from.
Use a LongPtr for that handle.
SCardEstablishContext uses a pointer to the handle, so ByRef
Public Declare PtrSafe Function SCardEstablishContext Lib "winscard.dll" ( _
ByVal dwScope As Long, _
ByVal pvReserved1 As LongPtr, _
ByVal pvReserved2 As LongPtr, _
ByRef phContext As LongPtr_
) As Long
Note that both pvReserveds are also pointers so LongPtr, not Long. You're only supposed to add PtrSafe after thoroughly checking which Longs should actually be a LongPtr.
While for SCardIsValidContext, the handle is passed directly, so ByVal:
Public Declare PtrSafe Function SCardIsValidContext Lib "winscard.dll" ( _
ByVal hContext As LongPtr _
) As Long
Then, adjust your code accordingly, which should be trivial.
And of course, don't forget SCardReleaseContext when you're done, Windows can get fussy if you open contexts and never close them.

Related

How do you get the current label dimensions setting for a zebra printer

I am making an access application that prints two sizes of label, 3" width by 2" height, and then 1.5" width by 1" height. This application will run on several different computers that dont have the same sets of printers, for example, machine 1 might have a GC420d, a GK420d and a regular 8.5x11 printer, then machine 2 might have a LP 2844, a GC420d, and a regular 8.5x11 printer. The machines are spread out across the production environment and we cant standardize on printer type. So, this leaves me where i need to be able to determine which printer has the 3" x 2" settings and which has the 1.5" by 1" setting.
EDIT: I know this looks like a "I havent tried anything and im too lazy to try" situation, but all of the code i had was lost when access crashed to desktop. I mostly tried Win API stuff like DeviceCapabilities, but i couldn't get it to give me anything useful. a paper type Enumeration of Custom is useless when i cant see what the actual dimensions of the custom paper type is. Then i tried DocumentProperties which required OpenPrinter to get the printer handle. Thats the stuff that nuked everything access side. i used this
website to get the API calls for VBA.
EDIT2: this is the return for the papertype according to access.
?application.Printers(0).DeviceName
ZDesigner GC420d (EPL)
?application.Printers(0).PaperSize
256
You can use the below to list all supported paper names and their corresponding sizes:
Private Enum DeviceCapabilitiesFlags
DC_FIELDS = 1
DC_PAPERS = 2
DC_PAPERSIZE = 3
DC_MINEXTENT = 4
DC_MAXEXTENT = 5
DC_BINS = 6
DC_DUPLEX = 7
DC_SIZE = 8
DC_EXTRA = 9
DC_VERSION = 10
DC_DRIVER = 11
DC_BINNAMES = 12
DC_ENUMRESOLUTIONS = 13
DC_FILEDEPENDENCIES = 14
DC_TRUETYPE = 15
DC_PAPERNAMES = 16
DC_ORIENTATION = 17
DC_COPIES = 18
DC_BINADJUST = 19
DC_EMF_COMPLIANT = 20
DC_DATATYPE_PRODUCED = 21
DC_COLLATE = 22
DC_MANUFACTURER = 23
DC_MODEL = 24
DC_PERSONALITY = 25
DC_PRINTRATE = 26
DC_PRINTRATEUNIT = 27
DC_PRINTERMEM = 28
DC_MEDIAREADY = 29
DC_STAPLE = 30
DC_PRINTRATEPPM = 31
DC_COLORDEVICE = 32
DC_NUP = 33
DC_MEDIATYPENAMES = 34
DC_MEDIATYPES = 35
End Enum
Private Type POINT
x As Long
y As Long
End Type
Private Declare Function DeviceCapabilities _
Lib "winspool.drv" _
Alias "DeviceCapabilitiesA" _
(ByVal lpDeviceName As String, _
ByVal lpPort As String, _
ByVal iIndex As Long, _
ByRef lpOutput As Any, _
ByRef lpDevMode As Any) _
As Long
Private Declare Function StrLen _
Lib "kernel32.dll" _
Alias "lstrlenA" _
(ByVal lpString As String) _
As Long
Public Sub ListSupportedPaperSizes()
Dim defaultPrinter() As String
Dim paperCount As Long
Dim NameArray() As Byte
Dim i As Long
Dim paperNames() As String
Dim paperName As String
Dim ctr As Long
defaultPrinter = Split(Application.ActivePrinter, " on ")
paperCount = DeviceCapabilities(defaultPrinter(0), defaultPrinter(1), DC_PAPERSIZE, ByVal 0&, ByVal 0&)
ReDim paperNames(1 To paperCount)
ReDim NameArray(0 To paperCount * 64) As Byte
' Get paper names
paperCount = DeviceCapabilities(defaultPrinter(0), defaultPrinter(1), DC_PAPERNAMES, NameArray(0), 0)
'convert the retrieved byte array to an ANSI string
AllNames = StrConv(NameArray, vbUnicode)
ReDim paperNames(1 To paperCount)
'loop through the string and search for the names of the papers
For i = 1 To Len(AllNames) Step 64
ctr = ctr + 1
paperName = Mid(AllNames, i, 64)
paperName = Left(paperName, StrLen(paperName))
If paperName <> vbNullString Then
paperNames(ctr) = paperName
End If
Next i
ReDim PaperSizes(1 To paperCount) As POINT
paperCount = DeviceCapabilities(defaultPrinter(0), defaultPrinter(1), DC_PAPERSIZE, PaperSizes(1), 0)
For i = 1 To paperCount
Debug.Print paperNames(i) & " : " _
& Format(PaperSizes(i).x / 254, "0.00") & " x " _
& Format(PaperSizes(i).y / 254, "0.00") _
& " inch"
Next
End Sub

Call Stack size?

Greetings from Michigan,
I have a program that runs continuously (logging data) where it runs inside a While loop within one Sub ("logging data" Sub), then when the log file becomes "full", it jumps to another Sub to create a new file, then jumps back to the "logging data" Sub to continue on. Anyway, it keeps doing this and can run for hours like this, creating 100+ files or more of data. The problem is that the program crashes at some point and it always crashes within this part of the program (one of these two subs, although I haven't pinpointed which one. When I run the debugger on the machine in which the program is deployed, the Call Stack is rather large. I'm wondering if that is a problem, and how is that managed. Could that be the reason for the program crashing (Call stack getting too large?). I have gotten some sort of memory exception error on at least one of the crashes. I made some edits to the code yesterday to try and alleviate this. This last crash (this morning when I got into the office) that I experienced was a nullreference exception error, although I can't pinpoint where unless I run the program from my development machine in debug mode, which I plan to do next to catch exactly what line of code the crash is happening within either of these two Subs. I'll need to run it overnight as like I said, the program can run for hours before a crash occurs. Anyway, the question is in regards to the Call Stack. Is the large Call Stack a problem? How is that managed/cleared?
Thanks,
D
Public Sub dataAcquiring()
'Receive the collection of channels in this sub and append data to each of the channels
'Set up the channel group
Dim message1 As String = "The data file may have been deleted or moved prior to a new data file and directory being created. Check the main 'Data' directory and be sure the file exists, or simply create a new data file."
Dim testBool As Boolean = False
'Set the global variable to True if running the application from the development machine in debug mode. Otherwise, initialize it to false for deployment.
If Connectlocal = True Then
statsFile = "C:\Users\dmckin01\Desktop\Data\" & folderName & "\" & dataFileName & "_stats.csv"
Else : statsFile = "D:\Data\" & folderName & "\" & dataFileName & "_stats.csv"
End If
Try
logFile.Open()
Catch ex As Exception
MessageBox.Show(Me, ex.Message & message1, "File not found", MessageBoxButtons.OK, MessageBoxIcon.Error)
cbRecord.Checked = False
Return
End Try
Dim i As Integer = 0, n As Integer = 0, hvar As Integer, value As Single, count As Integer = 0, maxValue As Single
Dim b As Boolean = False, returnValue As Type, stringVar As String, lastValidNumber As Integer
Dim dtype As System.Type
Dim channelGroupName As String = "Main Group"
Dim channelGroup As TdmsChannelGroup = New TdmsChannelGroup(channelGroupName)
Dim channelGroups As TdmsChannelGroupCollection = logFile.GetChannelGroups()
If (channelGroups.Contains(channelGroupName)) Then
channelGroup = channelGroups(channelGroupName)
Else
channelGroups.Add(channelGroup)
End If
'Set up the TDMS channels
Dim Names As String() = New String(13) {" Spindle Speed (rpm) ", " Oil Flow (ccm) ", " Torque (Nm) ", " LVDT Displacement (mm) ", " Linear Pot Displacement (mm) ", _
" Pneu. Actuator (0=OFF, 1=ON) ", " Elec. Actuator (0=OFF, 1=ON) ", " Hydr. Actuator (0=OFF, 1=ON) ", _
" Upper Tank Oil Temp. (°F) ", " Lower Tank Oil Temp. (°F) ", " Exit Oil Temp. (°F) ", _
" Inlet Oil Temp. (°F) ", " Part Temp. (°F) ", " Time Stamp "}
Dim dataArrayNames As String() = New String(13) {"arrSpeed", "arrFlow", "arrTorque", "arrLVDT", "arrLinPot", "arrActPneu", "arrActElec", "arrActHydr", _
"arrUpperOil", "arrLowerOil", "arrExitOil", "arrInletOil", "arrTestPart", "arrTimeStamp"}
Dim OPCTagNames As String() = New String(13) {"peakTorque", "peakTorqueSpeed", "peakTorquePlatePos", "timeToPeakTorque", "firstPeakTorque", "firstPeakTorqueSpeed", _
"firstPeakTorquePlatePos", "timeToFirstPeakTorque", "peakDecel", "peakJerk", "engagementSpeed", "slidePlateSpeed", _
"timeOfEngagement", "totalEnergy"}
Dim bools As Boolean() = New Boolean(13) {recSpeed, recOilFlow, recTorque, recLVDT, recLinPot, recActPneu, recActElec, recActHydr, recUpperOil, recLowerOil, _
recExitOil, recInletOil, recTestPart, recTimeStamp}
'Instantiate the TDMS channels to be used. We have to do this each and every time this Sub is executed because National Instruments
'does not have a method to 'clear' the channel group.
Dim ch0 As TdmsChannel = New TdmsChannel(Names(0), TdmsDataType.Float) 'spindle speed
Dim ch1 As TdmsChannel = New TdmsChannel(Names(1), TdmsDataType.Float) 'oil flow
Dim ch2 As TdmsChannel = New TdmsChannel(Names(2), TdmsDataType.Float) 'torque
Dim ch3 As TdmsChannel = New TdmsChannel(Names(3), TdmsDataType.Float) 'actuator position (LVDT)
Dim ch4 As TdmsChannel = New TdmsChannel(Names(4), TdmsDataType.Float) 'actuator position (LINEAR POT)
Dim ch5 As TdmsChannel = New TdmsChannel(Names(5), TdmsDataType.Float) 'actuator state (pneu)
Dim ch6 As TdmsChannel = New TdmsChannel(Names(6), TdmsDataType.Float) 'actuator state (elec)
Dim ch7 As TdmsChannel = New TdmsChannel(Names(7), TdmsDataType.Float) 'actuator state (hydr)
Dim ch8 As TdmsChannel = New TdmsChannel(Names(8), TdmsDataType.Float) 'upper oil tank temp
Dim ch9 As TdmsChannel = New TdmsChannel(Names(9), TdmsDataType.Float) 'lower oil tank temp
Dim ch10 As TdmsChannel = New TdmsChannel(Names(10), TdmsDataType.Float) 'Exit oil tank temp
Dim ch11 As TdmsChannel = New TdmsChannel(Names(11), TdmsDataType.Float) 'Inlet oil temp
Dim ch12 As TdmsChannel = New TdmsChannel(Names(12), TdmsDataType.Float) 'Part temp
Dim ch13 As TdmsChannel = New TdmsChannel(Names(13), TdmsDataType.String) 'Time stamp
Dim Channels As TdmsChannelCollection
Dim chans As TdmsChannel() = New TdmsChannel(13) {ch0, ch1, ch2, ch3, ch4, ch5, ch6, ch7, ch8, ch9, ch10, ch11, ch12, ch13}
Channels = channelGroup.GetChannels()
ch0.UnitString = "RPM" : ch0.Description = "Rotational speed of the spindle shaft."
ch1.UnitString = "CCM" : ch1.Description = "Oil flow from the specimen pump."
ch2.UnitString = "Nm" : ch2.Description = "Torque from the torque cell."
ch3.UnitString = "mm" : ch3.Description = "Linear displacement of the linear velocity displacement transducer."
ch4.UnitString = "mm" : ch4.Description = "Linear displacement of the linear potentiometer."
ch5.UnitString = "BIT" : ch5.Description = "Binary state of the pneumatic actuator (0=OFF, 1=ON)."
ch6.UnitString = "BIT" : ch6.Description = "Binary state of the electric actuator (0=OFF, 1=ON)."
ch7.UnitString = "BIT" : ch7.Description = "Binary state of the hydraulic actuator (0=OFF, 1=ON)."
ch8.UnitString = "°F" : ch8.Description = "Upper tubular tank oil temperature."
ch9.UnitString = "°F" : ch9.Description = "Lower (main) tank oil temperature."
ch10.UnitString = "°F" : ch10.Description = "Thermocouple (Location: Remote rack, EL3318, Ch.2)."
ch11.UnitString = "°F" : ch11.Description = "Thermocouple (Location: Remote rack, EL3318, Ch.3)."
ch12.UnitString = "°F" : ch12.Description = "Thermocouple (Location: Remote rack, EL3318, Ch.1)"
ch13.UnitString = "nS" : ch13.Description = "Time when the data was captured."
'The only TDMS channels that get added to the collection are the ones that the user selects on the 'Configure Data File' form.
'That is what this If-Then block is for.
If Channels.Count = 0 Then
jArray.Clear()
plcArrayNames.Clear()
For Each [boolean] In bools
If [boolean] = True Then
Channels.Add(chans(i))
Channels = channelGroup.GetChannels 'new
jArray.Add(jaggedarray(i))
plcArrayNames.Add(dataArrayNames(i))
End If
i += 1
Next
End If
'At this point, we are ready to write data to the TDMS file.
'Establish the line of communication to the PLC so we can read the data arrays.
Dim tcClient As New TwinCAT.Ads.TcAdsClient()
Dim dataStreamRead As TwinCAT.Ads.AdsStream = New AdsStream
Dim binaryReader As System.IO.BinaryReader = New BinaryReader(dataStreamRead)
If Connectlocal = True Then
tcClient.Connect(851) 'local
Else : tcClient.Connect(AMSNetID, 851)
End If
While cbRecord.Checked = True
b = tcClient2.ReadAny(DRHvar, GetType(Boolean)) 'read the handshaking variable from the PLC
If b = False Then
'This For loop reads the appropriate arrays in the PLC and then writes that data to the appropriate arrays here.
'The arrays in here will eventually get written to the TDMS file.
i = 0
n = 0
writingData = True
For Each [string] In dataArrayNames
If dataArrayNames(n) = plcArrayNames(i) Then
hvar = tcClient.CreateVariableHandle("IO_HS.Data." & dataArrayNames(n))
value = 0
returnValue = jArray(i).GetType
If returnValue.Name = "Single[]" Then
dataStreamRead.SetLength(jArray(0).Length * 4)
dataStreamRead.Position = 0
tcClient.Read(hvar, dataStreamRead)
For Each [element] In jArray(0)
jArray(i)(value) = binaryReader.ReadSingle()
value += 1
Next
ElseIf returnValue.Name = "Int64[]" Then
dataStreamRead.SetLength(jArray(0).Length * 8)
dataStreamRead.Position = 0
tcClient.Read(hvar, dataStreamRead)
For Each [element] In jArray(0)
jArray(i)(value) = binaryReader.ReadInt64()
value += 1
Next
ElseIf returnValue.Name = "String[]" Then
dataStreamRead.SetLength(jArray(0).Length * 32)
dataStreamRead.Position = 0
tcClient.Read(hvar, dataStreamRead)
For Each [element] In jArray(0)
stringVar = binaryReader.ReadChars(32)
lastValidNumber = Math.Max(Math.Max(Math.Max(Math.Max(Math.Max(Math.Max(Math.Max(Math.Max(Math.Max(stringVar.LastIndexOf("0"), stringVar.LastIndexOf("1")), stringVar.LastIndexOf("2")), stringVar.LastIndexOf("3")), stringVar.LastIndexOf("4")), stringVar.LastIndexOf("5")), stringVar.LastIndexOf("6")), stringVar.LastIndexOf("7")), stringVar.LastIndexOf("8")), stringVar.LastIndexOf("9"))
If lastValidNumber > 0 Then
jArray(i)(value) = stringVar.Substring(0, lastValidNumber + 1)
Else
jArray(i)(value) = "Invalid Timestamp"
End If
value += 1
Next
End If
tcClient.DeleteVariableHandle(hvar)
i += 1
If i = plcArrayNames.Count Then
Exit For
End If
End If
n += 1
Next
'This For loop appends/writes the data from each array to the actual TDMS file.
i = 0
For Each [array] In jArray
dtype = Channels(i).GetDataType
If dtype.Name = "Int32" Then
Channels(i).AppendData(Of Integer)(jArray(i))
ElseIf dtype.Name = "Single" Then
Channels(i).AppendData(Of Single)(jArray(i))
ElseIf dtype.Name = "Boolean" Then
Channels(i).AppendData(Of Boolean)(jArray(i))
ElseIf dtype.Name = "String" Then
Channels(i).AppendData(Of String)(jArray(i))
End If
i += 1
Next
Try
'Call the DataAnalyzer dll to write stats of the cycle to stats CSV file. Also plot the data of the cycle on the chart on the UI
Invoke(Sub() DataAnalyzer.Analyze(arrSpeed, arrTorque, arrLinPot))
Invoke(Sub() plotData())
Invoke(Sub() DataAnalyzer.WriteData(statsFile, logFile.Path, arrTimeStamp(0), plcData.cyclesCompleted))
Catch ex As Exception
testBool = True
End Try
'Populate the datagridview cells with the data values
dgvStats.Item(1, 0).Value = DataAnalyzer.peakTorque
dgvStats.Item(1, 1).Value = DataAnalyzer.engagementSpeed
dgvStats.Item(1, 2).Value = DataAnalyzer.slidePlateSpeed
dgvStats.Item(1, 3).Value = plcData.bimbaTravSpeed
dgvStats.Item(1, 4).Value = plcData.lastCycleTime
dgvStats.Item(1, 5).Value = plcData.currentCycleTime
dgvStats.Item(1, 6).Value = plcData.meanCycleTime
dgvStats.Item(1, 7).Value = plcData.cyclesPerHr
'NEW CODE to Evalute the elements in the arrTorque array to get the Max value recorded
maxValue = 0
For Each [element] In arrTorque
maxValue = Math.Max(maxValue, element)
Next
If maxValue <= plcData.torqueAlrmSP And plcData.cycleStarted Then
torqueLowCount += 1
Else : torqueLowCount = 0
End If
'Let the PLC know that we received the data and are now ready for the next set (handshaking variable).
tcClient2.WriteAny(DRHvar, True)
End If
'If the data count in the first column of the TDMS file exceeds the number here, then
'close the file and create a new one, then continue to append/write data
If Channels(0).DataCount >= 1020000 Then
For Each channel As TdmsChannel In chans
channel.Dispose() : channel = Nothing
Next
chans = Nothing
channelGroup.Dispose() : channelGroup = Nothing
If tcClient.IsConnected Then
dataStreamRead.Dispose() : dataStreamRead = Nothing
tcClient.Disconnect() : tcClient.Dispose() : tcClient = Nothing
End If
'Jump to the CreateNewFile Sub to create the next TDMS file
CreateNewFile()
End If
End While
If logFile.IsOpen = True Then
logFile.Close()
End If
If tcClient.IsConnected Then
dataStreamRead.Dispose() : dataStreamRead = Nothing
tcClient.Disconnect() : tcClient.Dispose() : tcClient = Nothing
End If
writingData = False
End Sub
Private Sub CreateNewFile()
'Create the new folder where the data file/s will reside
Dim newFilename As String = dataFileName & "_" & fileNum
Dim customFilePropertyNames() As String = {"Date"}
Dim customFilePropertyVals() As String = {""}
Dim newAuthor As String = logFile.Author
Dim newDescription As String = logFile.Description
Dim newTitle As String = logFile.Title
Dim newPath1 As String = "C:\Users\dmckin01\Desktop\Data\" & folderName
Dim newPath2 As String = "D:\Data\" & folderName
fileNum += 1
'Create the TDMS file and save it to the user specified directory
customFilePropertyVals(0) = Date.Today.ToShortDateString()
logFile.Close() 'Close the old logfile after we've gotten values/properties from it
logFile.Dispose() : logFile = Nothing
Try
If Connectlocal = True Then
logFile = New TdmsFile(newPath1 & "\" & newFilename & ".tdms", New TdmsFileOptions())
Else : logFile = New TdmsFile(newPath2 & "\" & newFilename & ".tdms", New TdmsFileOptions())
End If
Catch ex As Exception
MessageBox.Show("Directory not created. Make sure the TDMS file and/or directory that you are referencing are not already currently opened.", "Directory Creation Failed", MessageBoxButtons.OK, MessageBoxIcon.Error)
Exit Sub
End Try
logFile.Author = newAuthor
logFile.Description = newDescription
logFile.Title = newTitle
logFile.AddProperty(customFilePropertyNames(0), TdmsPropertyDataType.String, customFilePropertyVals(0))
logFile.AutoSave = True
dataAcquiring()
End Sub
Stack errors are always caused by loops in your code that call back on themselves. Often caused by property setting handlers that set other properties that, in their turn, try to set the initial property. They can be difficult to pinpoint sometimes.
In your case, you have called the logging function
dataAcquiring()
End Sub
At then end of the file creation routine... this is a SERIOUS bug.
Each time you start a new file you start a new instance of the log loop and the old one remains on the stack... it's just a matter of time till it runs out of room
In this instance... the create routine should just exit..
However, if it were me I would make that code a function that returns true or false. Have it return false if the file could not be created for some reason and handle it gracefully in the main loop.

Check if mapped network available

I am trying to have my program check is a mapped network drive is actually connected, and change the curDrive variable based on the result. It works okay, but if the drive is still mapped and the drive is not available, there is a long delay while the program tries to connect (4-6 seconds). I tried two methods and both ways have this delay. I tried the following:
On Error GoTo switch
checker= Dir("F:\")
If checker= "" Then GoTo switch
curDrive = "F:\"
GoTo skip
switch:
curDrive = "C:\"
skip:
........
I also tried:
Dim FSO As Object '//FileSystemObject
Dim f As Object '//File Object
Set FSO = CreateObject("Scripting.FileSystemObject")
With FSO
If .FolderExists("F:\Sample") Then
curDrive = "F:\"
Else
curDrive = "C:\"
End If
End With
Both have the same delay.
After much searching and brainstorming, I put together some info from here and from elsewhere and came up with a method that takes half a second. Basically, I'm pinging the server and reading the results from a text file. I'm also checking to make sure that the F: Drive (the server drive) is available (Someone can be on the server but hasn't set the F: Drive to the server).
Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long
Private Declare Function WaitForSingleObject Lib "kernel32.dll" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccessas As Long, ByVal bInheritHandle As Long, ByVal dwProcId As Long) As Long
Sub CheckAllConnections()
ServerOn = ComputerIsOnline("server.mmc.local")
FDrive = CreateObject("scripting.filesystemobject").driveexists("F")
test = FDrive - 1
ProgramFolder = False
If ServerOn + FDrive = -2 Then
ProgramFolder = Len(Dir("F:\SampleProgram\")) > 0
End If
MsgBox ("Server connection is " & ServerOn & "." & Chr(10) & "F: Drive available is " & FDrive _
& Chr(10) & "The Program Folder availability is " & ProgramFolder)
End Sub
Public Function ComputerIsOnline(ByVal strComputerName As String) As Boolean
On Error Resume Next
Kill "C:\Logger.txt"
On Error GoTo ErrorHandler
ShellX = Shell("cmd.exe /c ping -n 1 " & strComputerName & " > c:\logger.txt", vbHide)
lPid = ShellX
lHnd = OpenProcess(&H100000, 0, lPid)
If lHnd <> 0 Then
lRet = WaitForSingleObject(lHnd, &HFFFF)
CloseHandle (lHnd)
End If
FileNum = FreeFile
Open "c:\logger.txt" For Input As #FileNum
strResult = Input(LOF(1), 1)
Close #FileNum
ComputerIsOnline = (InStr(strResult, "Lost = 0") > 0)
Exit Function
ErrorHandler:
ComputerIsOnline = False
Exit Function
End Function
Both show the same delay because both methods invoke the same underlying OS functionality to check for the presence of the network drive.
The OS is giving the external resource time to be available. I don't think you can do anything except await the timeout, if you want to know for sure.
If you know that, in your environment the OS timeout is just too long (e.g. "If it has not responded after 1 second, it will not respond), you could use a mechanism such as a timer to avoid waiting the full duration (set a 1 second timer when you start checking, if the timer fires and you still have no reply, the drive was not present).
There is no long delay when testing for a drive letter using the FileSystemObject and DriveExists:
Sub Tester()
Dim n As Integer
For n = 1 To 26
Debug.Print Chr(64 + n), HaveDrive(Chr(64 + n))
Next n
End Sub
Function HaveDrive(driveletter)
HaveDrive = CreateObject("scripting.filesystemobject").driveexists(driveletter)
End Function

Capturing a photo on x86 Atom Windows 8, DirectShow

I don't have a C background, so pointers seem to be my downfall. Working with a Lenovo Thinkpad tablet running full blown Windows (Atom processor). I ported the sample project DXSnap to vb.net. It works fine on my laptop, but on the tablet I'm getting errors.
First error is: Exception Occurred: System.Runtime.InteropServices.COMException (0x80070032). The request is not supported.
2nd error (after closing 1st error): Uninitialized Buffer in BufferCB.
I think the main problem is I'm not sure what video settings to use. I started with the default 640x480x24bpp. I moved past my first issues by changing it to what I was getting from the videoInfoHeader, which is 448x252, although it didn't return a bpp that I saw.
Some sample data from 1 run:
Media Format Type: 05589f80-c356-11ce-bf01-00aa0055595a 'this is constant, probably ok
Height: 252
Width: 448
m_stride: 1344 'Pretty sure this is calculated by the program, should be ok
pBuffer: 128778240
m_ipBuffer: 81070712
Buffer Length: 338688 'constant. Should be ok
Subs/Functions of concern for me:
Private Sub SetupGraph(dev As DsDevice, iWidth As Integer, iHeight As Integer, iBPP As Short, hControl As Control)
Dim hr As Integer
Dim sampGrabber As ISampleGrabber = Nothing
Dim capFilter As IBaseFilter = Nothing
Dim pCaptureOut As IPin = Nothing
Dim pSampleIn As IPin = Nothing
Dim pRenderIn As IPin = Nothing
' Get the graphbuilder object
m_FilterGraph = TryCast(New FilterGraph(), IFilterGraph2)
Try
#If DEBUG Then
m_rot = New DsROTEntry(m_FilterGraph)
#End If
' add the video input device
hr = m_FilterGraph.AddSourceFilterForMoniker(dev.Mon, Nothing, dev.Name, capFilter)
DsError.ThrowExceptionForHR(hr)
MsgBox(dev.Name.ToString & vbNewLine & dev.Mon.ToString & vbNewLine & capFilter.ToString)
' Find the still pin
m_pinStill = DsFindPin.ByCategory(capFilter, PinCategory.Still, 0)
' Didn't find one. Is there a preview pin?
If m_pinStill Is Nothing Then
m_pinStill = DsFindPin.ByCategory(capFilter, PinCategory.Preview, 0)
End If
' Still haven't found one. Need to put a splitter in so we have
' one stream to capture the bitmap from, and one to display. Ok, we
' don't *have* to do it that way, but we are going to anyway.
If m_pinStill Is Nothing Then
Dim pRaw As IPin = Nothing
Dim pSmart As IPin = Nothing
' There is no still pin
m_VidControl = Nothing
' Add a splitter
Dim iSmartTee As IBaseFilter = DirectCast(New SmartTee(), IBaseFilter)
Try
hr = m_FilterGraph.AddFilter(iSmartTee, "SmartTee")
DsError.ThrowExceptionForHR(hr)
' Find the find the capture pin from the video device and the
' input pin for the splitter, and connnect them
pRaw = DsFindPin.ByCategory(capFilter, PinCategory.Capture, 0)
pSmart = DsFindPin.ByDirection(iSmartTee, PinDirection.Input, 0)
hr = m_FilterGraph.Connect(pRaw, pSmart)
DsError.ThrowExceptionForHR(hr)
' Now set the capture and still pins (from the splitter)
m_pinStill = DsFindPin.ByName(iSmartTee, "Preview")
pCaptureOut = DsFindPin.ByName(iSmartTee, "Capture")
' If any of the default config items are set, perform the config
' on the actual video device (rather than the splitter)
If iHeight + iWidth + iBPP > 0 Then
SetConfigParms(pRaw, iWidth, iHeight, iBPP)
End If
Finally
If pRaw IsNot Nothing Then
Marshal.ReleaseComObject(pRaw)
End If
If Not pRaw Is pSmart Then
Marshal.ReleaseComObject(pSmart)
End If
If Not pRaw Is iSmartTee Then
Marshal.ReleaseComObject(iSmartTee)
End If
End Try
Else
' Get a control pointer (used in Click())
m_VidControl = TryCast(capFilter, IAMVideoControl)
pCaptureOut = DsFindPin.ByCategory(capFilter, PinCategory.Capture, 0)
' If any of the default config items are set
If iHeight + iWidth + iBPP > 0 Then
MsgBox("mPinStill: " & m_pinStill.ToString & vbNewLine & "iHeight: " & iHeight.ToString & vbNewLine & "iWidth: " & iWidth.ToString & vbNewLine & "bpp: " & iBPP.ToString)
SetConfigParms(m_pinStill, iWidth, iHeight, iBPP)
End If
End If
' Get the SampleGrabber interface
sampGrabber = TryCast(New SampleGrabber(), ISampleGrabber)
' Configure the sample grabber
Dim baseGrabFlt As IBaseFilter = TryCast(sampGrabber, IBaseFilter)
ConfigureSampleGrabber(sampGrabber)
pSampleIn = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Input, 0)
' Get the default video renderer
Dim pRenderer As IBaseFilter = TryCast(New VideoRendererDefault(), IBaseFilter)
hr = m_FilterGraph.AddFilter(pRenderer, "Renderer")
DsError.ThrowExceptionForHR(hr)
pRenderIn = DsFindPin.ByDirection(pRenderer, PinDirection.Input, 0)
' Add the sample grabber to the graph
hr = m_FilterGraph.AddFilter(baseGrabFlt, "Ds.NET Grabber")
DsError.ThrowExceptionForHR(hr)
If m_VidControl Is Nothing Then
' Connect the Still pin to the sample grabber
hr = m_FilterGraph.Connect(m_pinStill, pSampleIn)
DsError.ThrowExceptionForHR(hr)
' Connect the capture pin to the renderer
hr = m_FilterGraph.Connect(pCaptureOut, pRenderIn)
DsError.ThrowExceptionForHR(hr)
Else
' Connect the capture pin to the renderer
hr = m_FilterGraph.Connect(pCaptureOut, pRenderIn)
DsError.ThrowExceptionForHR(hr)
' Connect the Still pin to the sample grabber
hr = m_FilterGraph.Connect(m_pinStill, pSampleIn)
DsError.ThrowExceptionForHR(hr)
End If
' Learn the video properties
SaveSizeInfo(sampGrabber)
ConfigVideoWindow(hControl)
' Start the graph
Dim mediaCtrl As IMediaControl = TryCast(m_FilterGraph, IMediaControl)
hr = mediaCtrl.Run()
DsError.ThrowExceptionForHR(hr)
Finally
If sampGrabber IsNot Nothing Then
Marshal.ReleaseComObject(sampGrabber)
sampGrabber = Nothing
End If
If pCaptureOut IsNot Nothing Then
Marshal.ReleaseComObject(pCaptureOut)
pCaptureOut = Nothing
End If
If pRenderIn IsNot Nothing Then
Marshal.ReleaseComObject(pRenderIn)
pRenderIn = Nothing
End If
If pSampleIn IsNot Nothing Then
Marshal.ReleaseComObject(pSampleIn)
pSampleIn = Nothing
End If
End Try
End Sub
Private Function BufferCB(SampleTime As Double, pBuffer As IntPtr, BufferLen As Integer) As Integer Implements ISampleGrabberCB.BufferCB
' Note that we depend on only being called once per call to Click. Otherwise
' a second call can overwrite the previous image.
Debug.Assert(BufferLen = Math.Abs(1344) * 252, "Incorrect buffer length")
'Debug.Assert(BufferLen = Math.Abs(m_stride) * m_videoHeight, "Incorrect buffer length")
If m_WantOne Then
m_WantOne = False
MsgBox("P Buffer: " & pBuffer.ToString & "- Buffer Length: " & BufferLen.ToString & vbNewLine & "m_ipBuffer: " & m_ipBuffer.ToString)
Debug.Assert(m_ipBuffer <> IntPtr.Zero, "Unitialized buffer")
' Save the buffer
CopyMemory(m_ipBuffer, pBuffer, BufferLen)
MsgBox("After CopyMemory", MsgBoxStyle.AbortRetryIgnore)
' Picture is ready.
m_PictureReady.[Set]()
End If
Return 0
End Function
CopyMemory in BufferCB seems to be what is causing the issue, which is why I think there's a problem with the buffers, or video size/bpp.

Bandwidth calculation (Internet data transfer)

I have used the following code to get bandwidth
It works but i have following doubts
1.I need Total Internet Data transferred in MB, how do i convert?, total data transferred (download+upload) varies with other bandwidth monitoring applications. how do i get exact data transferred?
2.I need to exclude file transfer in local LAN in Data Transfer, The follwoing method includes internet data transfer + Local file transfer
Option Explicit
Public Enum OperationalStates
MIB_IF_OPER_STATUS_NON_OPERATIONAL = 0
MIB_IF_OPER_STATUS_UNREACHABLE = 1
MIB_IF_OPER_STATUS_DISCONNECTED = 2
MIB_IF_OPER_STATUS_CONNECTING = 3
MIB_IF_OPER_STATUS_CONNECTED = 4
MIB_IF_OPER_STATUS_OPERATIONAL = 5
End Enum
Public Enum InterfaceTypes
MIB_IF_TYPE_OTHER = 1
MIB_IF_TYPE_ETHERNET = 6
MIB_IF_TYPE_TOKENRING = 9
MIB_IF_TYPE_FDDI = 15
MIB_IF_TYPE_PPP = 23
MIB_IF_TYPE_LOOPBACK = 24
MIB_IF_TYPE_SLIP = 28
End Enum
Public Enum AdminStatuses
MIB_IF_ADMIN_STATUS_UP = 1
MIB_IF_ADMIN_STATUS_DOWN = 2
MIB_IF_ADMIN_STATUS_TESTING = 3
End Enum
Private Const MAXLEN_IFDESCR As Integer = 256
Private Const MAXLEN_PHYSADDR As Integer = 8
Private Const MAX_INTERFACE_NAME_LEN As Integer = 256
Private Const ERROR_NOT_SUPPORTED As Long = 50
Private Const ERROR_SUCCESS As Long = 0
Private Type MIB_IFROW
wszName(0 To 511) As Byte
dwIndex As Long '// index of the interface
dwType As Long '// type of interface
dwMtu As Long '// max transmission unit
dwSpeed As Long '// speed of the interface
dwPhysAddrLen As Long '// length of physical address
bPhysAddr(0 To 7) As Byte '// physical address of adapter
dwAdminStatus As Long '// administrative status
dwOperStatus As Long '// operational status
dwLastChange As Long
dwInOctets As Long '// octets received
dwInUcastPkts As Long '// unicast packets received
dwInNUcastPkts As Long '// non-unicast packets received
dwInDiscards As Long '// received packets discarded
dwInErrors As Long '// erroneous packets received
dwInUnknownProtos As Long
dwOutOctets As Long '// octets sent
dwOutUcastPkts As Long '// unicast packets sent
dwOutNUcastPkts As Long '// non-unicast packets sent
dwOutDiscards As Long '// outgoing packets discarded
dwOutErrors As Long '// erroneous packets sent
dwOutQLen As Long '// output queue length
dwDescrLen As Long '// length of bDescr member
bDescr(0 To 255) As Byte '// interface description
End Type
Private m_lngBytesReceived As Long
Private m_lngBytesSent As Long
Private Declare Function GetIfTable _
Lib "IPhlpAPI" (ByRef pIfRowTable As Any, _
ByRef pdwSize As Long, _
ByVal bOrder As Long) As Long
Private Declare Sub CopyMemory _
Lib "kernel32" _
Alias "RtlMoveMemory" (ByRef pDest As Any, _
ByRef pSource As Any, _
ByVal Length As Long)
Private Declare Function FreeResource Lib "kernel32" (ByVal hResData As Long) As Long
Public Property Get BytesReceived() As Long
BytesReceived = m_lngBytesReceived
End Property
Public Property Get BytesSent() As Long
BytesSent = m_lngBytesSent
End Property
Public Function InitInterfaces() As Boolean
Dim arrBuffer() As Byte
Dim lngSize As Long
Dim lngRetVal As Long
Dim Name As String
Dim lngRows As Long
Dim lngRow As Long
Dim i As Integer
Dim j As Integer
Dim IfRowTable As MIB_IFROW
On Error GoTo err
lngSize = 0
m_lngBytesReceived = 0
m_lngBytesSent = 0
lngRetVal = GetIfTable(ByVal 0&, lngSize, 0)
If lngRetVal = ERROR_NOT_SUPPORTED Then
Exit Function
End If
ReDim arrBuffer(0 To lngSize - 1) As Byte
lngRetVal = GetIfTable(arrBuffer(0), lngSize, 0)
If lngRetVal = ERROR_SUCCESS Then
CopyMemory lngRows, arrBuffer(0), 4
If lngRows >= 1 Then
For lngRow = 1 To lngRows
CopyMemory IfRowTable, arrBuffer(4 + (lngRow - 1) * Len(IfRowTable)), Len(IfRowTable)
For i = 0 To 25
Name = Name & Chr(IfRowTable.bDescr(i))
If IfRowTable.bDescr(i) = Chr(0) Then GoTo ok
Next
ok:
If Not InStr(1, Name, "loop", vbTextCompare) > 0 Then
With IfRowTable
m_lngBytesReceived = m_lngBytesReceived + .dwInOctets
m_lngBytesSent = m_lngBytesSent + .dwOutOctets
End With 'IFROWTABLE
'Set IfRowTable = Nothing
InitInterfaces = True
End If
Name = vbNullString
Next
Erase arrBuffer
End If
End If
On Error GoTo 0
Exit Function
err:
Call GErrorHandler(err.Number, err.Description, "CIPHelper:InitInterfaces:" & err.Source, True)
End Function
Private Sub GetBandwidth()
Dim c As New CIpHelper, R As Double, s As Double
Dim r1 As Double, c1 As Double, SendBytes1 As Double, ReceivedBytes1 As Double
On Error GoTo errh:
c.InitInterfaces
If FirstTime Then
FirstTime = False
SendBytes = Format(c.BytesSent / 1024, ".0")
ReceivedBytes = Format(c.BytesReceived / 1024, ".0")
SendBytes1 = c.BytesSent
ReceivedBytes1 = c.BytesReceived
Else 'FIRSTTIME = FALSE/0
R = ((c.BytesReceived / 1024) - ReceivedBytes)
s = ((c.BytesSent / 1024) - SendBytes)
End If
lblBandwidthUsed = R+s
OldR = R
OldS = s
On Error GoTo 0
Exit Sub
errh:
Call GErrorHandler(err.Number, err.Description, "ScreenBlock:GetBandwidth:" & err.Source, True)
End Sub
1) 1024 bytes = 1 kB and 1024 kB = 1 MB. In other words, divide the number of kilobytes by 1024.
2) I assume if you don't want to monitor LAN traffic, you want to monitor Wireless traffic. That might be a little tricky to do as a generic solution, but if you know the MAC address of your lan network card, you can exclude it in the calculations which looks like the "bPhysAddr" variable to me.
You can get the MAC address of a PC executing the command in the command line:
ipconfig /all