IBM MQSeries ActiveX Write Message Error - vb6

I've a VB6 application with MQSeries Automation Classes for ActiveX. The problem is when i'm writing the message con the queue. I use this code :
This is how I open the connection and the relative queue :
Set MQSess = New MQSession
//Access Queue
Set QMgr = MQSess.AccessQueueManager(QueueManagerName)
Dim Queue As MQQueue
Dim msg As MQMessage
Dim pmo As MQPutMessageOptions
Dim ArrCar() As Byte
Set pmo = New MQPutMessageOptions
Set Queue = QMgr.AccessQueue(QueueName, OpenOption , RemoteQueueManagerName)
//OpenOption is a integer with value of 16 (MQOO_OUTPUT)
strMsgAppo = Translate("*MESSAGE_TO_INSERT*", ASCII_To_EBCDIC_Table())
ReDim ArrCar(Len(strMsgAppo) - 1)
For lngI = 1 To Len(strMsgAppo)
ArrCar(lngI - 1) = Asc(Mid(strMsgAppo, lngI, 1))
Next lngI
Call msg.Write(ArrCar) //Write the ByteArray
Call Queue.Put(msg, pmo)
The ASCII_To_EBCDIC_Table is a function used to change the encoding.
The error i'm getting from MQ is :
MQAX200.MQMessage::Write CompletionCode = 2, ReasonCode = 2043, ReasonName = MQRC_OBJECT_TYPE_ERROR
Is Anyone using this activex and can help me on how to write message in a queue?

In the code snippet provided, I'm not seeing where the connection to the QMgr is made nor where the queue is opened. Both of these steps must be completed before it is possible to put messages on the queue.
The 2043 reason code occurs when there is an invalid option in the Message Options field for a PUT or an OPEN. In this case the problem could either be on the PUT or an implicit OPEN, depending on what's in the code that was not provided and whether it contains an OPEN.
My suggestion would be to refer to the .Net samples provided in the installation and reconcile between those and your application. The samples reside at C:\Program Files (x86)\IBM\WebSphere MQ\tools\dotnet\samples in a default V7 installation.

The failure is on your msg.Write, and you should probably be using the .WrirteString method instead, after setting the .CharacterSet property to 37 (EBCDIC).
The hackish approach of your Translate() function might work, but only if assigned to a Byte array. As you have things you're likely to see scrambling when the data is converted back to Unicode. Or if Translate() does return a Byte array you'll have a mess with 8-bit data in a Unicode String (which can be fine but not with this MQ library).
You can probably just throw Translate() and your table away.
The IBM manual on this API is called "Using the Component Object Model Interface." Check it out!

Related

Data Loss Prevention policy making OpenMsgStore fail (0x80040312)

When DLP policy is enabled, Redemption fails with the error:
"All business e-mail messages are protected based on a policy set in your organization. There was an error opening the protected e-mail message."
ulLowLevelError: 2147746578 (i.e. 0x80040312)
ulContext: 805701633 (0x30060801)
Is there any way around this?
The error occurs when trying to access the IPMRootFolder property of a Store object:
// A previous version of the code was multi-threaded, it is no longer.
Session = OutlookRpcLoader.new_RDOSession();
Session.Logon(ProfileName: profile, ShowDialog: false, NewSession: true);
var stores = Session.Stores;
var store = stores["{STORE-NAME}"];
var root = store.IPMRootFolder;
The call stack shows that Redemption.IRDOStore.get_IPMRootFolder() threw the exception.
Edit
This is seen when using Redemption version 5.22.0.5498 loaded via the RedemptionLoader class in .NET (registry-free COM).
When testing with Redemption version 5.19.0.5238 from VBScript using CreateObject(), the error doesn't occur.
Could anything have changed between v5.19 and v5.22?
First of all, you need to detect where your code is running - whether it is the foreground or background thread. I'd suggest checking the ThreadID of the process. The foreground thread has the value set to 1. All background threads will values greater than one. If it is a secondary thread you need to create a new Redemption session on a secondary thread where you are going to use and set the MAPIOBJECT property to the object retrieved from the main thread. For example, a raw sketch in VB.NET:
Dim PrimaryRDOSession As New Redemption.RDOSession()
PrimaryRDOSession.Login([...])
Dim WorkerThread as New System.Threading.Thread(AddressOf ThreadProc)
WorkerThread.Start(PrimaryRDOSession.MAPIOBJECT)
Sub ThreadProc(ByVal param as Object)
Dim ThdRDOSession As New Redemption.RDOSession()
ThdRDOSession.MAPIOBJECT = param
' do other stuff
End Sub
Don't use objects created on the main thread if you are on a secondary one. Ensure you are consistent when using the objects.
I believe this was caused by AppLocker rules blocking unsigned binaries. The resolution was to either code-sign the files or add the program to the AppLocker allow-list.

Using ODP.NET OracleAQQueue.Listen on a Multiconsumer Queue

I have a client app that connects to an Oracle AQ multi-consumer queue. I want to use OracleAQQueue.Listen to listen for new messages on the queue. API docs show that the Listen method can be used for multi-consumer queues. My code for listening to the queue is shown below.
string consumerName = "APPINST1";
using (OracleConnection con = new OracleConnection(connectionString))
{
con.Open();
OracleAQQueue queue = new OracleAQQueue("MY_Q");
queue.MessageType = OracleAQMessageType.Udt;
queue.UdtTypeName = "MY_Q_MSG";
queue.DequeueOptions.DeliveryMode = OracleAQMessageDeliveryMode.Persistent;
queue.Connection = con;
Console.WriteLine("Listening for messages...");
queue.Listen(new string[] { consumerName });
}
The problem that I'm having is that on the line of code where I call queue.Listen(), I get the Oracle exception:
ORA-25295: Subscriber is not allowed to dequeue buffered messages
Googling for advice on this particular error hasn't been too helpful. I've removed and re-added my subscriber to the queue several times to no avail. My guess is that I'm not setting some property correctly before I make the call to Listen, but I can't figure out the issue.
Any ideas?
I ran across the following note in the Streams Advanced Queuing User's Guide, in Chapter 10 - Oracle Streams AQ Operations Using PL/SQL:
Note: Listening to multiconsumer queues is not supported in the Java API.
Although I can't find it explicitly stated anywhere, I'm guessing the same rule applies to the ODP.NET API.
You must set the visibility attribute to IMMEDIATE to use buffered messaging.

VB6 - Reading a single bit over an RS232 line/ COM port

I am currently working on writing a little script on VB6 to replace a script running on a UNIX machine. What that script does is wait for the UPS system to close a switch which is then received by a COM port and a driver shuts down the UNIX machine. I want to do that for a Windows PC but it is giving me some trouble.
I built a connector, according to the schematics I have, bridging pins 7 and 8 and connecting a switch between pins 2 and 3 (RXD and TXD). Flipping the switch on is exactly the same as the UPS system doing it.
Private Sub shutdownPC()
Dim inStr As Variant
myCom.CommPort = 1
myCom.Settings = "9600,e,7,1"
myCom.RThreshold = 1
myCom.InputLen = 0
myCom.InputMode = comInputModeBinary
myCom.InBufferCount() = 0
myCom.PortOpen = True
'Shell ("shutdown.exe -s -t01")
If myCom.CommEvent = comEvReceive Then
inStr = myCom.Input
End If
End Sub
This is my code so far. I have included the MSComm library and added an MSComm object to my form. When I use comInputModeBinary and comInputModeText, I get "No variables" and "" on myCom.Input respectively. Using Powershell I can see that the COM1 port is working.
Any ideas on what I am doing wrong?
connecting a switch between pins 2 and 3 (RXD and TXD)
That would create a loopback.
That is only useful if your program is sending out test messages.
If nothing is received, then the switch is still open. When the switch closes, then the program will begin receiving the messages it sent.
Any ideas on what I am doing wrong?
Your program cannot wait passively.
It has to poll the UPS by sending bytes out and then check if any of the data is received back.
You either have to loop or put in an event handler as your code will execute before anything in the external world happens. Looping wastes battery life and slows computers down. The helpfile is at C:\Windows\HELP\COMM98.CHM.
OnComm Event
The OnComm event is generated whenever the value of the CommEvent property changes, indicating that either a communication event or an error occurred.
Syntax
Private Sub object_OnComm ()
The OnComm event syntax has these parts:
Part Description
object Anobject expression that evaluates to an object in the Applies To list.
Remarks
The CommEvent property contains the numeric code of the actual error or event that generated the OnComm event. Note that setting the RThreshold or SThreshold properties to 0 disables trapping for the comEvReceive and comEvSend events, respectively.

WinSock recv() timeout: setsockopt()-set value + half a second?

I am writing a cross-platform library which, among other things, provides a socket interface, and while running my unit-test suite, I noticed something strange with regard to timeouts set via setsockopt(): On Windows, a blocking recv() call seems to consistently return about half a second (500 ms) later than specified via the SO_RCVTIMEO option.
Is there any explanation for this in the docs I missed? Searching the web, I was only able to find a single other reference to the problem – could somebody who owns »Windows Sockets
Network Programming« by Bob Quinn and Dave Shute look up page 466 for me? Unfortunately, I can only run my test Windows Server 2008 R2 right now, does the same strange behavior exist on other Windows versions as well?
From Networking Programming for Microsoft Windows by Jones and Ohlund:
SO_RCVTIMEO optval
Type: int
Get/Set: Both
Winsock Version: 1+
Description : Gets or sets the timeout value (in milliseconds)
associated with receiving data on the
socket
The SO_RCVTIMEO option sets the
receive timeout value on a blocking
socket. The timeout value is an
integer in milliseconds that indicates
how long a Winsock receive function
should block when attempting to
receive data. If you need to use the
SO_RCVTIMEO option and you use the
WSASocket function to create the
socket, you must specify
WSA_FLAG_OVERLAPPED as part of
WSASocket's dwFlags parameter.
Subsequent calls to any Winsock
receive function (such as recv,
recvfrom, WSARecv, or WSARecvFrom)
block only for the amount of time
specified. If no data arrives within
that time, the call fails with the
error 10060 (WSAETIMEDOUT). If the
receiver operation does time out the
socket is in an indeterminate state
and should not be used.
For performance reasons, this option
was disabled in Windows CE 2.1. If you
attempt to set this option, it is
silently ignored and no failure
returns. Previous versions of Windows
CE do implement this option.
I'd think the crucial information in this is:
If you need to use the SO_RCVTIMEO option and you use the WSASocket
function to create the socket, you
must specify WSA_FLAG_OVERLAPPED as
part of WSASocket's dwFlags parameter
I hope this is still useful :)
I am having the same problem. Going to use
patchedTimeout = max ( unpatchedTimepit - 500, 1 )
Tested this with the unpatchedTimepit == 850
your problem is not in rcv function timeout!
if your application have a while loop to check and receive just put an if statement to check the receive buffer last index for '\0' char to check is the receiving string is ended or not.
typically if rcv function is still receiving return value is the size of received data. size can be used as last index of buffer array.
do{
result = rcv(s,buf,len,0);
if(buf[result] == '\0'){
break;
}
}
while(result > 0);

Server unable to receive byte data smoothly in vb6

I have a sender, a message forwarder which sends fix sizes of byte data at a rate of 5 milliseconds per message to my receiving program written in vb6, when I run the message fowarder and my receiving program on one machine, there's no issue but when they run on separate machines, the receiving program starts to experience some abnormalities.
e.g:
private sub socket_DataArrival(index as integer, ByVal dataTotal as Long)
Dim Data() as Byte
Length.Text = dataTotal
socket.GetData byteData, vbArray + vbByte
If Length.Text = "100" Then
txtOutput.Text = "Message1"
ElseIf Length.Text = "150" Then
txtOutput.text = "Message2"
End Sub
I will sometimes receive "2 in 1" message as in it comes in as 250 bytes or a non-recognizable byte size when I should be receiving either 100 or 150 only but if I reduce the sending rate to a slower speed say 50 milliseconds per message then it will be fine.
Can anyone provide with an advice? Thanks.
When sending data over a network you have to get used to the fact that the packets may arrive out of order, not promptly, not at all, etc.
You need to improve your message protocol to include a header that states which type of message follows. If order is important include a sequence number (I'm assuming you're using UDP). At present you are relying on timing to separate messages, which you cannot rely on over a network.
Buffer all your arriving data and handle it in chunks - the header allows you to tell what chunk size to use. Separate your input buffering from your message handling - use the DataArrival event to add data to the buffer, use a Timer or some other means of polling the buffer to check if it has messages ready to parse. Alas, this is VB6 so threading is not so easy. Take a look at The Common Controls Replacement Project timer object DLL if you need a Timer class that doesn't rely on a UI element being present.

Resources