Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. Visual Basic
  4. Accessing an external DLL from a Timer - should there be a problem?

Accessing an external DLL from a Timer - should there be a problem?

Scheduled Pinned Locked Moved Visual Basic
helpquestioncsscomhardware
7 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P Offline
    P Offline
    Peter R Fletcher
    wrote on last edited by
    #1

    I want to download data every five minutes from a Davis Weather Station. The code that actually talks to the hardware is in a DLL, and I don't have access to the source (or to terribly good documentation, sadly!). My code that does the downloading (below) works reliably and without problems if called in the normal way. If it is called from a System.Timer OnElapsed thread, the program (run in Debug mode) crashes immediately without reporting what is going wrong. The variables and structures starting with g are defined outside any Functions in a Module, so they have global scope, as do WSInitialized and USBSerialNumber. I think that everything else is fairly obvious. Commenting out the one line which retrieves text data into a StringBuilder seems to fix the problem, and I can do without that data, but I would like to know what is going on, since I may want to do something in the future where the use of StringBuilders to receive data (if that is what is causing the problem) is less optional.

    Private Sub Get_Davis_WeatherData(ByRef gwdcurrent As WeatherData)
    Dim dtsTemp As New DateTimeStamp
    Dim sbWindDir As New StringBuilder(5)
    If Not WSInitialized Then
    CloseUSBPort_V()
    USBSerialNumber = GetUSBDevSerialNumber_V()
    If (OpenUSBPort_V(USBSerialNumber) = 0) Then
    If (InitStation_V() = COM_ERROR) Then
    MsgBox("Cannot initialize the USB port for the Weather Station")
    Exit Sub
    Else
    SetCommTimeoutVal_V(100, 100)
    WSInitialized = True
    End If
    Else
    MsgBox("Cannot open the USB port for the Weather Station")
    Exit Sub
    End If
    End If
    If (GetStationTime_V(dtsTemp) = 0) Then gwdcurrent.Time = DateStamp2UnixTime(dtsTemp)
    If LoadCurrentVantageData_V() = 0 Then
    gwdcurrent.OutTempF = GetOutsideTemp_V()
    gwdcurrent.OutHum = GetOutsideHumidity_V()
    gwdcurrent.BPressure = GetBarometer_V()
    gwdcurrent.WindChillF = GetWindChill_V()
    gwdcurrent.DewPointF = GetDewPt_V()
    gwdcurrent.RainTotal = GetTotalRain_V()
    gwdcurrent.Rain24h = GetDailyRain_V()
    gwdcurrent.Rain1h = GetRainRate_V()
    gwdcurrent.WindSpeedMPH = GetWindSpeed_V()
    gwdcurrent.WindRDir = GetWindDir_V()
    gwdcurrent.WindDir = GetWindDirStr_V(sbWindDir).ToString ' This is where things go badly wrong
    gsngRainMTD = GetMonthlyRain_V()
    End If
    If gsns

    D B 3 Replies Last reply
    0
    • P Peter R Fletcher

      I want to download data every five minutes from a Davis Weather Station. The code that actually talks to the hardware is in a DLL, and I don't have access to the source (or to terribly good documentation, sadly!). My code that does the downloading (below) works reliably and without problems if called in the normal way. If it is called from a System.Timer OnElapsed thread, the program (run in Debug mode) crashes immediately without reporting what is going wrong. The variables and structures starting with g are defined outside any Functions in a Module, so they have global scope, as do WSInitialized and USBSerialNumber. I think that everything else is fairly obvious. Commenting out the one line which retrieves text data into a StringBuilder seems to fix the problem, and I can do without that data, but I would like to know what is going on, since I may want to do something in the future where the use of StringBuilders to receive data (if that is what is causing the problem) is less optional.

      Private Sub Get_Davis_WeatherData(ByRef gwdcurrent As WeatherData)
      Dim dtsTemp As New DateTimeStamp
      Dim sbWindDir As New StringBuilder(5)
      If Not WSInitialized Then
      CloseUSBPort_V()
      USBSerialNumber = GetUSBDevSerialNumber_V()
      If (OpenUSBPort_V(USBSerialNumber) = 0) Then
      If (InitStation_V() = COM_ERROR) Then
      MsgBox("Cannot initialize the USB port for the Weather Station")
      Exit Sub
      Else
      SetCommTimeoutVal_V(100, 100)
      WSInitialized = True
      End If
      Else
      MsgBox("Cannot open the USB port for the Weather Station")
      Exit Sub
      End If
      End If
      If (GetStationTime_V(dtsTemp) = 0) Then gwdcurrent.Time = DateStamp2UnixTime(dtsTemp)
      If LoadCurrentVantageData_V() = 0 Then
      gwdcurrent.OutTempF = GetOutsideTemp_V()
      gwdcurrent.OutHum = GetOutsideHumidity_V()
      gwdcurrent.BPressure = GetBarometer_V()
      gwdcurrent.WindChillF = GetWindChill_V()
      gwdcurrent.DewPointF = GetDewPt_V()
      gwdcurrent.RainTotal = GetTotalRain_V()
      gwdcurrent.Rain24h = GetDailyRain_V()
      gwdcurrent.Rain1h = GetRainRate_V()
      gwdcurrent.WindSpeedMPH = GetWindSpeed_V()
      gwdcurrent.WindRDir = GetWindDir_V()
      gwdcurrent.WindDir = GetWindDirStr_V(sbWindDir).ToString ' This is where things go badly wrong
      gsngRainMTD = GetMonthlyRain_V()
      End If
      If gsns

      D Offline
      D Offline
      Dave Kreskowiak
      wrote on last edited by
      #2

      If you're using the System.Timers.Timer (there is no System.Timer!), the Elapsed callback is done on a background thread. If the library you're using is not written to handle that, it may screw up the library like you're seeing. You'll have to check with the people who wrote that library to find out. If possible, you can swap out the System.Timers.Timer with the Timer object in the Toolbox. That's the Forms-based Timer and runs on windows messaging Events, but needs to be used in a Windows Forms app, not a Console app or WPF. These events are always raised on the UI (startup) thread and shouldn't give you the problem that you're seeing.

      A guide to posting questions on CodeProject

      How to debug small programs
      Dave Kreskowiak

      P 1 Reply Last reply
      0
      • D Dave Kreskowiak

        If you're using the System.Timers.Timer (there is no System.Timer!), the Elapsed callback is done on a background thread. If the library you're using is not written to handle that, it may screw up the library like you're seeing. You'll have to check with the people who wrote that library to find out. If possible, you can swap out the System.Timers.Timer with the Timer object in the Toolbox. That's the Forms-based Timer and runs on windows messaging Events, but needs to be used in a Windows Forms app, not a Console app or WPF. These events are always raised on the UI (startup) thread and shouldn't give you the problem that you're seeing.

        A guide to posting questions on CodeProject

        How to debug small programs
        Dave Kreskowiak

        P Offline
        P Offline
        Peter R Fletcher
        wrote on last edited by
        #3

        Yes, it is/was a System.Timers.Timer. I had a vague memory of this sort of problem responding to switching to a Forms timer, so I did try that (my app normally keeps a main Form instantiated, even though it was written as a Console App). This, however, also resulted in a crash when the timer fired and the code executed - I left the Form open for the test.

        1 Reply Last reply
        0
        • P Peter R Fletcher

          I want to download data every five minutes from a Davis Weather Station. The code that actually talks to the hardware is in a DLL, and I don't have access to the source (or to terribly good documentation, sadly!). My code that does the downloading (below) works reliably and without problems if called in the normal way. If it is called from a System.Timer OnElapsed thread, the program (run in Debug mode) crashes immediately without reporting what is going wrong. The variables and structures starting with g are defined outside any Functions in a Module, so they have global scope, as do WSInitialized and USBSerialNumber. I think that everything else is fairly obvious. Commenting out the one line which retrieves text data into a StringBuilder seems to fix the problem, and I can do without that data, but I would like to know what is going on, since I may want to do something in the future where the use of StringBuilders to receive data (if that is what is causing the problem) is less optional.

          Private Sub Get_Davis_WeatherData(ByRef gwdcurrent As WeatherData)
          Dim dtsTemp As New DateTimeStamp
          Dim sbWindDir As New StringBuilder(5)
          If Not WSInitialized Then
          CloseUSBPort_V()
          USBSerialNumber = GetUSBDevSerialNumber_V()
          If (OpenUSBPort_V(USBSerialNumber) = 0) Then
          If (InitStation_V() = COM_ERROR) Then
          MsgBox("Cannot initialize the USB port for the Weather Station")
          Exit Sub
          Else
          SetCommTimeoutVal_V(100, 100)
          WSInitialized = True
          End If
          Else
          MsgBox("Cannot open the USB port for the Weather Station")
          Exit Sub
          End If
          End If
          If (GetStationTime_V(dtsTemp) = 0) Then gwdcurrent.Time = DateStamp2UnixTime(dtsTemp)
          If LoadCurrentVantageData_V() = 0 Then
          gwdcurrent.OutTempF = GetOutsideTemp_V()
          gwdcurrent.OutHum = GetOutsideHumidity_V()
          gwdcurrent.BPressure = GetBarometer_V()
          gwdcurrent.WindChillF = GetWindChill_V()
          gwdcurrent.DewPointF = GetDewPt_V()
          gwdcurrent.RainTotal = GetTotalRain_V()
          gwdcurrent.Rain24h = GetDailyRain_V()
          gwdcurrent.Rain1h = GetRainRate_V()
          gwdcurrent.WindSpeedMPH = GetWindSpeed_V()
          gwdcurrent.WindRDir = GetWindDir_V()
          gwdcurrent.WindDir = GetWindDirStr_V(sbWindDir).ToString ' This is where things go badly wrong
          gsngRainMTD = GetMonthlyRain_V()
          End If
          If gsns

          B Offline
          B Offline
          Bernhard Hiller
          wrote on last edited by
          #4

          Dim sbWindDir As New StringBuilder(5)
          'nothing happens with that StringBuilder, and then
          gwdcurrent.WindDir = GetWindDirStr_V(sbWindDir).ToString

          So you pass an empty StringBuilder instance with a capacity of 5 characters to the GetWindDirStr_V function. What does happen in that function? How does the signature of the function of the thirdparty dll look like, and how does your DllImport statement look like? Other values called seem to be numeric types, and this one is a string type. Hence I guess the problem is actually in the marshalling of the non-managed "string" to the managed string. Also the length of the string could be wrong: what about "SouthEast" with 9 characters or "NorthNorthWest" with 14? I.e. a simple buffer overflow, actually independent from threading issues.

          P 1 Reply Last reply
          0
          • B Bernhard Hiller

            Dim sbWindDir As New StringBuilder(5)
            'nothing happens with that StringBuilder, and then
            gwdcurrent.WindDir = GetWindDirStr_V(sbWindDir).ToString

            So you pass an empty StringBuilder instance with a capacity of 5 characters to the GetWindDirStr_V function. What does happen in that function? How does the signature of the function of the thirdparty dll look like, and how does your DllImport statement look like? Other values called seem to be numeric types, and this one is a string type. Hence I guess the problem is actually in the marshalling of the non-managed "string" to the managed string. Also the length of the string could be wrong: what about "SouthEast" with 9 characters or "NorthNorthWest" with 14? I.e. a simple buffer overflow, actually independent from threading issues.

            P Offline
            P Offline
            Peter R Fletcher
            wrote on last edited by
            #5

            The documentation of the DLL is (to put it politely) somewhat sketchy - for this routine: 'char* GetWindDirStr_V (char* dirStr) Description This function gets the currenct (sic!) wind direction in string representation. Return Values current wind direction "---" represents no data available.' The DllImport statement is:

            <DllImport("VantagePro.dll", CharSet:=CharSet.Ansi, CallingConvention:=CallingConvention.StdCall)> _
            Public Function GetWindDirStr_V(dirStr As StringBuilder) As StringBuilder
            End Function

            While string length overflow is an obvious possibility, the longest string actually passed is three characters (e.g. 'NNE'), and buffers for text wind direction strings which are explicitly sized elsewhere in Structures passed to and from the DLL are always char(5). In addition, the code was extensively exercised without any problems outside timer OnElapsed routines and worked fine - it only fails when called from interrupt code.

            1 Reply Last reply
            0
            • P Peter R Fletcher

              I want to download data every five minutes from a Davis Weather Station. The code that actually talks to the hardware is in a DLL, and I don't have access to the source (or to terribly good documentation, sadly!). My code that does the downloading (below) works reliably and without problems if called in the normal way. If it is called from a System.Timer OnElapsed thread, the program (run in Debug mode) crashes immediately without reporting what is going wrong. The variables and structures starting with g are defined outside any Functions in a Module, so they have global scope, as do WSInitialized and USBSerialNumber. I think that everything else is fairly obvious. Commenting out the one line which retrieves text data into a StringBuilder seems to fix the problem, and I can do without that data, but I would like to know what is going on, since I may want to do something in the future where the use of StringBuilders to receive data (if that is what is causing the problem) is less optional.

              Private Sub Get_Davis_WeatherData(ByRef gwdcurrent As WeatherData)
              Dim dtsTemp As New DateTimeStamp
              Dim sbWindDir As New StringBuilder(5)
              If Not WSInitialized Then
              CloseUSBPort_V()
              USBSerialNumber = GetUSBDevSerialNumber_V()
              If (OpenUSBPort_V(USBSerialNumber) = 0) Then
              If (InitStation_V() = COM_ERROR) Then
              MsgBox("Cannot initialize the USB port for the Weather Station")
              Exit Sub
              Else
              SetCommTimeoutVal_V(100, 100)
              WSInitialized = True
              End If
              Else
              MsgBox("Cannot open the USB port for the Weather Station")
              Exit Sub
              End If
              End If
              If (GetStationTime_V(dtsTemp) = 0) Then gwdcurrent.Time = DateStamp2UnixTime(dtsTemp)
              If LoadCurrentVantageData_V() = 0 Then
              gwdcurrent.OutTempF = GetOutsideTemp_V()
              gwdcurrent.OutHum = GetOutsideHumidity_V()
              gwdcurrent.BPressure = GetBarometer_V()
              gwdcurrent.WindChillF = GetWindChill_V()
              gwdcurrent.DewPointF = GetDewPt_V()
              gwdcurrent.RainTotal = GetTotalRain_V()
              gwdcurrent.Rain24h = GetDailyRain_V()
              gwdcurrent.Rain1h = GetRainRate_V()
              gwdcurrent.WindSpeedMPH = GetWindSpeed_V()
              gwdcurrent.WindRDir = GetWindDir_V()
              gwdcurrent.WindDir = GetWindDirStr_V(sbWindDir).ToString ' This is where things go badly wrong
              gsngRainMTD = GetMonthlyRain_V()
              End If
              If gsns

              B Offline
              B Offline
              Bernhard Hiller
              wrote on last edited by
              #6

              If you enclose the line gwdcurrent.WindDir = GetWindDirStr_V(sbWindDir).ToString in a try-catch block, can you catch an exception? If so, what's the message - and GetLastError's message?

              P 1 Reply Last reply
              0
              • B Bernhard Hiller

                If you enclose the line gwdcurrent.WindDir = GetWindDirStr_V(sbWindDir).ToString in a try-catch block, can you catch an exception? If so, what's the message - and GetLastError's message?

                P Offline
                P Offline
                Peter R Fletcher
                wrote on last edited by
                #7

                I had not previously tried that, but I did, with Debug.Print commands inserted to display the information. Unfortunately, the crash is a Windows "This application has stopped working" one, which is apparently not prevented by exception-trapping the line of code that provokes it, and it won't let me 'Debug' it with the open instance of VS.

                1 Reply Last reply
                0
                Reply
                • Reply as topic
                Log in to reply
                • Oldest to Newest
                • Newest to Oldest
                • Most Votes


                • Login

                • Don't have an account? Register

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • World
                • Users
                • Groups