title: WinAPI/MFC User-defined functions
body: <p>I have a simple C++ console application I use to drive a colorimeter.
  The functions that interface to the device were provided in the form of a MSVC DLL with <code>__cdecl</code> functions.</p>
  <p>I was also given the corresponding <code>.h</code> and <code>.lib</code> files. All processing rests on an Event handler that needs to be instantiated on startup. It is called from within the DLL functions to alert when data is ready for retrieval. The device is connected to the USB port and appears as a (virtual?) COM port in Device Manager (COM0).</p>
  <p>I need to &quot;port&quot; this simple application to a GUI environment to sustain my project. I tried QT Creator 5.15.2 (with MinGW Open Source option) and Embarcadero C++Builder, but getting access from these environments to the DLL functions is impossible. I experimented with wxWidget, but it &quot;did not work&quot; for me -- I could not get the Sample to execute, for some reason (couldn't find &quot;Main/Invoke&quot;?).</p>
  <p>So I turned my attention to MFC and WinAPI. Creating a C++ MFC app is &quot;straight forward&quot; up to the point that I have to figure &quot;how to interface&quot; my device to this system. I tried creating a custom class, <code>myDevice</code>, to regroup all my custom functions such as &quot;Connect&quot; and &quot;Calibrate&quot; and &quot;Measure&quot;.</p>
  <p>In <code>main.h</code>, I declare this class:</p>
  <pre><code>class myDevice{
  private:
     //bool CalibratedStatus;
  public:
     bool Connect();
     bool Calibrate();
     bool Measure();
     myDevice();
     ~myDevice();
  };
  </code></pre>
  <p>Then in <code>Main.cpp</code>, I have the member functions definitions:</p>
  <pre><code>MainApp::MainApp()
  {
      // TODO: add construction code here,
      DEVICE_ERROR_TYPES deviceError = DEVICE_RegisterDeviceEventHandler(EventNotice);
  
      // Place all significant initialization in InitInstance
  }
  
  myDevice::MyDEVICE() { }
  myDevice::~MyDEVICE() { }
  
  bool myDevice::Connect() {
  
      string StatusDEVICE;
      uint8 StateTableRB, portInfoName, portInfoSerialNo;
      string DevicePortList;
      uint32 portCount = 0;
      DEVICE_PortInfo portInfo[16];
      uint8 StateTable[2][4] = { &quot;Eth&quot;, &quot;USB&quot; };
  
      // &quot;01 Looking for the instrument...
      DEVICE_GetDevicePortList(0, &amp;portCount, 0);
  
      if (portCount &gt; 16) {
          portCount = 16;
      }
      else if (portCount &lt; 1) {
          // printf(&quot;device not found\n&quot;);
         return false;
      }
  
      DEVICE_GetDevicePortList(portInfo, &amp;portCount, portCount);  // display device list
  
      deviceError = DEVICE_Connect(&amp;portInfo[0], 10);
  
      if (DEVICE_SUCCESSFUL(deviceError)) {
          StatusDEVICE = &quot;Device Connect Complete!&quot;;
          // printf(&quot;Device Connect Complete!\n&quot;);
          return true;
      }
  }
  
  bool myDevice::Calibrate() { }
  
  bool myDevice::Measure() {
  
      if (CalibratedStatus == true) {
  
          // Set measure condition
          DEVICE_MeasureCondition measureCondition = { measureType, 0 };
          deviceError = DEVICE_SetMeasureCondition(&amp;measureCondition);
          // start measurement
          deviceError = DEVICE_StartMeasurement();
  
          if (device_SUCCESSFUL(deviceError)) {
             while (!isMeasureWait) {
                 if (isDisConnect) break; 
                 // waiting for measurement complete
                    this_thread::sleep_for(chrono::milliseconds(1000));
             }
             ExportMeasureData(measureType);
             isMeasureWait = true;
             return true;
          }
          else return false;
      }
  }
  </code></pre>
  <p>Then I need to use these flags:</p>
  <pre><code>bool isMeasureCompleted = false;
  bool isCcalibrationCompleted = false;
  bool isCcalibrationFailed = false;
  bool isMeasureWait = false;
  </code></pre>
  <p>Which I place above the <code>MainApp::MainApp()</code> line (Globals?).</p>
  <p>I'll admit I don't have any experience coding for MFC or WinAPI, but I have a hunch it's radically different from declaring an Event handler somewhere in the middle of a source file and followed by a bunch of loose functions that retrieve data.</p>
  <p>Somehow, it is not clear to me WHERE can 'user-defined functions&quot; like these 'strategically' be placed? And called? If I create a button, let's say, to 'Connect' to the Device, in the button handler, it's easy to place the code that connects to the device and execute it from there. But what about the &quot;Return&quot;? Because the return is not 'direct' (maybe it's 'asynchronous'?); the return always takes the route of the Event Handler and lands in the Event Notice that's where I have a Switch statement that redirects the task to the function that correspond to the &quot;Event received&quot;. I cannot change that behavior.</p>
  <p>I was reading about Serial communications applications that, from what I understand, use &quot;Serial Events&quot; from within MFC, to trigger calls to the functions? But that's really 'new' to me. I'm not sure whether this would be a good approach? As you can see in the code above, there is a 'thread sleep' that executes &quot;while the device&quot; is busy? Once the device is done, it calls the Event Notice handler on its own with its response:</p>
  <pre><code>void EventNotice(DEVICE_EventCode outEventCode, uint32 outRAWDataCount, DEVICE_ERROR_TYPES outError)
  {
         switch (outEventCode) {
           case Event_Standby:        // 0
              // cout &lt;&lt; &quot;Standby...&quot; &lt;&lt; endl;
               break;
           case Event_MeasureWait:        // 1
              if (isMeasureCompleted) {
                 // export measure data
                 // printf(&quot;\n04 Export Measure Data...&quot;);
                 ExportMeasureData(measureType);          
                 isMeasureWait = true;
           case ...
  </code></pre>
  <p>I need to be able to implement this Event Handler function as is? Otherwise, I don't have access to the device.</p>
  <p>That's where I'm not sure how this can be done in a &quot;Message processing&quot; approach: I can't just &quot;dump&quot; the Event handler code anywhere and expect the device to find the Event handler by magic, on its own, right? It does not work like in a simple procedural program, does it?</p>
  <p>I've been reading a lot about how to transpose my silly console application code to MFC/WinAPI, but all I find are references to how to <em>use</em> the API itself, how to create buttons and menus and resources, but nothing like what I'm trying to accomplish.</p>
  <p>==== Update 2021 04 14</p>
  <p>@Remy: I moved the DLL function calls out of my class and now getting a different kind of error from the Linker. Before, the error referred to
  &quot;public: __thiscall&quot; ...., now, the error refers to
  &quot;public: __cdecl&quot;.</p>
  <p>I read this morning that c++ functions were always prefixed with &quot;__thiscall&quot;?
  I got rid the of the __thiscall prefix but but the Linker is still unable to find the functions. with the __cdel prefix. BTW, I would <em>love</em> to embark on this project with C++ Builder!! I tried using IMPLIB and COFF2OMF and then IMPDEF but was not successful to coerce the DLL to work with C++ Builder to no avail.
  From the documentation: C++Builder cannot use .lib files from other compilers, only its own. If the .lib file is an import lib for a DLL, use C++Builder's command-line IMPLIB tool to create a new .lib file from the DLL directly. Which is what I did (to the best of my ability).
  In the end, I used this statement in my Source file to direct the compiler to my new .lib version : #pragma comment(lib, &quot;FDXSDK.lib&quot;)</p>
  <p>Here are the first four lines of the EDF I got from IMDEF :</p>
  <p>LIBRARY     DEVICE.DLL
  EXPORTS
  DEVICE_CalculateMeasureData       @60  ; DEVICE_CalculateMeasureData
  DEVICE_Calibration                @61  ; DEVICE_Calibration</p>
  <p>I tried contacting Embarcadero support but since I'm only using the 'Community' edition, there is no support -- forget about the Forum. I search every reference I could and tried everything I could before giving up.</p>
  <p>At the end of the day, I'm still getting &quot;Unresolved Reference&quot; from Embarcadero Linker.</p>
  <p>=== UPDATE 2  / 2021 04 15 ================
  I looked at Dumpbin utility to check on the function names inside the DLL and got this output (only showing the first lines):</p>
  <p>dumpbin DEVICE.dll /EXPORTS
  Microsoft (R) COFF/PE Dumper Version 14.28.29913.0
  Copyright (C) Microsoft Corporation.  All rights reserved.</p>
  <p>Dump of file device.dll</p>
  <p>File Type: DLL</p>
  <p>Section contains the following exports for DEVICE.dll</p>
  <pre><code>00000000 characteristics
  FFFFFFFF time date stamp
      0.00 version
         1 ordinal base
        91 number of functions
        91 number of names
  
  ordinal hint RVA      name
  
       60    0 0003E2F0 DEVICE_Calculate
       61    1 0003DA60 DEVICE_Calibrate
       62    2 0003DE10 DEVICE_Cancel
       63    3 0003D7D0 DEVICE_Connect
       64    4 0003D8E0 DEVICE_Disconnect
  </code></pre>