I have a windows service with a timer. About 3 times a day the timer uploads files to different ftp servers. I set the timer, upload the files, then set the next time. This worked fine for a while, until I added another ftpserver for uploading files. When uploading to that ftpserver the project hangs at manualresetevent.waitone (even though the folder was uploaded)
Here part of the code, let me know if more is needed.
Dim state As New FtpState
Dim request As FtpWebRequest = DirectCast(WebRequest.Create(target), FtpWebRequest)
request.Method = WebRequestMethods.Ftp.UploadFile
request.Credentials = mycredentials
state.Request = request
state.FileName = fileName
' Get the event to wait on.
waitObject = state.OperationComplete
' Asynchronously get the stream for the file contents.
request.BeginGetRequestStream(New AsyncCallback(AddressOf EndGetStreamCallback), state)
' Block the current thread until all operations are complete.
waitObject.WaitOne()
' The operations either completed or threw an exception.
If state.OperationException IsNot Nothing Then
Throw New Exception(state.OperationException.ToString)
Else
Publish.sendMail("Upload completed for filename:" & fileName & state.StatusDescription)
End If
End If
This ftpserver works a little different than the others that I'm using and I'm not sure if thats the cause of the problem.
Here is the difference: I upload a zip folder (not just files) which can be quite large and soon after it's uploaded, it is being moved from that ftpserver.
(Whereas the other ftpservers leave the files on the ftpserver)
I think this problem only started once the zipfolder got larger.
I know that it is uploaded and then deleted from there.
So if the upload completed, why does it get stuck at waitone?
Here my endstreamcallback function
Private Shared Sub EndGetStreamCallback(ByVal ar As IAsyncResult)
Dim state As ftpState = DirectCast(ar.AsyncState, ftpState)
Dim requestStream As Stream = Nothing
' End the asynchronous call to get the request stream.
Try
requestStream = state.Request.EndGetRequestStream(ar)
' Copy the file contents to the request stream.
Const bufferLength As Integer = 2048
Dim buffer As Byte() = New Byte(bufferLength - 1) {}
Dim count As Integer = 0
Dim readBytes As Integer = 0
Dim stream As FileStream = File.OpenRead(state.FileName)
Do
readBytes = stream.Read(buffer, 0, bufferLength)
requestStream.Write(buffer, 0, readBytes)
count += readBytes
Loop While readBytes <> 0
'Console.WriteLine("Writing {0} bytes to the stream.", count)
' IMPORTANT: Close the request stream before sending the request.
requestStream.Close()
' Asynchronously get the response to the upload request.
state.Request.BeginGetResponse(New AsyncCallback(AddressOf EndGetResponseCallback), state)
' Return exceptions to the main application thread.
Catch e As Exception
Publish.sendMail("Could not get the request stream.")
state.OperationException = e
state.OperationComplete.[Set]()
Return
End Try
End Sub
' The EndGetResponseCallback method
' completes a call to BeginGetResponse.
Private Shared Sub EndGetResponseCallback(ByVal ar As IAsyncResult)
Dim state As FtpState = DirectCast(ar.AsyncState, FtpState)
Dim response As FtpWebResponse = Nothing
Try
response = DirectCast(state.Request.EndGetResponse(ar), FtpWebResponse)
response.Close()
state.StatusDescription = response.StatusDescription
' Signal the main application thread that
' the operation is complete.
state.OperationComplete.[Set]()
' Return exceptions to the main application thread.
Catch e As Exception
Publish.sendMail("Error getting response.")
state.OperationException = e
state.OperationComplete.[Set]()
End Try
End Sub
Related
I have some old code that writes binary data to the Response object's BinaryWrite() method (Classic ASP). It sends the data in 4MB chunks to BinaryWrite(), but now I'm wondering whether that ever worked and whether BinaryWrite() is even designed to handle serial chunks of data (or whether it should only be called, at most, once per page request).
I found this link that describes how the "Response Buffering Limit" should be increased, and increasing it seems to have solved the issues I was seeing (without using my chunking code at all).
https://learn.microsoft.com/en-us/troubleshoot/iis/http-500-response-binarywrite
This is the old code in question:
HRESULT STDMETHODCALLTYPE CQVMActiveHost::WriteData (const VOID* pcvData, DWORD cbData, __out DWORD* pcbWritten)
{
HRESULT hr;
DISPPARAMS dispParams = {0};
VARIANT vWrite = {0}, vResult = {0};
Check(LoadResponseObject());
dispParams.cArgs = 1;
dispParams.rgvarg = &vWrite;
if(m_fSupportsBinary)
{
SAFEARRAYBOUND Bound;
DWORD cbRemaining = cbData;
Bound.lLbound = 0;
vWrite.vt = VT_ARRAY | VT_UI1;
while(0 < cbRemaining)
{
PVOID pbPtr;
Bound.cElements = min(cbRemaining, 4 * 1024 * 1024);
vWrite.parray = SafeArrayCreate(VT_UI1, 1, &Bound);
CheckAlloc(vWrite.parray);
SafeArrayAccessData(vWrite.parray, &pbPtr);
CopyMemory(pbPtr, pcvData, Bound.cElements);
SafeArrayUnaccessData(vWrite.parray);
VariantClear(&vResult);
Check(m_pResponse->Invoke(m_dispidBinaryWrite, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispParams, &vResult, NULL, NULL));
SafeArrayDestroy(vWrite.parray);
vWrite.parray = NULL;
pcvData = reinterpret_cast<const BYTE*>(pcvData) + Bound.cElements;
cbRemaining -= Bound.cElements;
}
vWrite.vt = VT_EMPTY;
}
else
I've seen a couple different behaviors with the old code. In some tests, the first call to BinaryWrite() succeeded, but subsequent calls failed with the "exception occurred" HRESULT. In other tests, the calls seemed to succeed, but the browser didn't receive any data.
Are there any scenarios where it would make sense to make multiple calls to BinaryWrite() with chunked data?
Or should I always increase the "Response Buffering Limit" value to more than 4MB and just make a single call to BinaryWrite() with the full data?
Thanks!
I have to wonder whether the Response.Buffer property was false when I originally wrote the code above. What I've found is the following:
The Response.BinaryWrite() method MAY be called multiple times per page request.
If a large amount of data is to be returned to the client, then split the data into multiple calls to Response.BinaryWrite().
The "Response Buffering Limit" value in IIS (for ASP) is 4MB by default.
If Response.Buffer is true, then multiple calls to Response.BinaryWrite() may be made until the total data reaches the "Response Buffering Limit" value. At that point, Response.Flush() MUST be called. Otherwise, attempting to send more data results in error 0x80020009.
If Response.Buffer is false, then do NOT call Response.Flush(), but do split the data into multiple (smaller) calls to Response.BinaryWrite().
As an example, I was trying to send a 12MB file using multiple calls to Response.BinaryWrite() with each chunk being 4MB. Buffering was enabled, so the first call succeeded, but the next call failed. Raising the "Response Buffering Limit" to 16MB "solved" the issue but increased the buffering allocation for ASP.
Ultimately, I've modified my chunking code to first query the Response.Buffer property. The data is always sent in smaller fragments to Response.BinaryWrite(), but Response.Flush() is also called if buffering is enabled.
Finally, don't set the Content-Length header. The browser may not know how many bytes will be downloaded, but it will receive the file correctly without manually setting that header. Setting that header breaks the download.
And the final ASP script:
function GoDownloadFile (strPath)
{
var idxName = strrchr(strPath, '/');
var strFolder = left(strPath, idxName + 1);
var strFile = right(strPath, len(strPath) - (idxName + 1));
var oFS = Security.GetChannel().OpenFileSystem();
oFS.Folder = strFolder;
Response.ContentType = Host.GetContentType(strFile);
Response.AddHeader("Content-Disposition", "attachment; FileName=\"" + strFile + "\"");
Host.BinaryWrite(oFS.ReadFile(strFile));
}
Thanks for reading.
I have built a VB6 DLL (VB_InterFace just for a name) that talks to a C# DLL (C#_Driver just for a name) that talks to a Bluetooth Device.
The Demo VB6 test app (VB_Demo just for a name) I created as stage one works fine, does what it is supposed to. It calls the VB_Interface and Opens and Closes the BTDevice. Additional functions also work fine.
However on placing the operational code from VB_Interface into another DLL that is the live operations DLL, Open works fine, but Close is throwing an error. "Variable not defined" when returning from the C#_Driver.
I just can't see why, the code is the same, the process is only marginally different. By this I mean ;
In the VB_Demo I have two buttons "Open" "Close" and when I click on these I get the feedback that I expect from the BTDevice.
Private Sub btnOpenPort_Click()
'MsgBox steps(0)
ReDim steps(5)
Dim rc As HF4000_ResultCodes
'rc = driver.OpenSerial(cmbPorts.Text)
If driver.OpenSerial(cmbPorts.Text) = True Then
Private Sub btnClosePort_Click()
Dim rc As HF4000_ResultCodes
If driver.CloseSerial("COM4") = True Then
However in the live DLL it just executes the same functions internally without being initiated by a button click.
' See IScanDevice documentation.
' #see IScanDevice#OpenDevice
Private Function IScanDevice_OpenDevice() As Scanning.Scan_ResultCodes
(truncated slightly)
50 If driver.OpenSerial("COM4") = True Then
rc = READY
MsgBox "Connected to the device successfully."
' See IScanDevice documentation.
' #see IScanDevice#CloseDevice
Private Function IScanDevice_CloseDevice() As Scanning.Scan_ResultCodes
(truncated slightly)
50 If driver.CloseSerial("COM4") = True Then
60 rc = READY
70 IScanDevice_CloseDevice = Scan_Success
clsDriver.cls
Public Event OnStateChanged(newState As String)
Public Event OnDataUpdated()
Dim WithEvents CSharpInteropServiceEvents As CSharpInteropService.LibraryInvoke
Dim load As New LibraryInvoke
Private Sub Class_Initialize()
Set CSharpInteropServiceEvents = load
End Sub
Private Sub CSharpInteropServiceEvents_MessageEvent(ByVal newState As String)
If newState = "OpenForm1" Then
' FormDummy2.Show ' Not required
End If
If State <> newState Then
State = newState
RaiseEvent OnStateChanged(State)
GetDriverData
End If
End Sub
Private Function BluetoothTestInvoke(load, functionName, param)
BluetoothTestInvoke = load.GenericInvoke("BluetoothTest.dll", "BluetoothTest.Class1", functionName, param)
End Function
Function OpenSerial(portNumber) ' "COM4"
Dim param(0) As Variant
Dim retorno As Variant
param(0) = portNumber
retorno = BluetoothTestInvoke(load, "OpenSerial", param)
OpenSerial = retorno(0) <<<<<<< Works fine returns TRUE
End Function
Function CloseSerial(portNumber) ' "COM4"
Dim param(0) As Variant
Dim retorno As Variant
param(0) = portNumber
retorno = BluetoothTestInvoke(load, "CloseSerial", param)
CloseSerial = retorno(0) <<<<<<<<< "Error Subscript Out of Range"
End Function
What I have discovered is this - and I guess this is the reason why the Close is not working. The question is why is this situation occurring ...
When driver.OpenSerial executes, it hits > Function OpenSerial
Within Function OpenSerial it executes BluetoothTestInvoke where "load" is "CSharpInteropService.LibraryInvoke"
From there it moves to - Sub CSharpInteropServiceEvents_MessageEvent
.. and everything is fine.
However when I then execute driver.CloseSerial after that, it hits > Function CloseSerial
Within Function OpenSerial it executes BluetoothTestInvoke where "load" is "CSharpInteropService.LibraryInvoke"
Now here it "should" move to - Sub CSharpInteropServiceEvents_MessageEvent
However No, it just drops to the next line which is CloseSerial = retorno(0)
and this is where I get the "Subscript out of range" error for retorno(0)
For some reason in the CloseSerial it is not invoking "load"
BluetoothTestInvoke(load, "CloseSerial", param)
Thoughts and suggestions much appreciated.
UPDATE
Quite right, one should never assume anything.
On the tips I started digging deeper into the C# Library. It turns out the "param" value that is the Bluetooth port is passed into the CloseSerial call, and from there is is passed around within the external C# library dll. At one stage it is reset so the port number that should be handled is lost, thus it doesn't close but specifically the "expected" data was not returned to the calling app.
param(0) = portNumber
retorno = BluetoothTestInvoke(load, "CloseSerial", param) << param was being reset in the external library.
I am have problems with an older classic ASP application where read receipts are employed in the code. This particular routine has been used for a number of years successfully but recently we have migrated to a new server with Windows 2008 r2, IIS 7.5 and SmarterMail 11.07 client. Now whenever the application attempts to send a server generated email, the SmarterMail logs are showing it successfully receives and authenticates the submission, but seems to terminate or abort the connection without cause and won't send the email without any errors. I'm at a loss here because like I stated, this routine has worked without problems for some time now and if we don't select the "read-receipt" option in the ASP application the email distributes just fine. I have included a shortened version of the code below and mainly looking for validation that the code for all intended purposes should work as is and if anyone may know of similar issues related to this within SmarterMail itself, like some kind of default security setting I am unaware of. Incidentally, if we manually use the SmarterMail webmail interface, we can successfully send mail with read receipts, so I know it should be possible.
- Thank you kindly!
Code Example
set Mail = Server.CreateObject("CDO.Message")
'Basic configuration
Mail.AutoGenerateTextBody = 0
Mail.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserver") = strHost
Mail.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
Mail.Configuration.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = strPort
Mail.Configuration.Fields.Update
Mail.Fields("urn:schemas:mailheader:X-Mailer") = "Custom EMailer"
Mail.Fields.update
'Priority
Mail.Fields("urn:schemas:mailheader:X-Priority") = emPriority
Mail.Fields("urn:schemas:mailheader:X-MSMail-Priority") = emPriorityTxt
Mail.Fields("urn:schemas:httpmail:importance") = emPriority
Mail.Fields.update
'Addressing
With Mail
.From = strFrom
.ReplyTo = strReplyTo
.To = strTo
.CC = strCc
.BCC = strBCc
End With
'Attachments
if len(sfls) > 0 then
if instr(1,sfls,",",1) > 0 then
strAttachments = split(sfls,",",-1,1)
else
strAttachments = sfls
end if
if isarray(strAttachments) then
for x = 0 to ubound(strAttachments)
Mail.AddAttachment strAttachments(x)
next
else
Mail.AddAttachment strAttachments
end if
end if
'Body
Mail.Subject = strSubject
if isHTML then
Mail.HTMLBody = strBody
else
Mail.TextBody = strBodyTxt
end if
'###################################################################
'If this section is included the email will not send, times out or
'connection is terminated, according to the SmarterMail logs
'###################################################################
' Read/Delivery Receipt
if isRead then
Mail.Fields("urn:schemas:mailheader:disposition-notification-to") = rrReplyTo
Mail.Fields("urn:schemas:mailheader:return-receipt-to") = rrReplyTo
Mail.DSNOptions = 14
Mail.Fields.Update
end if
'###################################################################
'Send Message
strErr = ""
bSuccess = False
On Error Resume Next
Mail.Send
If Err <> 0 Then
strErr = Err.Description
else
bSuccess = True
End If
set Mail = nothing
============================================================
I got a problem with a project I'm making
it's program that gets signature from a wacom
sign pad It works fine at first run then whenever
I try to enter another signature for the second
time it gets this error message
Here is the code:
Dim sigCtl As New SigCtl
Dim dc As New DynamicCapture
Dim res As DynamicCaptureResult
sigCtl.Licence = "AgAZAPZTkH0EBVdhY29tClNESyBTYW1wbGUBAoECA2UA"
res = dc.Capture(sigCtl, "who", "why", vbNull, vbNull)
If (res = DynamicCaptureResult.DynCaptOK) Then
print("signature captured successfully")
Dim sigObj As SigObj
sigObj = sigCtl.Signature
sigObj.ExtraData("AdditionalData") = "VB test: Additional data"
Dim filename As New String("sig1.png")
sigObj.RenderBitmap(filename, 200, 150, "image/png", 0.5F, &HFF0000, &HFFFFFF, -1.0F, -1.0F, _
RBFlags.RenderOutputFilename Or RBFlags.RenderColor32BPP Or RBFlags.RenderEncodeData)
sigImage.Load(filename)
Else
print("Signature capture error res=" & res)
Select Case res
Case DynamicCaptureResult.DynCaptCancel
print("signature cancelled")
Case DynamicCaptureResult.DynCaptError
print("no capture service available")
Case DynamicCaptureResult.DynCaptPadError
print("signing device error")
Case Else
print("Unexpected error code ")
End Select
End If
The error occurs around sigobj.rederbitmap syntax it gives of the System.Runtime.InteropServices.COMException exception
I'm kinda puzzled whats wrong here since it always work at first try
Thanks in advance*strong text*
I had the same problem with a wacom STU-530 device.
What worked for me was to change the filename string each time the user wanted to use another test.
Dim rndm As New Random
Dim serial As Integer = rndm.Next(1, 9999)
Dim str_serial As String = CStr(serial)
Dim filename As New String("sig_" & str_serial.PadLeft(4, "0") & ".png")
Im a complete novice to the "best practices" etc of writing in any code.
I tend to just write it an if it works, why fix it.
Well, this way of working is landing me in some hot water. I am writing a simple windows service to server a single webpage. (This service will be incorperated in to another project which monitors the services and some folders on a group of servers.)
My problem is that whenever a request is recieved, the memory usage jumps up by a few K per request and keeps qoing up on every request.
Now ive found that by putting GC.Collect in the mix it stops at a certain number but im sure its not meant to be used this way. I was wondering if i am missing something or not doing something i should to free up memory.
Here is the code:
Public Class SimpleWebService : Inherits ServiceBase
'Set the values for the different event log types.
Public Const EVENT_ERROR As Integer = 1
Public Const EVENT_WARNING As Integer = 2
Public Const EVENT_INFORMATION As Integer = 4
Public listenerThread As Thread
Dim HTTPListner As HttpListener
Dim blnKeepAlive As Boolean = True
Shared Sub Main()
Dim ServicesToRun As ServiceBase()
ServicesToRun = New ServiceBase() {New SimpleWebService()}
ServiceBase.Run(ServicesToRun)
End Sub
Protected Overrides Sub OnStart(ByVal args As String())
If Not HttpListener.IsSupported Then
CreateEventLogEntry("Windows XP SP2, Server 2003, or higher is required to " & "use the HttpListener class.")
Me.Stop()
End If
Try
listenerThread = New Thread(AddressOf ListenForConnections)
listenerThread.Start()
Catch ex As Exception
CreateEventLogEntry(ex.Message)
End Try
End Sub
Protected Overrides Sub OnStop()
blnKeepAlive = False
End Sub
Private Sub CreateEventLogEntry(ByRef strEventContent As String)
Dim sSource As String
Dim sLog As String
sSource = "Service1"
sLog = "Application"
If Not EventLog.SourceExists(sSource) Then
EventLog.CreateEventSource(sSource, sLog)
End If
Dim ELog As New EventLog(sLog, ".", sSource)
ELog.WriteEntry(strEventContent)
End Sub
Public Sub ListenForConnections()
HTTPListner = New HttpListener
HTTPListner.Prefixes.Add("http://*:1986/")
HTTPListner.Start()
Do While blnKeepAlive
Dim ctx As HttpListenerContext = HTTPListner.GetContext()
Dim HandlerThread As Thread = New Thread(AddressOf ProcessRequest)
HandlerThread.Start(ctx)
HandlerThread = Nothing
Loop
HTTPListner.Stop()
End Sub
Private Sub ProcessRequest(ByVal ctx As HttpListenerContext)
Dim sb As StringBuilder = New StringBuilder
sb.Append("<html><body><h1>Test My Service</h1>")
sb.Append("</body></html>")
Dim buffer() As Byte = Encoding.UTF8.GetBytes(sb.ToString)
ctx.Response.ContentLength64 = buffer.Length
ctx.Response.OutputStream.Write(buffer, 0, buffer.Length)
ctx.Response.OutputStream.Close()
ctx.Response.Close()
sb = Nothing
buffer = Nothing
ctx = Nothing
'This line seems to keep the mem leak down
'System.GC.Collect()
End Sub
End Class
Please feel free to critisise and tear the code apart but please BE KIND. I have admitted I dont tend to follow the best practice when it comes to coding.
You are right, you should not be doing this. Remove the Collect() call and let it run for a week. Any decent .NET book will talk about how the garbage collector works and how it does not immediately release memory when you set an object to Nothing. It doesn't kick in until you've consumed somewhere between 2 and 8 megabytes. This is not a leak, merely effective use of a plentiful resource.
You use a new thread for each individual connection, that's pretty expensive and scales very poorly when you get a lot of connections. Consider using ThreadPool.QueueUserWorkItem instead. Threadpool threads are very cheap and their allocation and execution is well controlled by the threadpool manager.