How to ALTER CHANNEL in C++? - c++

IBM's documentation on ALTER CHANNEL goes to commendable length explaining the various available alterations, but does not offer a single example -- certainly not for C++-users.
Suppose, I want to change the MCAUSER from the default (OS username) to another string, what would the function-call look like?

The documentation you link to in your question is the MQSC command reference. This is designed for scripts.
Please also note that the default value of a channel's MCAUSER field is actually blank, not the OS username. Because it is blank, then in the case of a SVRCONN channel, when a client application connects, the OS username flowed from the client, will be used for the MCAUSER for that running instance. You cannot change this behaviour using ALTER CHANNEL from your client application. I note this, in case this is the reason you are thinking to use ALTER CHANNEL.
If you want to write a program to make a change to an IBM MQ object, such as a channel, you would instead want to make use of a different, but equivalent interface called the Programmable Command Format (PCF). The equivalent command reference page is here.
There is an example C++ PCF sample here - look for SrvPCF
In short, psuedo-code, you would write a program as follows:-
MQCONN(Qmgr-name)
MQOPEN(Reply-Q)
Build PCF message for MQCMD_CHANGE_CHANNEL
with MQCACH_CHANNEL_NAME
with MQIACH_CHANNEL_TYPE
with MQCACH_MCA_USER_ID
MQPUT1(PCF Message to SYSTEM.ADMIN.COMMAND.QUEUE)
MQGET(wait for reply on Reply-Q to say whether it worked or not)

Related

C++ IBM i Access API Running remote commands and getting output

IBM i Access API for C++ lets you run server commands for example (DSPSYSSTS Displaying system status):
cwbSV_ErrHandle msgHandle; //Error Handle
cwbSV_CreateErrHandle(&msgHandle); //Create Error Handle
int code = cwbRC_RunCmd(SystemData::hxSystem, "DSPSYSSTS", msgHandle); //Run command
//Command ran successfully
if(code == CBW_OK){
int code = cwbSV_GetErrText(msgHandle, returnTxt, 1024, NULL);
//code value is CWBSV_NO_ERROR_MESSAGES
}
I can retrieve error messages thrown by the server after command run. But how can I retrieve the command output? If I run a "DSP" (Display) command, I'm obviously wanting to get the output display.
DSP type commands by definition send their output to the 5250 data stream which is then interpreted by a 5250 emulator in order to properly paint a display. It's not at all like stdout, which means that intercepting output meant for a display will require a fair amount of work.
The traditional answer is to use an API which returns the information in a form intended to be read by a program. In the case of system status, that's probably the Retrieve System Status (QWCRSSTS) API. One way to make this easy on yourself is to write a stored procedure and call that instead of directly invoking the API from the client.
Another alternative is to DSPSYSSTS OUTPUT(*PRINT), then read the spooled file. It'll be easier to parse than the raw 5250 output but it can and does change between releases so the API is a more consistent interface.
If you really want to screen scrape the output from DSPSYSSTS, you'll need to learn about the 5250 protocol, which is complex enough that I don't think it can be explained in a forum like this. On the other hand, Albert York has written a program called TNAPI which might fit your needs.
Use Scott Klement explaning to translate Retrieve System Status (QWCRSSTS) API into C++ code. This way you dont need rpg at all.

Passing arguments to a program using another program

I have created two executables that accept command line arguments. Now, I want to pass arguments to available executables using C++ (executing on Windows). What is the best way of doing it?
I have used CreateProcess(); it's working fine for static input but I want to input dynamically through CLI.
The command-line (with arguments) is one of the parameters to CreateProcess(). Just put whatever arguments you want to pass on to the child executable in there.
What problems are you having with non-static input?
I usually use system(const char*) and it works for me :)
You pass over a string which contains the command as you type it in the command line. In your case it means the path to the exe file and the arguments it takes, with just spaces in between. It runs the specified process as if it was run from command-line.
For more information: http://www.cplusplus.com/reference/cstdlib/system/
It sounds as though you already understand that string arguments can be sent via CreateProcess at launch time. If you want to continue to send data at run time, you have a couple options.
Use console redirection. Since you are already using the Win32 API, it is not too far of a stretch to write to cin of the child process after you have launched it. See this MSDN article. I think this might be what you mean by "input dynamically through CLI"
Use some sort of IPC. There are Win32 ways of doing this such as message queues, and more platform independent methods such as Protocol Buffers, Thrift, or Boost.Interprocess.
There is really more than one way to skin a cat when it comes to IPC and your goal is to do your research and make sure you have made the correct design decisions early on for how your processes will communicate.
If you do decide to use a more full-blown IPC rather than something like console redirection to solve a smaller problem, some questions you should ask yourself are:
Will I be able to send all the types of data using this type of IPC?
Will this communication ever need to cross network boundaries?
And, the two big questions that always show up are:
How maintainable will this be in the future?
Will this code ever have to run on another platform?
Hopefully this response is not overkill for your question.

How to find out if hibernation is available for a Windows user (with C++)

I know that one can call the following API to hibernate the system:
SetSuspendState(TRUE, FALSE, FALSE);
But is there any way to find out if "real" hibernation is available for the current Windows user?
Here's what I mean:
If an admin calls:
powercfg.exe /hibernate off
the API above will put system into a Sleep mode. So how do you know (from a C++ program) that this will happen instead of hibernation?
I'm not sure if there's a group policy that can prohibit a user from hibernating a computer connected to an Active Directory?
Edit I am aware of the (dated) IsPwrHibernateAllowed API. I find that it doesn't work: it still returns the same result even if powercfg.exe /hibernate off was called. Am I doing something wrong there? Can someone explain why IsPwrHibernateAllowed doesn't work for me?
Take a look at SYSTEM_POWER_CAPABILITIES structure that can be obtained with CallNtPowerInformation. Specifically, look at HiberFilePresent field.

Name mapping -- \\.\PhysicalDrive to \\.\SCSI

I'm developing in windows with C/C++ and I want to know is it possible to get an apropriate \\.\SCSI device name by \\.\PhysicalDrive ?..
For example, it's wonderful to know how to get that \\.\PhysicalDrive0 is the same that \\.\SCSI0.
Look at the code which I posted in my answer to the question. The author of the question had changed the text of the question so many time and the last version of text clear nor really what the original problem was.
In the example, which C source code you can download here, I show how to get many kind of information about the local drive using different Windows API. The important thing which you need is that some name conversion like DeviceType and DeviceNumber (received by IOCTL_STORAGE_GET_DEVICE_NUMBER) like the following
DeviceType: 7, DeviceNumber: 5, PartitionNumber: 1
are unique in the operation system and can be used to identify the same devices. The reference to the statement you can find in the documentation of IOCTL_STORAGE_GET_DEVICE_NUMBER control code:
The values in the
STORAGE_DEVICE_NUMBER structure are
guaranteed to remain unchanged until
the device is removed or the system is
restarted. It is not guaranteed to be
persistent across device restarts or
system restarts.
In the way you can compare \\.\SCSI0 devices and \\.\PhysicalDrive0 and find out the correspondence.

Is MsiOpenProduct the correct way to read properties from an installed product?

Given an MSI product code I want to get the upgrade code (among other properties) from an already installed product. I have tried this by calling the MsiOpenProduct method, followed by MsiGetProductProperty(). An (abbreviated) example looks like this:
MSIHANDLE handle = NULL;
MsiOpenProduct(strProductCode,&handle);
CString strUpgradeCode;
MsiGetProductProperty(handle,_T("UpgradeCode"), strUpgradeCode.GetBuffer(GUID_LENGTH), &dwSize);
strUpgradeCode.ReleaseBuffer();
MsiCloseHandle(handle);
This gets me the desired value, and judging from the MSDN documentation this seems like a valid way to do this:
The MsiOpenProduct function opens a
product for use with the functions
that access the product database. The
MsiCloseHandle function must be called
with the handle when the handle is no
longer needed.
However the call to MsiOpenProduct() pops up the "Windows installer is preparing the installation..." dialog. The call to MsiCloseHandle() makes it disappear again.
This left me wondering:
What does the call to MsiOpenProduct() do under the hood? I do not want to trigger any actions, I just want to read properties.
I don't mind the dialog popping up, as this is only for unit test code as long as this has no side effects. And as there are many unit tests that do this, it must still work when opening and closing handles in rapid succession.
Although I stumbled over the MsiGetProductInfo method, there seems to be no way to get the upgrade code. Am I right?
Is MsiOpenProduct the correct way to read properties like the upgrade code?
MsiOpenProduct should be fine So long as you don't run any sequences or actions, it won't do anything. If you want to silence the dialog, you can with careful use of either MsiSetInternalUI() or MsiSetExternalUI().
Another approach you can take, as long as the ProductCode and UpgradeCode are safely static (i.e. as long as they aren't changed by transforms), is to locate the database using MsiGetProductInfo() and call MsiOpenDatabase() on that. The difference is that MsiOpenProduct() (or similarly MsiOpenPackage) applies the transforms that were used at installation time and prepares a session, whereas MsiOpenDatabase() does neither.
There is a comprehensive answer with information on how to get the UpgradeCode using Powershell or VBScript and WMI here: How can I find the Upgrade Code for an installed MSI file?
Below is a quick, basic example using VBScript / COM automation (MSI API, not WMI) and the approach discussed by OP (using the OpenProduct method - the COM equivalent to the Win32 installer function).
As discussed in my comment above, I will just add this little VBScript to do the same as OP does in C++. Note that Windows Installer can be accessed via WMI (Win32_Product object), COM automation and Win32 C++ installer functions.
For some reason the UpgradeCode for a package appears to not be available directly from the COM API or the Win32 API. Very strange indeed, especially since it is an input parameter to functions like Installer.RelatedProducts - it is not clear in the documentation that the actual call should be RelatedProducts(UpgradeCode), but looking in the msi.IDL you see: StringList* RelatedProducts([in] BSTR UpgradeCode);
The WMI option works, but so does this OpenProduct call demonstrated below (which is significantly faster and appears safe - WMI is completely read-only as far as I know though - but heaven knows what they are doing "under the hood". Are they spinning up a session object? Or are they reading from a WMI database? WMI does "feels" safer somehow).
The beauty of the below method is that it will apply all transforms that were applied to the product in question at installation time. If you want to write to disk instead of showing message boxes and can't be bothered looking up the docs, here is a similar VBScript that writes package info to a desktop text file: How can I find the product GUID of an installed MSI setup? - quite a bit down the page, just copy a couple of lines and you are message box free).
Note! The script below will create one log file per opened MSI if automatic logging is enabled on the system. As it stands the script will only open one MSI before it exists though (the Exit For construct).
On Error Resume Next ' This "tersified" script has no error handling
Const msiUILevelNone = 2
Set installer = CreateObject("WindowsInstaller.Installer")
Set products = installer.ProductsEx("", "", 7)
installer.UILevel = msiUILevelNone ' Suppress GUI (MSI progress dialog)
'Iterate over all MSI packages on the box
For Each product In products
' productcode = product.ProductCode
' name = product.InstallProperty("ProductName")
' version = product.InstallProperty("VersionString")
' pkgcode = product.InstallProperty("PackageCode")
Set session = installer.OpenProduct(product.ProductCode)
upgradecode = session.ProductProperty("UpgradeCode")
MsgBox upgradecode
Set session = Nothing ' Important, close the session (doesn't work in Javascript btw)
Exit For ' End after one iteration (so you don't get a million message boxes)
' Alternatively something like: If i > 4 Then Exit For
Next
Set installer = Nothing
MsgBox "Finished"
I have tried to look in the C++ Win32 installer functions for any other way to retrieve the UpgradeCode, but I can't see anything obvious. The session approach should work in C++ as well, but I am a little apprehensive about the release of handles and resources. I am not properly potty-trained with C++, but know more than enough to be dangerous. Fire In The Hole. Etc...
I wonder if the OP retrieved all packages on the box, or just a single one. I wonder if the timing issues and concurrent session object problems seen with Javascript would strike in C++ as well? I will give it a go I think - someday.
For the information you want, it sounds like you can just call ::MsiGetProductInfo(). ::MsiOpenDatabase() is a very slow operation while ::MsiGetProductInfo() is (IIRC) more on par with registry look ups.