XMS IBytesMessage causing problems with split ZIP file - ibm-mq

Since upgrading MQ to "IBM MQ Explorer V9.1", the XMS libraries that always worked in previous versions have started behaving differently.
Essentially, the code still recognises the messages as IBytesMessage type, and successfully writes them to file via a Byte array, but the file itself, which is a split zip file, fails to reconstitute itself.
Here's the lions share of that code:
Dim FactoryFactory As XMSFactoryFactory = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ)
'Create a ConnectionFactory Object
cfConnectionFactory = FactoryFactory.CreateConnectionFactory()
'this variable will contain the full path of any file downloaded from MQ
Dim strMQMessageOutputFileDestinationFilePath As String = ""
'This variable will be used to evaluate whether the MQ Message Output file exists
Dim fiMQMessageOutputFile As FileInfo = Nothing
'Set various Connection Factory properties
cfConnectionFactory.SetStringProperty(XMSC.WMQ_HOST_NAME, Me.HostName)
cfConnectionFactory.SetIntProperty(XMSC.WMQ_PORT, 1414)
cfConnectionFactory.SetStringProperty(XMSC.WMQ_CHANNEL, "SYSTEM.DEF.SVRCONN")
cfConnectionFactory.SetIntProperty(XMSC.WMQ_CONNECTION_MODE, 1)
cfConnectionFactory.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, Me.QueueManager)
cfConnectionFactory.SetIntProperty(XMSC.WMQ_BROKER_VERSION, 0)
'Create a new Iconnection object via the Connection Factory
connection = cfConnectionFactory.CreateConnection()
'Create a sesion via the Connection Object, using ClientAcknowledge mode
'ClientAcknowledge is being used because it allows us to control precisely
'when a message should be removed from the queue
session = connection.CreateSession(False, AcknowledgeMode.ClientAcknowledge)
'Create a destination using the Session Object
destination = session.CreateQueue(Me.mstrDestinationURI)
destination.SetIntProperty(XMSC.DELIVERY_MODE, 1)
'Create a consumer using the Session & Destination Objects
Consumer = session.CreateConsumer(destination)
connection.Start()
'IMessage is the base class that is returned from the Consumer's Receive method
Dim recvMsg As IMessage = Nothing
' Retrieve message from Queue
recvMsg = Consumer.ReceiveNoWait
strFileNameFromMsg = If(Not recvMsg.PropertyExists("fileName"), "",
recvMsg.GetStringProperty("fileName"))
If TypeOf (recvMsg) Is IBytesMessage Then
'Binary Message
Dim msg As IBytesMessage = CType(recvMsg, IBytesMessage)
Dim buffer(msg.BodyLength) As Byte
msg.ReadBytes(buffer)
Dim content As String = Text.Encoding.UTF8.GetString(buffer)
'The PrepareDestinationFile Function will generate a unique file name for the new file
'and ensure that the file does not already exist on the drive
strMQMessageOutputFileDestinationFilePath = PrepareDestinationFile(strFileNameFromMsg)
'A FileStream object is needed to write a binary array to a file
Dim fsZipFile As FileStream = New FileStream(strMQMessageOutputFileDestinationFilePath, FileMode.Create)
'Write the contents of the Byte Array to the File via the FileStream object
fsZipFile.Write(buffer, 0, buffer.Length)
fsZipFile.Close()
End If
So, the code doesn't throw any kind of exception - the code still recognises the messages as IBytesMessage, but the files won't unzip correctly.
Oddly, If we use rfhutilc.exe, we can manually pull files provided we set the Write options as No Headers and not Include MQMD - but the code above always worked in the previous version of MQ / XMS
Any assistance you can provide would be very much appreciated.

Related

msxml6.dll error '800c0005' The system cannot locate the resource specified [duplicate]

I have a function which uses MSXML to post an XML document which yesterday started failing despite no change being made to the code. The function is as follows:
Public Function PostFile(ByVal address As String, ByVal data As Byte()) As xmldocument
Dim xmlHTTP As New MSXML2.XMLHTTP
Dim response As New XmlDocument
Dim xmlDoc As New MSXML2.DOMDocument
Try
xmlDoc.load(data)
xmlHTTP.open("post", address, False)
xmlHTTP.send(xmlDoc)
If xmlHTTP.responseXML.xml <> String.Empty Then
response.LoadXml(xmlHTTP.responseXML.xml)
Return response
Else
Dim result As String = "<NO_Response><Error>the post succeeded to " + address + " but there was no responce returned</Error><Hint>Check FireWall Settings</Hint></NO_Response>"
response.loadxml(result)
Return response
End If
Catch ex As Exception
'Error logging code removed
End Try
Return Nothing
End Function
The XML document and the address being passed in are both correct - the line which causes the error is xmlHTTP.send(xmlDoc). I have tried this on 2 different machines with the same error each time and have also tried resinstalling MSXML3, with no success.
The exception thrown is:
InnerException: Nothing
Message: "The system cannot locate the resource specified. "
Source: "msxml3.dll"
StackTrace: " at MSXML2.XMLHTTPClass.send(Object varBody) at comms.HTTPHandler.PostFile(String address, Byte[] data) in D:\SCC\Main\Sender\Http.vb:line 42"
It turned out to be a networking issue - I didn't suspect this at first as the error was raised so quickly which didn't suggest an issue with the endpoint. The problem was with a rule which had been added (don't ask why) to the firewall preventing communication with the destination address.
If you are just processing the xml or dtd is offline, you can use:
xmlDoc.resolveExternals = False

How to asdd call attrs. after the call droped just like mark done button?

I am able to add call attrs using 'Genesyslab.Platform.Voice.Protocols.TServer.Requests.Userdata.RequestAttachUserData' when the call is online but how to do when the call is dropped?
I found this in WDE
void SelectDispositionCodeSetAttachedData(string dispositionCodeValueName);
//
// Summary:
// Update or add the keys of the specificed KeyValueCollection in the attached data
// of the interaction . The current list of attached data can then be retrieved
// using GetAttachedData. If the interaction media type is 'voice' or 'instant message'
// and the interaction is not released the added/updated values are immediately
// committed to T/SIP Server. If the interaction media type is 'voice' or 'instant
// message' and the interaction is released the added/updated values are sent to
// T/SIP Server as a UserEvent when the interaction is marked done (programmatic?aly
// or by Agent). If it is an eServices interaction (e-mail, chat, etc.) and the
// interaction is still handled by the agent the added/updated values are immediately
// committed to Interaction Server. After e-Services interaction is released, no
// further programmatical update is committed to Interaction Server. For all interaction
// types any attached data programmatical update applied after interaction release
// is not reflected in UI controls such as 'Case information'.
This is my code:
Genesyslab.Platform.Commons.Collections.KeyValueCollection keyValueCollectionUpDate = new Genesyslab.Platform.Commons.Collections.KeyValueCollection();
keyValueCollectionUpDate.Add("Business Result", "Platform: Business Result");
keyValueCollectionUpDate.Add("StrAttribute1", "AttachedData.Business Result"); RequestAttachUserData requestAttachUserData= RequestAttachUserData.Create("7012", GetConnectionID(ExtractedArtributes[1][0].Value.ToString()), keyValueCollectionUpDate); IMessage respondingEvent2=tserverProtocol.Request(requestAttachUserData);
Need to add call attts after the call is dropped
You can't update attached data when the call is dropped.
I do a workaround by using WDE itself to attach data when agent clicks 'mark done' in WDE custom command.
The way to attach data to voice calls after disconnect, is to send a UserEvent. This does require the AfterCallWork state to be enabled in your environment. You have already mentioned understanding how to insert Commands into the Command Chain. This example Execute function of a command can be inserted into the "BundleClose" Command Chain, prior to the "Close" Command.
This sample is in VB, apologies, but I guess you can easily convert to c#.
Public Function Execute(ByVal parameters As IDictionary(Of String, Object), ByVal progress As IProgressUpdater) As Boolean Implements IElementOfCommand.Execute
' To go to the main thread
If Application.Current.Dispatcher IsNot Nothing AndAlso Not Application.Current.Dispatcher.CheckAccess() Then
Dim result As Object = Application.Current.Dispatcher.Invoke(DispatcherPriority.Send, New ExecuteDelegate(AddressOf Execute), parameters, progress)
Return CBool(result)
Else
Dim interactionsBundle As IInteractionsBundle = Nothing
Dim interaction As IInteraction = Nothing
interactionsBundle = parameters("CommandParameter")
interaction = interactionsBundle.MainInteraction
Dim channel As Enterprise.Model.Channel.IClientChannel = interaction.EntrepriseInteractionCurrent.ActiveChannel 'agent.Channel
Dim protocol As IProtocol = channel.Protocol
Dim kvp As Platform.Commons.Collections.KeyValueCollection = New Platform.Commons.Collections.KeyValueCollection()
kvp.Add("keyname", "keyvalue")
Dim userevent As Platform.Voice.Protocols.TServer.CommonProperties = Platform.Voice.Protocols.TServer.CommonProperties.Create()
userevent.UserData = kvp
Dim connID As Platform.Voice.Protocols.ConnectionId = Nothing
Dim interactionVoice as IInteractionVoice = TryCast(interaction, IInteractionVoice)
If interactionVoice IsNot Nothing Then
userevent.UserEvent = Platform.Voice.Protocols.TServer.Events.EventUserEvent.MessageId
connID = New Platform.Voice.Protocols.ConnectionId(interactionVoice.TConnectionId)
Dim strDN As String = Nothing
'ensure the correct DN is passed when attaching reason codes, in case agent is logged into multiple DNs
Dim devices() As Enterprise.Model.Device.IDevice = interactionVoice.Device
Dim device As Enterprise.Core.DN = devices(0)
strDN = device.Name
userevent.ThisDN = strDN
userevent.ConnID = connID
Dim req = Platform.Voice.Protocols.TServer.Requests.Special.RequestSendEvent.Create()
req.UserEvent = userevent
'send request
protocol.Send(req)
End If
End If
End Function

Refresh system variable using vbscript/QTP

I want to set system variable MQSERVER for connecting to MQ using QTP. Each time this value is changed from QTP, I need to restart QTP to reflect changes.
E.g. in the system variables window,
MQSERVER = ABCD
change the variable using
Set objWSH = CreateObject("WScript.Shell")
Set objSystemVariables = objWSH.Environment("SYSTEM")
objSystemVariables(MQVariableName) = MQVariableValue
The variable is set correctly but does not reflect in QTP code when connecting to websphere MQ.
Immediately when I restart QTP, the QTP reads the env variable correctly. Can you please let me know how I can use the below API method. I am getting type mismatch in QTP.
lnRetVal = SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, "Environment", 2, 1000, Null) 'Getting type mismatch here
Updating my original question with the code that connects to queue manager.
The very basic thing that I am trying to do is (which can't be done without restarting QTP)
1) Connect to a queue manager
2) Put the message
3) Connect to another queue manager
4) Read the output
Const MQOO_OUTPUT = 16
Const MQOO_INPUT_AS_Q_DEF = 1
Set MQS = CreateObject("MQAX200.MQSession")
Set QM = MQS.AccessQueueManager(Environment.Value("MQName")) 'This will pass the queue name and access the queue manager.
Set MQQueue = QM.AccessQueue(strQueName, MQOO_INPUT_AS_Q_DEF Or MQOO_OUTPUT)
Set PutOptions = MQS.AccessPutMessageOptions()
PutOptions.Options = MQPMO_NO_SYNCPOINT
Set PutMsg = MQS.AccessMessage()
PutMsg.CharacterSet = 1208
PutMsg.MessageData = PutMsgStr 'the message text
PutMsg.ApplicationIdData = "INTF_0439B"
MQQueue.Put PutMsg, PutOptions 'write the message to queue.
Also, my websphere MQ version is 7.0.1.8

VBscript for sending mail using SMTP for .mht file attachment

I am using Gmail SMTP server to send out a .mht file. once send out, i am getting a lot of attachemnts and the .mht file were loading in the email body (from yahoo mail). Instead in outlook, i am getting it as a mail attachements.
VB script used for this :
Set objMessage = CreateObject("CDO.Message")
objMessage.HTMLBody = "<h1>Matrikon AM</h1>"
objMessage.Subject = "Test 1 -Blank"
objMessage.From = "xxxxx#gmail.com"
objMessage.To = "xxxxx#yahoo.com"
objMessage.TextBody = "From b.vbs"
objMessage.AddAttachment "c:\xxxxxxx\A1.mht"
objMessage.Send
I had some quick search online that "ContentMediaType" have to be define somewhere since the file extension is .mht.
Need help on this as i could not find a way to define the content-type.
My issue were exactly like mentioned in "https://stackoverflow.com/questions/15976836/modifying-the-content-type-of-an-attachment-in-a-cdo-message-object"
thanks.
This is from Help.
urn:schemas:mailheader: Namespace
The urn:schemas:mailheader: namespace defines fields that contain Internet standard message header values. Each field value (with a few exceptions) is stored as US-ASCII characters and is identical to the ASCII string found in the message stream. Non US-ASCII characters are encoded according to the RFC 1522 specification. No conversion is performed when the property value is set or updated. An application that sets the raw message header property must RFC 1522-encode non US-ASCII characters or the header value will be corrupted.
String constants are provided in the C++ header file cdosysstr.h and type library (cdoMailHeader module) for each field name. You can use these constants when referring to the fields to avoid typos and extra typing.
Example
The following example demonstrates use of the fields in the urn:schemas:mailheader: namespace. First, RFC 822 headers are added for a message. Next, body parts are added and the MIME headers set manually.
This code is for illustrative purposes only.
Copy Code
Dim iMsg as New CDO.Message
Dim Flds as ADODB.Fields
With iMsg
.To = """Someone"" <example#example.com>"
.From = """Me"" <example#example.com>"
.Subject = "Here is a sample message"
' Now set some custom mail headers using the raw fields collection
Set Flds = .Fields
With Flds
.Item("urn:schemas:mailheader:X-Mailer") = "Microsoft CDO for Windows 2000"
' I add a custom header here
.Item("urn:schemas:mailheader:Myheader")= "some value"
.Update
.Resync
End With ' Flds
End With ' iMsg
' Create a multipart/alternative (HTML) message below
Dim iBp as CDO.IBodyPart
Dim iBp2 as CDO.IBodyPart
Set iBp = iMsg ' get IBodyPart on Message object
Set Flds = iBp.Fields
Flds("urn:schemas:mailheader:content-type") = "multipart/alternative"
Flds.Update
Set iBp2 = iBp.AddBodyPart
Set Flds = iBp2.Fields
Flds("urn:schemas:mailheader:content-type") = "text/plain"
Flds("urn:schemas:mailheader:content-transfer-encoding") = "quoted-printable"
Flds.Update
Dim Stm as ADODB.Stream
Set Stm = iBp2.GetDecodedContentStream
Stm.WriteText "This is a test", stWriteLine
Stm.Flush
Set iBp2 = iBp.AddBodyPart
Set Flds = iBp2.Fields
Flds("urn:schemas:mailheader:content-type") = "text/html"
Flds("urn:schemas:mailheader:content-transfer-encoding") = "quoted-printable"
Flds.Update
Set Stm = iBp2.GetDecodedContentStream
Stm.WriteText "This is a <i>test</i>", stWriteLine
Stm.Flush
iMsg.Send

Sending an object to a client computer after connection made

I have a program that currently works as a chat server. It's a turn based card game with a chat box to communicate with the opponent. The chat stuff all works over the connection, but I'm to the point where I need to start sending certain cards to the opponent, so that when I play a card, my opponent will see it on his screen. I want the client computer to receive the object or collection of objects, figure out what the card type is based on its properties, and then put the card in the correct location. The sending and receiving part is what I don't understand how to accomplish. From what I've read, this requires serialization and I just don't know where to begin with this. Please assist! I'm using visual studio.
Answering my own question again... I ended up creating a new class called card container which contains the cardType as a string and the card id as a int. There are also other properties for the card container so I know where the card goes. Then I serialized the card container (which is 'cc' in the following code) and sent it as follows:
Dim cc as new CardContainer
cc.id = card.id
cc.cardType = card.GetType.ToString
cc.discard = true
Dim bf As New BinaryFormatter
Dim ms As New MemoryStream
Dim b() As Byte
'serializes to the created memory stream
bf.Serialize(ms, cc)
'converts the memory stream to the byte array
b = ms.ToArray()
ms.Close()
'sends the byte array to client or host
SyncLock mobjClient.GetStream
mobjClient.GetStream.Write(b, 0, b.Length)
End SyncLock
The client listens on its TCPClient for anything at all and picks up the card with the following code:
Dim intCount As Integer
Try
SyncLock mobjClient.GetStream
'returns the number of bytes to know how many to read
intCount = mobjClient.GetStream.EndRead(ar)
End SyncLock
'if no bytes then we are disconnected
If intCount < 1 Then
MarkAsDisconnected()
Exit Sub
End If
Dim bf As New BinaryFormatter
Dim cc As New CardContainer
'moves the byte array found in arData to the memory stream
Dim ms As New MemoryStream(arData)
'cuts off the byte array in the memory stream after all the received data
ms.SetLength(intCount)
'the new cardContainer will now be just like the sent one
cc = bf.Deserialize(ms)
ms.Close()
'starts the listener again
mobjClient.GetStream.BeginRead(arData, 0, 3145728, AddressOf DoRead, Nothing)
Depending on what data the cardcontainer has determines which method the client now calls. For example, when this is received, the created cc is passed to my CardReceived method which then has a bunch of if, elseif statements. One of those would be
ElseIf cc.discard = true then
'makes a new card from the id and cardType properties
dim temp as new object = MakeCard
'discard method will find the correct card in the Host's known hand and discard it to the correct pile
Discard(temp)

Resources