⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dde_stuf.cpp

📁 a program that generates a pulse-width modulated (PWM)signal.
💻 CPP
📖 第 1 页 / 共 5 页
字号:
//*************************************************************************************
//  DDE_Stuf.cpp
//      This file contains the class member functions for DDE handler objects.  These
//      objects encapsulate a DDE communication interface which allows C++ programs to
//      talk to each other (or to other applications) using dynamic data exchange.
//      Note that since DDE is a Windows phenomenon, this file can only be compiled
//      and run under Windows.  Also, it's designed for 32-bit, Windows 95/NT mode.
//
//  Classes
//      C_DDE_Item    - An item of data maintained by one of a server's topics
//      C_DDE_Topic   - A topic which is to be serviced by a DDE server
//      C_DDE_Manager - Base class with common code for client and server objects
//      C_DDE_Server  - A DDE server which services a bunch of topics and items
//      C_DDE_Client  - A client which can talk to a DDE server
//
//  Nonmember Functions
//      DDE_CheckForError          - Check for errors from the DDEML library
//      DDE_ErrorString            - Convert DDE error codes into readable strings        
//      DDE_Server_WndProc         - Processes messages for DDE server window
//      Create_DDE_Server_Window   - Creates the DDE server window
//      DDE_Server_Thread_Function - Function which runs the DDE server's thread
//      DdeServerCallback          - DDEML callback handles incoming DDE transactions
//      DdeClientCallback          - A similar callback, but for DDE client objects
//
//  Version
//       8-16-97  JRR  Original file
//       9-02-97  JRR  Added thread protection for data
//       9-07-97  JRR  A few changes to make it compatible with client object
//       9-14-97  JRR  Merged server and client into one file for convenience
//*************************************************************************************

#ifdef __WIN32__            //  This file should only be compiled for Win32 projects

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <ddeml.h>
#include <DDE_Stuf.hpp>
#include "MT_Debug.hpp"

//  We need global pointers to the DDE objects so the callback functions, which are
//  not member functions, can access member functions and data of the server object
static C_DDE_Server* The_DDE_Server = NULL;
static C_DDE_Client* The_DDE_Client = NULL;

static HWND hDDE_Server_Window = NULL;      //  Handles for the server's and client's
static HWND hDDE_Client_Window = NULL;      //  little GUI windows

static bool DDE_ServerTimeToStop = false;   //  These flags synchronize the exiting
static bool DDE_ServerThreadDone = false;   //  of the DDE threads with the server's
static bool DDE_ClientTimeToStop = false;   //  and the client's destructors
static bool DDE_ClientThreadDone = false;

static int NumConnections = 0;              //  Number of clients currently connected
const int MAX_TIMEOUT = 1000;               //  How long to wait for thread to finish


//-------------------------------------------------------------------------------------
//  Function:  DDE_CheckForError
//      This function checks to see if there has been a DDE error.  If there has, it
//      displays a complaint.

void DDE_CheckForError (DWORD idInstance)
    {
    UINT ErrorCode;                         //  Save the error (or no error) code here

    if ((ErrorCode = DdeGetLastError (idInstance)) != DMLERR_NO_ERROR)
        MessageBox (NULL, DDE_ErrorString (ErrorCode), "DDE Error!",
                    MB_OK | MB_ICONEXCLAMATION);
    }


//-------------------------------------------------------------------------------------
//  Function:  DDE_ErrorString
//      This function simply finds the correct string for a given DDE error, puts it
//      into the buffer it maintains, and returns a pointer to that buffer.

const char* DDE_ErrorString (UINT TheError)
    {
    static char DDE_Debug_String[64];       //  Buffer holds debugging strings

    //  Macro which copies DDE error strings into a buffer for output from function
    #define  ErrorDecode(x,y)  case (x): strcpy (DDE_Debug_String, (y)); break

    switch (TheError)
        {
        ErrorDecode (DMLERR_NO_ERROR, "NO ERROR: Oops, there's no error");
        ErrorDecode (DMLERR_ADVACKTIMEOUT, "Advise ACK timeout");
        ErrorDecode (DMLERR_BUSY, "Somebody's busy");
        ErrorDecode (DMLERR_DATAACKTIMEOUT, "Data ACK timeout");
        ErrorDecode (DMLERR_DLL_NOT_INITIALIZED, "DLL not initialized");
        ErrorDecode (DMLERR_DLL_USAGE, "DLL usage");
        ErrorDecode (DMLERR_EXECACKTIMEOUT, "Exec ACK timeout");
        ErrorDecode (DMLERR_INVALIDPARAMETER, "Invalid parameter");
        ErrorDecode (DMLERR_LOW_MEMORY, "Low memory");
        ErrorDecode (DMLERR_MEMORY_ERROR, "Memory error");
        ErrorDecode (DMLERR_NOTPROCESSED, "Not processed");
        ErrorDecode (DMLERR_NO_CONV_ESTABLISHED, "No conversation established");
        ErrorDecode (DMLERR_POKEACKTIMEOUT, "Poke ACK timeout");
        ErrorDecode (DMLERR_POSTMSG_FAILED, "Post message failed");
        ErrorDecode (DMLERR_REENTRANCY, "Re-entrancy is a no-no");
        ErrorDecode (DMLERR_SERVER_DIED, "Server died *sniff*");
        ErrorDecode (DMLERR_SYS_ERROR, "System error");
        ErrorDecode (DMLERR_UNADVACKTIMEOUT, "Unadvise ACK timeout");
        ErrorDecode (DMLERR_UNFOUND_QUEUE_ID, "Queue not found");
        default:
            sprintf (DDE_Debug_String, "Unknown error code %d", TheError);
            break;
        }
    return DDE_Debug_String;
    }


//-------------------------------------------------------------------------------------
//  Function:  DDE_WndProc
//      This is the window procedure for the DDE server window.  The DDE server runs
//      in its own thread and has its own message loop, and this is the procedure
//      which services messages for that window.

LRESULT CALLBACK DDE_WndProc (HWND hWnd, WPARAM message, WPARAM wParam, LPARAM lParam)
    {
    static LONG TextLineHeight;             //  Saves height of a line of screen text
    static TEXTMETRIC TextMetrics;          //  Structure for getting GUI text info
    PAINTSTRUCT PaintStruct;                //  Structure for talking to Windows GUI
    HDC hDevContext;                        //  Another structure for talking to GUI
    RECT ClientRect, DrawRect;              //  Rectangle structures, also for GUI
    char TextBuffer[80];                    //  Buffer holds a line of displayed text

    switch (message)
        {
        //  This message appears when the window is first being created
        case WM_CREATE:
            //  Figure out how big the window text is
            hDevContext = GetDC (hWnd);
            GetTextMetrics (hDevContext, &TextMetrics);
            TextLineHeight = TextMetrics.tmHeight + TextMetrics.tmExternalLeading;
            ReleaseDC (hWnd, hDevContext);
            return FALSE;

        //  This message means the window must be repainted.  Display text in the
        //  window showing how many connections to this server are currently active
        case WM_PAINT:
            BeginPaint (hWnd, &PaintStruct);
            SetBkMode (PaintStruct.hdc, TRANSPARENT);
            GetClientRect (hWnd, &ClientRect);
            ClientRect.bottom = ClientRect.top + TextLineHeight;
            wsprintf (TextBuffer, "%d connections active", NumConnections);
            DrawRect = ClientRect;
            if (IntersectRect (&DrawRect, &ClientRect, &(PaintStruct.rcPaint)))
                DrawText (PaintStruct.hdc, TextBuffer, -1, &ClientRect, DT_DDESTYLE);
            EndPaint (hWnd, &PaintStruct);
            break;

        //  If the message isn't anything we know about, let Windows deal with it
        default:
            return DefWindowProc (hWnd, message, wParam, lParam);
        }

    return FALSE;
    }


//-------------------------------------------------------------------------------------
//  Function:  Create_DDE_Window
//      This function creates a window just for the DDE server.  The window is just a
//      small white popup named "DDE Server" which doesn't display anything much.  A
//      handle for the window is returned.

HWND Create_DDE_Window (const char* aTitle)
    {
    WNDCLASS wc;

    wc.style = 0;                                   //  Class styles
    wc.lpfnWndProc = DDE_WndProc;                   //  Name of message loop function
    wc.cbClsExtra = 0;                              //  Not using Class Extra data
    wc.cbWndExtra = 0;                              //  Not using Window Extra data
    wc.hInstance = NULL;                            //  Instance that owns this class
    wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);        //  Use default app. icon
    wc.hCursor = LoadCursor (NULL, IDC_ARROW);          //  Use arrow cursor
    wc.hbrBackground = GetStockObject (WHITE_BRUSH);    //  Use sys. backg. color
    wc.lpszMenuName = NULL;                             //  Resource name for menu
    wc.lpszClassName = "DDE Window Class";              //  Name for this class

    if (RegisterClass (&wc) == 0) return NULL;          //  Register the window class

    //  Create a window in the default X and Y position, size 240x100, no parent
    //  window nor menu, and owned by nobody
    return (CreateWindow ("DDE Window Class", aTitle,
                          WS_POPUP | WS_VISIBLE | WS_CAPTION, CW_USEDEFAULT,
                          CW_USEDEFAULT, 240, 100, 0, 0, NULL, NULL));
    }


//-------------------------------------------------------------------------------------
//  Function:  DDE_ServerThreadFunction
//      Because DDEML applications have to run entirely in one thread, the DDE server
//      object creates a thread and then runs entirely within it.  This is the thread
//      function for that thread.  It is started up by the C_DDE_Server constructor
//      and continues to run until the server object is deleted.

DWORD WINAPI DDE_ServerThreadFunction (LPVOID lpParam)
    {
    //  Set flag which tells other threads this one is still running
    DDE_ServerThreadDone = false;

    //  Create and display a window associated with the DDE system's thread
    if ((hDDE_Server_Window = Create_DDE_Window ("DDE Server")) == NULL)
        MessageBox (NULL, "Unable to create window", "DDE Error", MB_OK | MB_ICONSTOP);
    ShowWindow (hDDE_Server_Window, SW_SHOWNORMAL);
    UpdateWindow (hDDE_Server_Window);

    //  Wait until it's OK to register DDE server, topics, and items.  While waiting,
    //  give up the rest of each timeslice to other processes so they can do stuff
    while (The_DDE_Server->ReadyToRegister == false) Sleep (0);

    //  Initialize the DDE server object
    The_DDE_Server->Initialize ();

    //  Process messages for this window until we're told it's time to exit
    MSG msg;
    while (DDE_ServerTimeToStop == false)
        {
        //  Tell all items in advise loops to send data if it has been updated
        The_DDE_Server->SendAdviseData ();

        //  Process Windows messages in the ordinary way for GUI windows
        if (PeekMessage (&msg, 0, 0, 0, PM_REMOVE))
            {
            TranslateMessage (&msg);
            DispatchMessage (&msg);
            }

        //  If no message was received, give remainder of timeslice to other threads
        else Sleep (0);                    
        }

    //  Uninitialize the server; this must be done within this thread
    The_DDE_Server->Uninitialize ();
    DDE_ServerThreadDone = true;
    return 0;
    }


//-------------------------------------------------------------------------------------
//  Function:  DDE_ClientThreadFunction
//      This is the thread function for the DDE client thread.  It works the same way
//      as the DDE server thread function above works, but it is started up by the
//      C_DDE_Client constructor and it runs until the client object is deleted.

DWORD WINAPI DDE_ClientThreadFunction (LPVOID lpParam)
    {
    //  Set flag which tells other threads this one is still running
    DDE_ClientThreadDone = false;

    //  Create and display a window associated with the DDE system's thread
    if ((hDDE_Client_Window = Create_DDE_Window ("DDE Client")) == NULL)
        MessageBox (NULL, "Unable to create window", "DDE Error", MB_OK | MB_ICONSTOP);
    ShowWindow (hDDE_Client_Window, SW_SHOWNORMAL);
    UpdateWindow (hDDE_Client_Window);

    //  Wait until it's OK to register DDE server, topics, and items; then do so
    while (The_DDE_Client->IsReadyToRegister () == false) Sleep (0);
    The_DDE_Client->Initialize ();

    //  Process messages for this window until we're told it's time to exit
    MSG msg;
    while (DDE_ClientTimeToStop == false)
        {
        //  Update the client by checking if the DDE thread has any jobs to do
        The_DDE_Client->Update ();

        //  Check for Windows messages and process them if any have come in
        if (PeekMessage (&msg, 0, 0, 0, PM_REMOVE))
            {
            TranslateMessage (&msg);
            DispatchMessage (&msg);
            }
        else Sleep (0);                     //  If no message, let other threads run
        }

    //  Uninitialize the client, then shut down this thread
    The_DDE_Client->Uninitialize ();
    DDE_ClientThreadDone = true;
    return 0;
    }


//=====================================================================================
//  Class:  C_DDE_DataItem
//      This class represents one item of data to be maintained by the DDE server.
//      Each item has an item name, a type, and a value.
//=====================================================================================

//-------------------------------------------------------------------------------------
//  Constructor:  C_DDE_DataItem
//      These constructors create new C_DDE_DataItem objects.  One constructor is given
//      for each of the data types supported by the DDE server package.  The construc-
//      tor allocates storage space for the local copy (used by the DDE thread) of the
//      data and calls the common Construct() function to set everything else up.

C_DDE_Item::C_DDE_Item (const char* aName, int& rData)
    {
    pTheData = new int[1];                  //  Allocate space for the data
    *(int*)pTheData = rData;                //  Read the initial value of the data in
    TheDataType = DDT_int;                  //  Save the type of the data
    Construct (aName);                      //  Call the common constructor code
    }

C_DDE_Item::C_DDE_Item (const char* aName, unsigned int& rData)
    {
    pTheData = new unsigned int[1];         //  See comments above
    *(unsigned int*)pTheData = rData;
    TheDataType = DDT_uint;
    Construct (aName);
    }

C_DDE_Item::C_DDE_Item (const char* aName, long& rData)
    {
    pTheData = new long[1];                 //  Etc.
    *(long*)pTheData = rData;
    TheDataType = DDT_long;
    Construct (aName);
    }

C_DDE_Item::C_DDE_Item (const char* aName, unsigned long& rData)
    {
    pTheData = new unsigned long[1];
    *(unsigned long*)pTheData = rData;
    TheDataType = DDT_ulong;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -