• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 967
  • Last Modified:

Send messages (using Netmessagebuffersend in Vb.net) to multiple people simultaneously.

Ok, what i want to accomplish is if a user selects multiple people in my listbox and types a message in the message box it sends that identical message to the selected people.  However, right now it only sends to the FIRST person they select.  Is this possible?  Here's my code below:

'declare variables
    Dim strUserID As String
    Dim msg As Byte()
    Dim rc As Integer
    Dim UserName As String = Environ("username")

    'According to Platform SDK, all string parameters are Unicode, so declare accordingly
    Declare Unicode Function NetMessageBufferSend Lib "netapi32.dll" ( _
        ByVal servername As String, _
        ByVal msgname As String, _
        ByVal fromname As String, _
        ByVal buf As Byte(), _
        ByVal len As UInt32) As Integer

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'add names to listbox
        ListBox1.Items.Add("Rita Behrens")
        ListBox1.Items.Add("Emmanuel Boudon")
        ListBox1.Items.Add("Tom Duch")
        ListBox1.Items.Add("Tony Hughes")
        ListBox1.Items.Add("Kerstin Kloesener")
        ListBox1.Items.Add("Roger Kolasinski")
        ListBox1.Items.Add("Bernie Kuhlmann")
        ListBox1.Items.Add("Aravinda Paladugu")
        ListBox1.Items.Add("Carol Petrone")
        ListBox1.Items.Add("Ray Poirier")
        ListBox1.Items.Add("Krishna Reddy")
        ListBox1.Items.Add("Jan Richter")
        ListBox1.Items.Add("Marcus Roewekamp")
        ListBox1.Items.Add("Stefan Schmidgall")
        ListBox1.Items.Add("Ed Seyler")
        ListBox1.Items.Add("Eric Soboslay")
        ListBox1.Items.Add("Martin Valach")
        ListBox1.Items.Add("Brian Walker")
        ListBox1.Items.Add("Dave Williams")
    End Sub

    Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
        Select Case ListBox1.SelectedIndex
            Case 0
                strUserID = "behrri1"
            Case 1
                strUserID = "boudem1"
            Case 2
                strUserID = "duchto1"
            Case 3
                strUserID = "hughto1"
            Case 4
                strUserID = "kloeke1"
            Case 5
                strUserID = "kolaro1"
            Case 6
                strUserID = "kuhlbe1"
            Case 7
                strUserID = "palaar1"
            Case 8
                strUserID = "petrca1"
            Case 9
                strUserID = "poirra1"
            Case 10
                strUserID = "reddkr1"
            Case 11
                strUserID = "richja1"
            Case 12
                strUserID = "roewma1"
            Case 13
                strUserID = "schmst1"
            Case 14
                strUserID = "seyled1"
            Case 15
                strUserID = "soboer1"
            Case 16
                strUserID = "valama1"
            Case 17
                strUserID = "walkbr2"
            Case 18
                strUserID = "willda1"
        End Select
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        msg = System.Text.UnicodeEncoding.Unicode.GetBytes(TextBox1.Text)
        rc = NetMessageBufferSend(Nothing, strUserID, UserName, msg, Convert.ToUInt32(msg.Length))
        If rc = 0 Then
            MsgBox("Your Message was sent successfully")
        Else
            MsgBox("Could not find client.  Contact your Systems Administrator.")
        End If
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        End
    End Sub
End Class
0
lkingpinl
Asked:
lkingpinl
  • 10
  • 9
1 Solution
 
Bob LearnedCommented:
You tell me, is it possible?  Does it run?  Do you get any errors?

Bob
0
 
lkingpinlAuthor Commented:
No, like I said, it only sends to the FIRST person I select in the list.  I want it to go to all persons that I select.  I get no errors. It takes the first selection, uses that as the case statement and executes the message to them.  It completely avoids the other selections.  As if they were never selected.

So you tell me, is it possible?  :)
0
 
Bob LearnedCommented:
Ok, now that I understand (misread the question), it is very possible:

  Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    SendMessageToAllSelected()

  End Sub


  Private Sub SendMessageToAllSelected()

    For Each itemCurrent As String In Me.ListBox1.SelectedItems

      SendMessage(TextBox1.Text, itemCurrent)

    Next

  End Sub


  Private Sub SendMessage(ByVal messageText As String, ByVal userName As String)

    Dim strUserID As String = UserNameToUserID(userName)

    Dim bytMessage() As Byte = System.Text.UnicodeEncoding.Unicode.GetBytes(messageText)

    Dim rc As Integer = NetMessageBufferSend(Nothing, strUserID, userName, bytMessage, Convert.ToUInt32(messageText.Length))

    If rc = 0 Then
      MsgBox("Your Message was sent successfully")
    Else
      MsgBox("Could not find client.  Contact your Systems Administrator.")
    End If

  End Sub


  Private Function UserNameToUserID(ByVal userName As String) As String

    Dim strUserID As String = String.Empty

    Select Case userName

      Case "Rita Behrens"
        strUserID = "behrri1"

      Case "Emmanuel Boudon"
        strUserID = "boudem1"

      Case "Tom Duch"
        strUserID = "duchto1"

      Case "Tony Hughes"
        strUserID = "hughto1"

      Case "Kerstin Kloesener"
        strUserID = "kloeke1"

      Case "Roger Kolasinski"
        strUserID = "kolaro1"

      Case "Bernie Kuhlmann"
        strUserID = "kuhlbe1"

      Case "Aravinda Paladugu"
        strUserID = "palaar1"

      Case "Carol Petrone"
        strUserID = "petrca1"

      Case "Ray Poirier"
        strUserID = "poirra1"

      Case "Krishna Reddy"
        strUserID = "reddkr1"

      Case "Jan Richter"
        strUserID = "richja1"

      Case "Marcus Roewekamp"
        strUserID = "roewma1"

      Case "Stefan Schmidgall"
        strUserID = "schmst1"

      Case "Ed Seyler"
        strUserID = "seyled1"

      Case "Eric Soboslay"
        strUserID = "soboer1"

      Case "Martin Valach"
        strUserID = "valama1"

      Case "Brian Walker"
        strUserID = "walkbr2"

      Case "Dave Williams"
        strUserID = "willda1"

      Case Else
        Throw New ArgumentException("Invalid user name = " & userName)

    End Select

    Return strUserID

  End Function

Bob

   
0
Introducing Cloud Class® training courses

Tech changes fast. You can learn faster. That’s why we’re bringing professional training courses to Experts Exchange. With a subscription, you can access all the Cloud Class® courses to expand your education, prep for certifications, and get top-notch instructions.

 
lkingpinlAuthor Commented:
Still not working correctly.  I IMMEDIATELY get a "Could not find client" error (which is the error message I wrote in).  It comes so fast meaning it's not executing correctly.  I changed all the Case "(name here)" to case 0 - 18 and then I get an Application Error of "Invalid User Name = (first name selected)"

Any thoughts?

Here's my new code:

 'declare variables
    Dim strUserID As String
    Dim msg As Byte()
    Dim rc As Integer
    Dim UserName As String = Environ("username")

    'According to Platform SDK, all string parameters are Unicode, so declare accordingly
    Declare Unicode Function NetMessageBufferSend Lib "netapi32.dll" ( _
        ByVal servername As String, _
        ByVal msgname As String, _
        ByVal fromname As String, _
        ByVal buf As Byte(), _
        ByVal len As UInt32) As Integer

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'add names to listbox
        ListBox1.Items.Add("Rita Behrens")
        ListBox1.Items.Add("Emmanuel Boudon")
        ListBox1.Items.Add("Tom Duch")
        ListBox1.Items.Add("Tony Hughes")
        ListBox1.Items.Add("Kerstin Kloesener")
        ListBox1.Items.Add("Roger Kolasinski")
        ListBox1.Items.Add("Bernie Kuhlmann")
        ListBox1.Items.Add("Aravinda Paladugu")
        ListBox1.Items.Add("Carol Petrone")
        ListBox1.Items.Add("Ray Poirier")
        ListBox1.Items.Add("Krishna Reddy")
        ListBox1.Items.Add("Jan Richter")
        ListBox1.Items.Add("Marcus Roewekamp")
        ListBox1.Items.Add("Stefan Schmidgall")
        ListBox1.Items.Add("Ed Seyler")
        ListBox1.Items.Add("Eric Soboslay")
        ListBox1.Items.Add("Martin Valach")
        ListBox1.Items.Add("Brian Walker")
        ListBox1.Items.Add("Dave Williams")
    End Sub

    Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
        Select Case ListBox1.SelectedIndex
            Case 0
                strUserID = "behrri1"
            Case 1
                strUserID = "boudem1"
            Case 2
                strUserID = "duchto1"
            Case 3
                strUserID = "hughto1"
            Case 4
                strUserID = "kloeke1"
            Case 5
                strUserID = "kolaro1"
            Case 6
                strUserID = "kuhlbe1"
            Case 7
                strUserID = "palaar1"
            Case 8
                strUserID = "petrca1"
            Case 9
                strUserID = "poirra1"
            Case 10
                strUserID = "reddkr1"
            Case 11
                strUserID = "richja1"
            Case 12
                strUserID = "roewma1"
            Case 13
                strUserID = "schmst1"
            Case 14
                strUserID = "seyled1"
            Case 15
                strUserID = "soboer1"
            Case 16
                strUserID = "valama1"
            Case 17
                strUserID = "walkbr2"
            Case 18
                strUserID = "willda1"
        End Select
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        SendMessageToAllSelected()

    End Sub


    Private Sub SendMessageToAllSelected()

        For Each itemCurrent As String In Me.ListBox1.SelectedItems

            SendMessage(TextBox1.Text, itemCurrent)

        Next

    End Sub


    Private Sub SendMessage(ByVal messageText As String, ByVal userName As String)

        Dim strUserID As String = UserNameToUserID(userName)

        Dim bytMessage() As Byte = System.Text.UnicodeEncoding.Unicode.GetBytes(messageText)

        Dim rc As Integer = NetMessageBufferSend(Nothing, strUserID, userName, bytMessage, Convert.ToUInt32(messageText.Length))

        If rc = 0 Then
            MsgBox("Your Message was sent successfully")
        Else
            MsgBox("Could not find client.  Contact your Systems Administrator.")
        End If

    End Sub


    Private Function UserNameToUserID(ByVal userName As String) As String

        Dim strUserID As String = String.Empty

        Select Case userName

            Case 0
                strUserID = "behrri1"

            Case 1
                strUserID = "boudem1"

            Case 2
                strUserID = "duchto1"

            Case 3
                strUserID = "hughto1"

            Case 4
                strUserID = "kloeke1"

            Case 5
                strUserID = "kolaro1"

            Case 6
                strUserID = "kuhlbe1"

            Case 7
                strUserID = "palaar1"

            Case 8
                strUserID = "petrca1"

            Case 9
                strUserID = "poirra1"

            Case 10
                strUserID = "reddkr1"

            Case 11
                strUserID = "richja1"

            Case 12
                strUserID = "roewma1"

            Case 13
                strUserID = "schmst1"

            Case 14
                strUserID = "seyled1"

            Case 15
                strUserID = "soboer1"

            Case 16
                strUserID = "valama1"

            Case 17
                strUserID = "walkbr2"

            Case 18
                strUserID = "willda1"

            Case Else
                Throw New ArgumentException("Invalid user name = " & userName)

        End Select

        Return strUserID

    End Function


    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        End
    End Sub
End Class
0
 
lkingpinlAuthor Commented:
upped amount of points to 200
0
 
Bob LearnedCommented:
What is the return value from the API call?

Bob
0
 
Bob LearnedCommented:
I thought that you said that it sent to only 1 person?  Now, it is that it won't send to anybody, right?

Bob
0
 
Bob LearnedCommented:
Error codes:
Const ERROR_ACCESS_DENIED = 5
Const ERROR_INVALID_PARAMETER = 87
Const ERROR_NOT_SUPPORTED = 50

Bob



0
 
Bob LearnedCommented:
Also:

Dim rc As Integer = NetMessageBufferSend(String.Empty, strUserID, userName, bytMessage, Convert.ToUInt32(messageText.Length))
0
 
Bob LearnedCommented:
Also:

Private Function GetNetSendMessageStatus(nError As Integer) As String
   
Const ERROR_ACCESS_DENIED As Integer= 5
Const ERROR_BAD_NETPATH As Integer= 53
Const ERROR_INVALID_PARAMETER As Integer= 87
Const ERROR_NOT_SUPPORTED As Integer= 50
Const ERROR_INVALID_NAME As Integer= 123
Const NERR_BASE As Integer= 2100
Const NERR_Success As Integer= 0               'success
Const NERR_NetworkError As Integer= (NERR_BASE + 36)   'general network error occurred.
Const NERR_NameNotFound As Integer= (NERR_BASE + 173)  'message alias could not be found on the network.
Const NERR_UseNotFound As Integer= (NERR_BASE + 150)   'network connection could not be found.

Dim msg As String
   
   Select Case nError
   
     Case NERR_Success:            msg = "The message was successfully sent."
     Case NERR_NameNotFound:       msg = "Send To: user or workstation was not found."
     Case NERR_NetworkError:       msg = "A general network error occurred."
     Case NERR_UseNotFound:        msg = "The network connection could not be found."
     
     Case ERROR_ACCESS_DENIED:     msg = "Access to the computer denied."
     Case ERROR_BAD_NETPATH:       msg = "Sent From: server name was not found."
     Case ERROR_INVALID_PARAMETER: msg = "Invalid parameter(s) have been specified."
     Case ERROR_NOT_SUPPORTED:     msg = "Network request not supported."
     Case ERROR_INVALID_NAME:      msg = "Illegal character or malformed name."

     Case Else:                    msg = "Unknown error executing command."
     
   End Select
   
   Return msg
   
End Function

Bob
0
 
lkingpinlAuthor Commented:
An unhandled exception of type 'System.ArgumentException' occurred in InstantMessaging.exe

Additional information: Invalid user name = Martin Valach

That is what I get when I use the code shown in my last post.  It highlights the End Select statement.  
0
 
lkingpinlAuthor Commented:
i've added the code you put here, and still get the same error.

An unhandled exception of type 'System.ArgumentException' occurred in InstantMessaging.exe

Additional information: Invalid user name = Brian Walker (highest selected name in the list)

Any ideas?
0
 
Bob LearnedCommented:
I think that you might be mixing my code with yours.  Can you show me the complete set?

Bob
0
 
lkingpinlAuthor Commented:
Here you go:

    'declare variables
    Dim strUserID As String
    Dim msg As Byte()
    Dim rc As Integer
    Dim UserName As String = Environ("username")

    'According to Platform SDK, all string parameters are Unicode, so declare accordingly
    Declare Unicode Function NetMessageBufferSend Lib "netapi32.dll" ( _
        ByVal servername As String, _
        ByVal msgname As String, _
        ByVal fromname As String, _
        ByVal buf As Byte(), _
        ByVal len As UInt32) As Integer

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'add names to listbox
        ListBox1.Items.Add("Rita Behrens")
        ListBox1.Items.Add("Emmanuel Boudon")
        ListBox1.Items.Add("Tom Duch")
        ListBox1.Items.Add("Tony Hughes")
        ListBox1.Items.Add("Kerstin Kloesener")
        ListBox1.Items.Add("Roger Kolasinski")
        ListBox1.Items.Add("Bernie Kuhlmann")
        ListBox1.Items.Add("Aravinda Paladugu")
        ListBox1.Items.Add("Carol Petrone")
        ListBox1.Items.Add("Ray Poirier")
        ListBox1.Items.Add("Krishna Reddy")
        ListBox1.Items.Add("Jan Richter")
        ListBox1.Items.Add("Marcus Roewekamp")
        ListBox1.Items.Add("Stefan Schmidgall")
        ListBox1.Items.Add("Ed Seyler")
        ListBox1.Items.Add("Eric Soboslay")
        ListBox1.Items.Add("Martin Valach")
        ListBox1.Items.Add("Brian Walker")
        ListBox1.Items.Add("Dave Williams")
    End Sub

    Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
        Select Case ListBox1.SelectedIndex
            Case 0
                strUserID = "behrri1"
            Case 1
                strUserID = "boudem1"
            Case 2
                strUserID = "duchto1"
            Case 3
                strUserID = "hughto1"
            Case 4
                strUserID = "kloeke1"
            Case 5
                strUserID = "kolaro1"
            Case 6
                strUserID = "kuhlbe1"
            Case 7
                strUserID = "palaar1"
            Case 8
                strUserID = "petrca1"
            Case 9
                strUserID = "poirra1"
            Case 10
                strUserID = "reddkr1"
            Case 11
                strUserID = "richja1"
            Case 12
                strUserID = "roewma1"
            Case 13
                strUserID = "schmst1"
            Case 14
                strUserID = "seyled1"
            Case 15
                strUserID = "soboer1"
            Case 16
                strUserID = "valama1"
            Case 17
                strUserID = "walkbr2"
            Case 18
                strUserID = "willda1"
        End Select
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        SendMessageToAllSelected()

    End Sub


    Private Sub SendMessageToAllSelected()

        For Each itemCurrent As String In Me.ListBox1.SelectedItems

            SendMessage(TextBox1.Text, itemCurrent)

        Next

    End Sub


    Private Sub SendMessage(ByVal messageText As String, ByVal userName As String)

        Dim strUserID As String = UserNameToUserID(userName)

        Dim bytMessage() As Byte = System.Text.UnicodeEncoding.Unicode.GetBytes(messageText)

        Dim rc As Integer = NetMessageBufferSend(String.Empty, strUserID, userName, bytMessage, Convert.ToUInt32(messageText.Length))

        If rc = 0 Then
            MsgBox("Your Message was sent successfully")
        Else
            MsgBox("Could not find client.  Contact your Systems Administrator.")
        End If

    End Sub

    Private Function GetNetSendMessageStatus(ByVal nError As Integer) As String

        Const ERROR_ACCESS_DENIED As Integer = 5
        Const ERROR_BAD_NETPATH As Integer = 53
        Const ERROR_INVALID_PARAMETER As Integer = 87
        Const ERROR_NOT_SUPPORTED As Integer = 50
        Const ERROR_INVALID_NAME As Integer = 123
        Const NERR_BASE As Integer = 2100
        Const NERR_Success As Integer = 0              'success
        Const NERR_NetworkError As Integer = (NERR_BASE + 36)  'general network error occurred.
        Const NERR_NameNotFound As Integer = (NERR_BASE + 173) 'message alias could not be found on the network.
        Const NERR_UseNotFound As Integer = (NERR_BASE + 150)  'network connection could not be found.

        Dim msg As String

        Select Case nError

            Case NERR_Success : msg = "The message was successfully sent."
            Case NERR_NameNotFound : msg = "Send To: user or workstation was not found."
            Case NERR_NetworkError : msg = "A general network error occurred."
            Case NERR_UseNotFound : msg = "The network connection could not be found."

            Case ERROR_ACCESS_DENIED : msg = "Access to the computer denied."
            Case ERROR_BAD_NETPATH : msg = "Sent From: server name was not found."
            Case ERROR_INVALID_PARAMETER : msg = "Invalid parameter(s) have been specified."
            Case ERROR_NOT_SUPPORTED : msg = "Network request not supported."
            Case ERROR_INVALID_NAME : msg = "Illegal character or malformed name."

            Case Else : msg = "Unknown error executing command."

        End Select

        Return msg

    End Function

    Private Function UserNameToUserID(ByVal userName As String) As String

        Dim strUserID As String = String.Empty

        Select Case userName

            Case 0
                strUserID = "behrri1"

            Case 1
                strUserID = "boudem1"

            Case 2
                strUserID = "duchto1"

            Case 3
                strUserID = "hughto1"

            Case 4
                strUserID = "kloeke1"

            Case 5
                strUserID = "kolaro1"

            Case 6
                strUserID = "kuhlbe1"

            Case 7
                strUserID = "palaar1"

            Case 8
                strUserID = "petrca1"

            Case 9
                strUserID = "poirra1"

            Case 10
                strUserID = "reddkr1"

            Case 11
                strUserID = "richja1"

            Case 12
                strUserID = "roewma1"

            Case 13
                strUserID = "schmst1"

            Case 14
                strUserID = "seyled1"

            Case 15
                strUserID = "soboer1"

            Case 16
                strUserID = "valama1"

            Case 17
                strUserID = "walkbr2"

            Case 18
                strUserID = "willda1"

            Case Else
                Throw New ArgumentException("Invalid user name = " & userName)

        End Select

        Return strUserID

    End Function


    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        End
    End Sub
End Class
0
 
Bob LearnedCommented:
Sorry for the delay:

Private Function UserNameToUserID(ByVal userName As String) As String

    Dim strUserID As String = String.Empty

    Select Case userName

      Case "Rita Behrens"
        strUserID = "behrri1"

      Case "Emmanuel Boudon"
        strUserID = "boudem1"

      Case "Tom Duch"
        strUserID = "duchto1"

      Case "Tony Hughes"
        strUserID = "hughto1"

      Case "Kerstin Kloesener"
        strUserID = "kloeke1"

      Case "Roger Kolasinski"
        strUserID = "kolaro1"

      Case "Bernie Kuhlmann"
        strUserID = "kuhlbe1"

      Case "Aravinda Paladugu"
        strUserID = "palaar1"

      Case "Carol Petrone"
        strUserID = "petrca1"

      Case "Ray Poirier"
        strUserID = "poirra1"

      Case "Krishna Reddy"
        strUserID = "reddkr1"

      Case "Jan Richter"
        strUserID = "richja1"

      Case "Marcus Roewekamp"
        strUserID = "roewma1"

      Case "Stefan Schmidgall"
        strUserID = "schmst1"

      Case "Ed Seyler"
        strUserID = "seyled1"

      Case "Eric Soboslay"
        strUserID = "soboer1"

      Case "Martin Valach"
        strUserID = "valama1"

      Case "Brian Walker"
        strUserID = "walkbr2"

      Case "Dave Williams"
        strUserID = "willda1"

      Case Else
        Throw New ArgumentException("Invalid user name = " & userName)

    End Select

    Return strUserID

  End Function

Bob
0
 
lkingpinlAuthor Commented:
I get an immediate "Could not find client.  Contact you Administrator."
0
 
lkingpinlAuthor Commented:
Whether I choose one person or more than one person I get that message.  It happens immediately, which tells me it is not excuting the send message properly.  In my original code I would get that message after about 15 seconds.  it usually meant the user's messenger service needs to be restarted.  

But with this code, no messages get sent at all.
0
 
Bob LearnedCommented:
Use GetNetSendMessageStatus to get the real error message from the return code.

Dim errorMessage As String = GetNetSendMessageStatus(rc)

Bob
0
 
lkingpinlAuthor Commented:
No real error message appears.  I get the same thing.  I'm all confused....  ;)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 10
  • 9
Tackle projects and never again get stuck behind a technical roadblock.
Join Now