Hello,
I am trying to interface with a laboratory instrument using C++. I realize that my C++ experience falls short of desirable for this task; I am a self-taught amateur C# programmer delving into C++ and much of the code I have written is new to me. However, I have been largely able to follow the instructions in the instrument manual and have an almost-working code with a couple problems that I would like help with. I will outline the problems below and then highlight them in the code.
My function takes a string as an input, but the message sending function takes a char array. I have tried multiple ways to do the conversion and each one results in a compile-time error (function call missing argument list; detailed further in the code below).
After sending the instruction, the instrument is supposed to send back a status update. The final part of this code is supposed to listen to this update, but it gives a ton of errors if I reproduce it from the instrument manual (also detailed in the code).
If anyone could help me resolve these issues I would appreciate it enormously. I have reproduced the code below. I reproduced the manual in a comment above each relevant code section, and also commented on the sections that aren't working (highlighted by the ####PROBLEM#### tag). Thank you!
#include "stdafx.h"
#include<iostream>
#include<vector>
#include<string>
//#include<WinUser.h>
#include<Windows.h>
//#include<afxwin.h>
//#include "Commands.h"
using namespace std;
void SendCommand(string command)
{
//for testing purose:
command = "CloseDrawer";
/*MANUAL
Call the Win32 RegisterWindowMessagefunction to register a unique message tag. SoftMax Pro uses this tag information when the command is
received to distinguish between a Windows generated message and an
external command. The value returned should be a non-zero value.
UINT tag = RegisterWindowMessage(“SOFTMaxProMsg”);
*/
//My Note: had to put "L" designator in front of string, otherwise obtain following error:
//argument of type "const char *" is incompatible with parameter of "LPCWSTR"
UINT tag = RegisterWindowMessage(L"SOFTMaxProMsg");
/*MANUAL
Call the Win32 RegisterWindowMessagefunction to register another unique
message tag. Your software will use this tag information when the asynchronous windows message is returned, and will distinguish between a
Windows generated message and an external command. The value
returned should be a non-zero value.
UINT replyTag = RegisterWindowMessage(“SOFTMaxProReplyMsg”);
*/
// My Note: same as above
UINT replyTag = RegisterWindowMessage(L"SOFTMaxProReplyMsg");
/*MANUAL
All messages must be sent to the SoftMax Pro main window. Note, if SoftMax Pro is not currently running this will return a null value,
thus, requiring your program to discontinue until SoftMax Pro is restarted.
HWND hwnd = FindWindow(“SOFTMaxProMainWnd”, “SoftMax Pro”);
*/
HWND hwnd = FindWindowA("SOFTMaxProMainWnd", "SoftMax Pro");
/*MANUAL
Get your window handle. This is the window to receive the return message.
HWND MyWnd = GetSafeHwnd()
*/
// My Note:
// 1: If I use the code above, I get "identifier GetSafeHwnd is undefined"
// 2: If I include afxwin.h and use HWND MyWnd = CWnd::GetSafeHwnd, I get "Error: a nonstatic member reference must be relative to
// a specific object"
// 3: I google searched, and the following code line accomplishes the same task (I think).
HWND MyWnd = ::GetActiveWindow();
/*MANUAL
Assign which command you wish to send. Place the command in heap
space, which appears to be necessary with older Windows operating systems.
char *cmdStr = “Read”;// Example remote command to send
char *msgStr = _strdup(cmdStr); // String duplication, copy command to heap space.
*/
//##### PROBLEM #####
//My Note: The following cast results in error C3867: 'std::basic_string<_Elem,_Traits,_Alloc>::c_str': function call missing argument list; use '&std::basic_string<_Elem,_Traits,_Alloc>::c_str' to create a pointer to member
//char *cmdStr = command.c_str; // note: command is the input string passed to this function
//My Note: using the following for the sake of debugging
char *cmdStr = "CloseDrawer";
char *msgStr = _strdup(cmdStr);
/*MANUAL
Create the Win32 COPYDATASTRUCT message that will be sent. See Microsoft
documentation regarding this structure for details.
COPYDATASTRUCT cd; // This struct is defined in Microsoft include file
cd.dwData = (DWORD) MyWnd; // Handle to a window receiving return information
cd.cbData = strlen(msgStr)+1; // Length of message string, adding 1 for null terminator
cd.lpData = msgStr;// String pointer to remote command
*/
COPYDATASTRUCT cd;
cd.dwData = (DWORD) MyWnd;
cd.cbData = strlen(msgStr)+1;
cd.lpData = msgStr;
/*MANUAL
Finally, send the message to SoftMax Pro. A complete of list of remote commands can be found in
“SoftMax Pro Commands” on page 12-9. Don't forget that the tag value, from RegisterWindowMessageabove,
is sent with the command string. (See Microsoft documentation regarding the SendMessage function for more information.)
SendMessage(hwnd, WM_COPYDATA, tag, (LPARAM) &cd)
*/
SendMessage(hwnd, WM_COPYDATA, tag, (LPARAM) &cd);
/*Manual
Either a completion message or return data is returned. Remote commands
Return Status, Return Timing, and ReturnData return data. In either case, data
is received through an asynchronous windows message inside Win32 COPYDATASTRUCTtype data packet.
For example, a typical OnCopyDatawindow callback is shown below, where
the string data retrieved is finally stored into a Microsoft CString object.
Note the use of variable replyTag, discussed above, which is used to isolate
the correct windows message returned.
BOOL CUserDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* cd)
{
….
if (cd->dwData == replyTag)
{
// String pointing to status //
CString retStatus = (char*) cd->lpData;
}
….
}
*/
//##### PROBLEM #####
// Note: The Bool CUserDlg line below produces the following error:
// Error: name followed by "::" must be a class or namespace name
// The only reference to CUserDlg::OnCopyData that I could find on google was for this manual
/*
BOOL CUserDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* cd);
{
if (cd->dwData == replyTag)
{
CString retStatus = (char*) cd->lpData;
cout << retStatus << endl;
}
}
*/
}
The code above works to an extent; the instrument successfully closes its drawer. However, I'd like to make the function be able to dynamically send whatever command is passed to it, and also be able to listen for a reply. Thanks for any help!