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.

  1. 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).

  2. 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!

//char *cmdStr = command.c_str;
c_str() is a function. It is called like this:
char *cmdStr = command.c_str();

Second issue:

The bit at the end looks like a a definition of a class function. Presumably you're not trying to define a class function; you're trying to use a function. In C++, to use a (non-staic) class function, you fist have to create an object of that class (in this case, an object of type CUserDlg), and then you can call that objects functions. Something like:

CUserDlg someInstance;
BOOL returnedValue;
returnedValue = someInstance.OnCopyData(first_parameter, second_parameter);

I wouldn't be surprised if you had to do something else with someInstance to ensure it's properly created, but the above lines of code sow an object of type CUserDlg being created, and then that objects class function OnCopyData being called. Exactly how and when that function is meant to be called I can't say without knowing more about the class.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.