I am developing my first VB program. The program's main task is to send Skype messages using SendKeys.
I managed to send messages successfully but it is kinda slow as I need to use System.Threading.Thread.Sleep(1000) to properly send messages. If I remove the Sleep(1000) function, the program starts to do weird things like partial messages, some dialogs not showing up and at the end Skype crashed and I couldn't type anything.
Problem: How to remove Sleep(1000) to send messages without such large pause? If I have more than 500 contacts it takes lot of time.
My code:
Dim all() As String = System.IO.File.ReadAllLines(appPath)
Dim message_text As String = TextBox1.Text
If all.Length > 0 Then
For i = 0 To all.Length - 1
System.Threading.Thread.Sleep(1000) '' < ---this line
Skype.Client.OpenMessageDialog(all(i))
Skype.Client.Focus()
SendKeys.SendWait(message_text + " - " + DateTime.Now.ToString())
SendKeys.SendWait("{ENTER}")
System.Threading.Thread.Sleep(100)
Next
MessageBox.Show("Ziņa nosūtīta Skype lietotājiem")
Else
End If
I don't understand why it sometimes sends just partial messages as I am using SendKeys.SendWait that should wait till message text is copied in dialog and then Sending "Enter" key.
Related
I'm busy with software that uses Rs232 Com port communication module.
I send a roll-call out 1st to all users (Ping all users) and then wait 10 min to receive all the roll-calls back, thereafter I send to all the outstanding names (Ping outstanding active individual) using a listview with the remaining members names, I send all the outstanding names in burst of 3's with 3.5 sec in-between. I'm using Threading.Thread.Sleep() to prevent flooding my repeater.
Is there an alternative to Threading.Thread.Sleep() that allows the software to still receive roll-call feedbacks sending the roll-Call pings through the Rs232 Module?
For i As Integer = 0 To LsvCopyRemove.Items.Count - 1
If LsvCopyRemove.Items(i).SubItems(11).Text = "Yes" Then
Dim Group As String = LsvCopyRemove.Items(i).Text
StringData = vbCrLf & "MY String Information comes here"
_rs232.Write("" & vbCrLf)
Threading.Thread.Sleep(500)
_rs232.Write(StringData & vbCrLf) 'The text contained in the txtText will be sent to the serial port as ascii
Threading.Thread.Sleep(3500)
_rs232.Write(StringData & vbCrLf)
Threading.Thread.Sleep(3500)
_rs232.Write(StringData & vbCrLf)
Threading.Thread.Sleep(3500)
Me.rtbTX.AppendText(.Text & vbCr)
'***********************************************************************************************************************************************************************************************************************************************
.Text = String.Empty & vbCrLf
Data = Encoding.Default.GetBytes(.Text)
_rs232.SendData(Data)
'***************************************************************************************************************************************************************************************************************************************************
Threading.Thread.Sleep(6500)
End If
Next
What you are looking for is asynchronous programming, which allows you to execute multiple threads simultaneously. In your example, you'll have to execute the code above which sends the outstanding names in a seperate thread. There are two ways to accomplish this:
Using System.Threading: Put the code you want to execute in a seperate thread in a sub routine, then call it like this:
Dim newThread As New Threading.Thread(AddressOf myFunction)
newThread.Start()
Now the code in the function called myFunction is executed, but the execution of the current function is continued, which allows you to still receive events.
You can also use the newer Threading.Tasks namespace, which can be used in a similar way:
Dim newTask As Task = Task.Factory.StartNew(AddressOf myFunction)
I need to validate if an incoming mailitem is signed in Outlook 2010.
If a mailitem is not signed, it should be moved into a "NOSIG"-folder.
While researching, I found (and sort of confirmed) that Outlook 2010 modifies the MessageClass to "IPM.Note", so I tried to use the PropertyAccessor and read the Security-Flags.
Here's my code so far:
Sub TRCR(MAIL_ITEM As MailItem)
Dim PR_SECURITY_FLAGS As Integer
On Error Resume Next
'Security-Flags: 0=none, 1=encrypted, 2=signed, 3=both
PR_SECURITY_FLAGS = MAIL_ITEM.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x6E010003")
'Modulo because, sometimes the flags value is added to a multiple of 32... <unfortunately I lost the source>
If (PR_SECURITY_FLAGS > 32) Then PR_SECURITY_FLAGS = PR_SECURITY_FLAGS Mod 32
If PR_SECURITY_FLAGS = 2 Or PR_SECURITY_FLAGS = 3 Then
'Do all that fancy stuff I want to with that signed Mail
Else
MAIL_ITEM.Move Application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Folders.Item("NOSIG")
End If
End Sub
I use an Outlook rule to run that script on every incoming E-Mail.
It sometimes moves signed mails to the NOSIG folder.
In those cases, the PR_SECURITY_FLAGS were both at 0, before and after that Modulo-Codeline. So being 0, the script worked right but since the mail was signed, the flag shouldn't have been 0 but 2.
I resent the same signed mail dozens of times, just to always see the same thing happening. Most of them are treated correctly while a few always appeared to show the flag 0 instead of 2 while they were signed.
I tried to pause the script for 1-5 seconds with Application.Wait Now + TimeSerial(0, 0, 1) thinking that the script may be too fast for the PropertyAccessor or something, but the pause didn't work. (I couldn't "feel" that five seconds delay while processing multiple mails.)
I start to think that it is an Outlook problem (maybe manipulating Security-Flags similar to MessageClass but not every time).
PR_SECURITY_FLAGS is only set on the outgoing messages to tell Outlook to encrypt the message when it is actually sent. It will not be present on the incoming messages - take a look at the messages with OutlookSpy (I am its author - click IMessage button).
For the incoming messages, you'd think you could check the MessageClass property and see if it is "IPM.Note.SMIME.MultipartSigned", but OOM tries real hard to represent signed and encrypted messages as the regular IPM.Note messages. You would have to either bypass OOM completely and use Extended MAPI (C++ or Delphi only) or you can use Redemption (any language, including VBA, I am its author). Something like the following would let you check the real message class:
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set SourceMsg = Session.GetRDOObjectFromOutlookObject(MAIL_ITEM , true)
MsgBox SourceMsg.MessageClass
What is the best way to access a serial port from VBA?
I have a need for some of our sales reps to be able to send a simple string over the serial port from an action button in PowerPoint. I don't commonly use VBA, especially for anything like this. Normally I would turn it into an application of some sort, but I actually don't think the idea is that bad. It will be a handy tool for them to demo this device with while on a projector and talking to other sales guys and non technical people. Also, this sales guy will have no problem making small modifications to the VBA or PowerPoint presentation, but would not do as well with recompiling a .NET application.
I know we could do it through a batch file run from the presentation on the action, but that doesn't make me very happy. I figure we could probably access a COM object and run from there, but again I am not real up on the latest and greatest libraries to use in VBA, and it would also be nice to get a quick little primer in how to easily open, send and close the connection.
Since this will need to be run on multiple people's computers, it would be nice if it would be easily transportable to other machines. I should be able to say it has to run on Office 2007 and Windows XP. Compatibility with anything else would be a nice bonus though.
How should I go about handling this? Any good tips or tricks? Library recommendations?
The Win32 API handles the serial port as a file. You can access the serial ports directly by calling these API functions from within VBA. I had to do this for an old .NET application but VBA is no different.
Rather than hash it out for you on this site, here's a reference I've hung onto over the years. How to perform serial port communications in VBA
Sub Stinky()
Dim COM_Byte As Byte
Dim Received_Lines As Long
Dim Input_Buffer As String
Dim Output_Buffer As String
Dim Chars2Send As Long
Dim CharsRemaining As Long
Dim lfsr As Long
Open "COM7:9600,N,8,1" For Random As #1 Len = 1
Input_Buffer = ""
CharsRemaining = 0
Do
Get #1, , COM_Byte
If COM_Byte Then
If COM_Byte = 13 Then ' look for CR line termination
Debug.Print Input_Buffer, Now ' print it
Input_Buffer = "" ' and clear input buffer
' generate some output (9 characters)
lfsr = &H3FFFFFFF - 2 ^ (Received_Lines And 15)
Output_Buffer = "?########"
Chars2Send = 9
CharsRemaining = 9
For j = 0 To 2
Mid(Output_Buffer, 2 + j, 1) = Chr(Asc(Mid(Output_Buffer, 2 + j, 1)) + (31 And Int(lfsr / 32 ^ (2 - j))))
Next j
Debug.Print Output_Buffer
' show what I generated
Received_Lines = Received_Lines + 1 ' keep track of received line count
Else
Input_Buffer = Input_Buffer & Chr(COM_Byte) ' assemble output buffer
' process any characters to send
If CharsRemaining Then
CharsRemaining = CharsRemaining - 1
COM_Byte = Asc(Mid(Output_Buffer, Chars2Send - CharsRemaining, 1))
Put #1, , COM_Byte
End If
End If
End If
DoEvents
Loop
Close
End Sub
This works for me. I'm not sure if the OPEN actually sets up the Baud rate, as I first used TeraTerm.
My COM port is a USB connection to a BASYS3 prototyping kit. It is spewing characters at 9600, records of 36 characters ending with CR. I can randomly send commands of 9 characters. In the above code, I generate these command strings every time I have received a new line.
The way I chose which character to send is a little clunky: perhaps a better way is to have a character pointer and a number of characters, and when those go equal to set them both to zero.
Here is a brief module of VBA code that can send and receive messages on a PC serial port. This is not very elegant, but it is simple and should work on modern versions of Excel and Windows.
You are left on your own to expand the functionality and store or parse the messages. This just shows the low-level stuff to deal with the serial port.
The first 5 lines declare the millisecond "Sleep" library function (based on Excel version).
The SerialPort() subroutine outlines the steps to open the port, transmit some data, receive some data, try again to receive some data (to show that it really does not run afoul of the "end of file" error), and close the port.
#If VBA7 Then ' Excel 2010 or later
Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal Milliseconds As LongPtr)
#Else ' Excel 2007 or earlier
Public Declare Sub Sleep Lib "kernel32" (ByVal Milliseconds As Long)
#End If
Public Sub SerialPort()
' open a COM port, transmit a message, gather results, close the port.
' open the COM port as file #1
Debug.Print "Open COM port 4"
Open "COM4:115200,N,8,1" For Binary Access Read Write As #1
transmit$ = Chr(2) + "Hello, World." + Chr(13)
receiveDummy$ = "~~~"
' transmit a message
Put #1, , transmit$
Debug.Print "Message sent."
' wait a bit for a response
Sleep 100
' check for received message
Debug.Print "Look for incoming message."
On Error Resume Next
Do While True
receive$ = receiveDummy$ 'dummy value
Input #1, receive$
If receive$ = receiveDummy$ Then Exit Do 'the string didn't change, so move on
Debug.Print receive$
Loop
On Error GoTo 0
' do it again to show that the empty input queue doesn't stop the flow
Debug.Print "Look again for incoming message (should not stop on error)."
On Error Resume Next
Do While True
receive$ = receiveDummy$ 'dummy value
Input #1, receive$
If receive$ = receiveDummy$ Then Exit Do 'the string didn't change, so move on
Debug.Print receive$
Loop
On Error GoTo 0
' close the serial port
Debug.Print "Close COM port."
Close #1
Debug.Print "Done."
End Sub
I am in the process of developing a VB.Net console app to get ID & password from users and should pop a message when invalid ID or password is entered, but I am stuck with a peculiar behavior observed while using Message box in console app. When the first message box is shown, its Out-Of-Focus & we explicitly need to bring the message box to focus. But the next subsequent message boxes are In-Focus.
Below is just the sample code.
Sub Main()
Start:
Console.WriteLine("Press Enter")
Console.ReadLine()
MsgBox("Good Day")
GoTo Start
End Sub
Just want to know why such thing is happening & what should be done so the first message box also will be In-Focus.?
You can use the MessageBoxOptions.ServiceNotification to show the dialog on top.
This is converted from a C# application, so not exactly sure if this is correct VB.NET (it should be though):
MsgBox( "Good Day"
, ""
, MessageBoxButtons.OK
, MessageBoxIcon.Asterisk
, MessageBoxDefaultButton.Button1
, MessageBoxOptions.ServiceNotification
)
But note this:
You shouldn't use a MessageBox inside a Console application. These are just two different worlds.
To explain why:
What do you expect when you run this application remotely using the console? There is no way to show that messagebox then. Use Console.WriteLine, but with different coloring if you want to show something is in error, or a warning, or something good.
I'm in the process of writing some code to download and process the attachments of email messages and then process them. The code is working as required in some cases, but still has some major problems.
Whenever the code loads the attachment into a file on the local disk, it takes a very long time to do so and often times out with the following exception as a result of the slow download:
A first chance exception of type 'Microsoft.Exchange.WebServices.Data.ServiceRequestException' occurred in Microsoft.Exchange.WebServices.dll
I may be wrong, but if the exchange server in question is on the same gigabit network as the server running the code and outlook has fast access to emails, attachments, etc then attachments should download considerably faster than they do and much more consistently. Here are some example of download/load times:
800KB Zip - 1m 4s
840KB Zip - 6m 18s
1.33MB Zip - 11m 23s
2.78MB Zip - 17m 3s
I have tried setting the EWS connection timeout setting to 300000ms instead of the default 100000ms to give the attachments more time to download and the number of exceptions has decreased slightly but the waiting time is now way too long.
The code does run in threads, no more than 8 at a time (10 being the throttling limit for EWS i believe), but i cant imagine that would make much of a difference. (It hasn't done when I've been testing single emails at a time).
Here is the threaded code that downloads the attachments (some un-related bits removed for simplicity):
Dim strMessageFolder As String
' Prepare the directory where this emails attachments will be stored
strMessageFolder = g_strFolder_Temp & strMessageID & "\"
' Create a folder to store the attachments for this email
Call FileSystem_CreateFolder(strMessageFolder, True)
' Process the emails attachments
For Each emailAttachment In emailMessage.Attachments
Dim fileattach As FileAttachment
'Dim fileattachStream As FileStream
Dim strAttachmentFile As String
' Prepare for the downloading of the attachment
fileattach = emailAttachment
blnTryFailed = False
intAttempts = 0
strAttachmentFile = strMessageFolder & fileattach.Name
' Handle up to 3 download attempts
Do
Try
' Try to download the attachment - Method 1
fileattach.Load(strAttachmentFile)
' Try to download the attachment - Method 2
'fileattachStream = New FileStream(strAttachmentFile, FileMode.OpenOrCreate, FileAccess.ReadWrite)
'fileattach.Load(fileattachStream)
'fileattachStream.Close()
'fileattachStream.Dispose()
blnTryFailed = False
Catch ex As Exception
blnTryFailed = True
' Ensure the failed download is deleted
Call FileSystem_DeleteFile(strAttachmentFile)
intAttempts += 1
End Try
Loop While blnTryFailed And intAttempts < 3
' If the attachment download was unsuccessful then we cannot process the current email
If blnTryFailed = True Then
emailMessage.IsRead = False
'message.Subject = message.Subject & " - Attachment download failed, skipped"
Try
emailMessage.Update(ConflictResolutionMode.AutoResolve)
Catch ex As Exception
Call Logging_Add("Unable to mark email as skipped", strMessageID, "Debug")
End Try
Exit Sub
End If
As mentioned previously, im aware of the Exchange throttling but cannot find anything related to the speed at which attachments are downloaded.
So my question is what could possibly be causing such slow download speeds?
I have the same issue with my app. The problem was caused by default EWS setting which writes to Console all HttpRequest and HttpResponse messages between EWS and application. Turning off TraceFlags was blessing.
My code in c#:
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
service.TraceFlags = TraceFlags.None;