Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
CODE PROJECT For Those Who Code
  • Home
  • Articles
  • FAQ
Community
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Driver architecture advice needed

Driver architecture advice needed

Scheduled Pinned Locked Moved C / C++ / MFC
questioncsharpc++com
9 Posts 3 Posters 4 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • W Offline
    W Offline
    Work
    wrote on last edited by
    #1

    Hi all, I am developing a driver for communication with some PLC's. First, I thought to create a win32 dll, but because I need to be able to send and receive messages, I start using MFC. One of the requirements of the driver was that it could be used in VC++, Visual Basic, VB.NET, C# (so a lot of different languages). Well, because I have developed a class that needs to be called in the dll (so you can use driver->Connect() and so on), I needed to export a class. But, in this case, other languages such as visual basic wouldn't understand the dll. Then, someone gave me the advice to use COM objects. Well, it seems very hard to learn using COM, and some people say it will not be used anymore soon. Now is my question, what is the best way to develop this driver??? Thanks! Geert [url]http://geert.yoki.org[/url]

    A 1 Reply Last reply
    0
    • W Work

      Hi all, I am developing a driver for communication with some PLC's. First, I thought to create a win32 dll, but because I need to be able to send and receive messages, I start using MFC. One of the requirements of the driver was that it could be used in VC++, Visual Basic, VB.NET, C# (so a lot of different languages). Well, because I have developed a class that needs to be called in the dll (so you can use driver->Connect() and so on), I needed to export a class. But, in this case, other languages such as visual basic wouldn't understand the dll. Then, someone gave me the advice to use COM objects. Well, it seems very hard to learn using COM, and some people say it will not be used anymore soon. Now is my question, what is the best way to develop this driver??? Thanks! Geert [url]http://geert.yoki.org[/url]

      A Offline
      A Offline
      Antti Keskinen
      wrote on last edited by
      #2

      Hi ! I'm somewhat unsure what you're trying to do. I take it that PLC stands for Programmable Logic Controller, yes ? In this case, how do these controllers connect to your PC ? Do you have any hardware-level drivers which allow sending and receiving data from the controller ? Or is it your task to develop a Windows hardware driver to communicate with the controllers ? If you're developing a hardware driver, DO NOT USE MFC. That's something you just DO NOT do. Drivers are written mainly in C, and do not use MFC. If you've never written a hardware driver, then you're in for a mess. First write the driver itself, then consider options on how to allow client access to the driver. Do not incorporate direct client access to the driver itself (that means, use a DLL to interface a client application to the driver), because this hampers the reliability of the driver. Unreliable drivers will crash the OS. If you already have a device driver provided by the PLC manufacturer, that allows you to send and receive data from the controller, and you're building the DLL that allows flexible access to the driver, then you can use MFC if you need to, but it's again not recommended. MFC is mainly for user interface applications, or solid Windows applications. In this case, the best option is to create a COM component which, when opened up, opens a handle to the device driver, and then offers an interface through which data can be written and read. Writing a COM component is quite easy when you use the wizards. They generate most of the background code and your job is to implement the actual business logic. To get you started on COM development, consult your local library for possible books. Rest assured, COM will not go anywhere, it will remain around for a long time still. Learning it is useful, because a lot of Windows subsystems, such as WMI or DirectX, are implemented as COM objects. If you need more information, post more details on the project, such as what the PLC actually is, if you have a hardware driver from the manufacturer and what the precise task you're trying to accomplish is. -Antti Keskinen ---------------------------------------------- "If we wrote a report stating we saw a jet fighter with a howitzer, who's going to believe us ?" -- R.A.F. pilot quote on seeing a Me 262 armed with a 50mm Mauser cannon.

      G 1 Reply Last reply
      0
      • A Antti Keskinen

        Hi ! I'm somewhat unsure what you're trying to do. I take it that PLC stands for Programmable Logic Controller, yes ? In this case, how do these controllers connect to your PC ? Do you have any hardware-level drivers which allow sending and receiving data from the controller ? Or is it your task to develop a Windows hardware driver to communicate with the controllers ? If you're developing a hardware driver, DO NOT USE MFC. That's something you just DO NOT do. Drivers are written mainly in C, and do not use MFC. If you've never written a hardware driver, then you're in for a mess. First write the driver itself, then consider options on how to allow client access to the driver. Do not incorporate direct client access to the driver itself (that means, use a DLL to interface a client application to the driver), because this hampers the reliability of the driver. Unreliable drivers will crash the OS. If you already have a device driver provided by the PLC manufacturer, that allows you to send and receive data from the controller, and you're building the DLL that allows flexible access to the driver, then you can use MFC if you need to, but it's again not recommended. MFC is mainly for user interface applications, or solid Windows applications. In this case, the best option is to create a COM component which, when opened up, opens a handle to the device driver, and then offers an interface through which data can be written and read. Writing a COM component is quite easy when you use the wizards. They generate most of the background code and your job is to implement the actual business logic. To get you started on COM development, consult your local library for possible books. Rest assured, COM will not go anywhere, it will remain around for a long time still. Learning it is useful, because a lot of Windows subsystems, such as WMI or DirectX, are implemented as COM objects. If you need more information, post more details on the project, such as what the PLC actually is, if you have a hardware driver from the manufacturer and what the precise task you're trying to accomplish is. -Antti Keskinen ---------------------------------------------- "If we wrote a report stating we saw a jet fighter with a howitzer, who's going to believe us ?" -- R.A.F. pilot quote on seeing a Me 262 armed with a 50mm Mauser cannon.

        G Offline
        G Offline
        Geert van Horrik
        wrote on last edited by
        #3

        Thanks a lot for your answer! Well, you are right, PLC stands for Programmable Logic Controller. The communication is done via TCP/IP, so I can use winsock for communication. In my driver I have developed several classes. One to communicate with the PLC using winsock, one to communicate with the user, and a few extra classes. I don't think (at least I hope) that I don't have to write real hardware drivers, because that wouldn't be nice... You say I shouldn't use MFC. Well, I didn't plan to use it, but I needed a window handle to communicate with winsock (to receive messages). To do this, I needed the class CWnd, which belongs to MFC. Are there other possibilities to be able to receive messages??? Geert [url]http://geert.yoki.org[/]

        A 1 Reply Last reply
        0
        • G Geert van Horrik

          Thanks a lot for your answer! Well, you are right, PLC stands for Programmable Logic Controller. The communication is done via TCP/IP, so I can use winsock for communication. In my driver I have developed several classes. One to communicate with the PLC using winsock, one to communicate with the user, and a few extra classes. I don't think (at least I hope) that I don't have to write real hardware drivers, because that wouldn't be nice... You say I shouldn't use MFC. Well, I didn't plan to use it, but I needed a window handle to communicate with winsock (to receive messages). To do this, I needed the class CWnd, which belongs to MFC. Are there other possibilities to be able to receive messages??? Geert [url]http://geert.yoki.org[/]

          A Offline
          A Offline
          Antti Keskinen
          wrote on last edited by
          #4

          Hello ! Ah, this explains a lot. You're writing the user-mode component that allows communication with the device. The hardware drivers are already there, so you don't need to write them. To help you get started, decide how the user should be able to use the PLCs. What services do they require ? Must they be able to write a program for the PLC and upload it ? Should they be able to read the program from the device and need a way of illustrating (such as a schematic) which shows what the device is currently programmed to accomplish ? Drawing a diagram (UML or otherwise) helps you design a solid structure on which to build. After these decisions, the rest is quite trivial. You should follow standard COM strategy, in which you do not provide a direct access (a handle) to the device, but an interface, through which interaction is done. This will limit the user's possibilities to those which you have previously outlined, thus eliminating the user from accidentally or purposefully misusing your device. Writing an interface is as simple as writing a pure virtual base class, deriving from this class, and implementing the methods in the derived class. Then, you create a DLL which generates the class objects for each PLC device connected, and offers a routine through which a pointer to the interface class is returned to the caller. Using interface classes is very useful. You only need to provide the base class header file for the user, alongside with the exported DLL routines, a possible .lib file, and the actual DLL. No source code is required, because the runtime will worry about redirecting the virtual function calls to the object in which these functions are implemented. Namely, the one which the DLL creates and upkeeps. The internal implementation of the DLL depends on how you wish to present it. Winsock makes use of window objects to handle messaging (a Windows Message is sent whenever data is sent/received or the device is connected). You don't need MFC to create window objects. Just register a WNDCLASS structure and call CreateWindow, like in a normal Win32 program. Unless you already knew, MFC is a collection of classes which wrap standard Windows routines. For example, CWnd is class which encapsulates the creation and displaying of a Windows window object. But you don't have to rely on MFC to create the window objects. You can create them manually as well. There are many, many websites which show you how to create Win32 window objects. MSDN is full of examples: just whip out any Hello World -exam

          G 1 Reply Last reply
          0
          • A Antti Keskinen

            Hello ! Ah, this explains a lot. You're writing the user-mode component that allows communication with the device. The hardware drivers are already there, so you don't need to write them. To help you get started, decide how the user should be able to use the PLCs. What services do they require ? Must they be able to write a program for the PLC and upload it ? Should they be able to read the program from the device and need a way of illustrating (such as a schematic) which shows what the device is currently programmed to accomplish ? Drawing a diagram (UML or otherwise) helps you design a solid structure on which to build. After these decisions, the rest is quite trivial. You should follow standard COM strategy, in which you do not provide a direct access (a handle) to the device, but an interface, through which interaction is done. This will limit the user's possibilities to those which you have previously outlined, thus eliminating the user from accidentally or purposefully misusing your device. Writing an interface is as simple as writing a pure virtual base class, deriving from this class, and implementing the methods in the derived class. Then, you create a DLL which generates the class objects for each PLC device connected, and offers a routine through which a pointer to the interface class is returned to the caller. Using interface classes is very useful. You only need to provide the base class header file for the user, alongside with the exported DLL routines, a possible .lib file, and the actual DLL. No source code is required, because the runtime will worry about redirecting the virtual function calls to the object in which these functions are implemented. Namely, the one which the DLL creates and upkeeps. The internal implementation of the DLL depends on how you wish to present it. Winsock makes use of window objects to handle messaging (a Windows Message is sent whenever data is sent/received or the device is connected). You don't need MFC to create window objects. Just register a WNDCLASS structure and call CreateWindow, like in a normal Win32 program. Unless you already knew, MFC is a collection of classes which wrap standard Windows routines. For example, CWnd is class which encapsulates the creation and displaying of a Windows window object. But you don't have to rely on MFC to create the window objects. You can create them manually as well. There are many, many websites which show you how to create Win32 window objects. MSDN is full of examples: just whip out any Hello World -exam

            G Offline
            G Offline
            Geert van Horrik
            wrote on last edited by
            #5

            Thanks a lot for your answer! There are some other things I need with this "driver". Users should be able to call the dll from visual basic, visual basic.net, c# and c++. That is the reason why some people said I have to use COM. The first thing I did was develop a usefull architecture for the driver. This is done in UML. But because I normally develop applications using OO, I also designed the driver that way. I wanted the user to be able to call a connection like this: MyObject->GetPLCConnection(index)->Connect(); But visual basic is not made for OO :( Now, I am thinking of this: 1 COM object to communication with the PLC (for single connection). 1 COM object to hold all the connections the user wants. But then there is one problem left. How do I call functions from the collection COM to the connection COM. I hope it's clear what I mean... Thanks a lot so far for your time! Geert [url]http://geert.yoki.org[/]

            A 1 Reply Last reply
            0
            • G Geert van Horrik

              Thanks a lot for your answer! There are some other things I need with this "driver". Users should be able to call the dll from visual basic, visual basic.net, c# and c++. That is the reason why some people said I have to use COM. The first thing I did was develop a usefull architecture for the driver. This is done in UML. But because I normally develop applications using OO, I also designed the driver that way. I wanted the user to be able to call a connection like this: MyObject->GetPLCConnection(index)->Connect(); But visual basic is not made for OO :( Now, I am thinking of this: 1 COM object to communication with the PLC (for single connection). 1 COM object to hold all the connections the user wants. But then there is one problem left. How do I call functions from the collection COM to the connection COM. I hope it's clear what I mean... Thanks a lot so far for your time! Geert [url]http://geert.yoki.org[/]

              A Offline
              A Offline
              Antti Keskinen
              wrote on last edited by
              #6

              Hi ! COM offers language indepence, thus it is the most reasonable choice if you want your object to be usable from all languages which support COM. These include, but are not limited to, Visual C++/Basic/C#/.NET. Even PHP supports COM these days... However, back into the issue. The object-oriented approach is correct on this problem, but it seems you've started with wrong presumptions. First of, you don't need multiple COM objects. A single COM object which has multiple interfaces is enough. One interface for enumerating the available PLC devices and offering an index of the device, a second interface for connecting and disconnecting from the PLC and possibly a third interface which allows reading/writing from the device. And 1...n classes which implement these interfaces. 3 in the biggest case, 1 in the simplest case. The keyword here is multiple inheritance. Consider this example:

              class IEnumPLCDevices
              {
              public:
              virtual DWORD GetPLCList(int* nArray, int& nAmountOfDevices) = 0;
              };

              class IConnectPLCDevice
              {
              public:
              virtual DWORD ConnectToDevice(int nIndex, IPLCDevice** plcDeviceInterface) = 0;
              };

              class IPLCDevice
              {
              public:
              virtual DWORD Read(int nByteCount, void** pDestination) = 0;
              virtual DWORD Write(int nByteCount, void* pSource) = 0;
              };

              class PrivatePLCCollection : public IEnumPLCDevices, public IConnectPLCDevice, public IPLCDevice
              {
              public:
              .
              // Implementation of the virtual methods to enumerate, connect and interact with the devices
              // A routine which will return the required interface pointer
              .
              };

              Here is the simplest model I can use to fathom an object-oriented DLL. It is not a COM example, but it follows the 'interface' idealism I showed earlier. You don't need to seperate the communication and connections to different COM objects. They can co-exist peacefully inside a single object. You must remember here that a COM object is not the same thing as a C++ class. A COM object can have multiple C++ classes inside it. For an example, consider DirectX. It has multiple interfaces, and even more classes. Some classes implement more than one interface. However, each DirectX component is a single, independent COM object, such as Direct3D. You don't need the DirectSound object to use the Direct3D object's services, but the Direct3D object offers all the services to create, populate and manipulate 3D scenes. Lots of services (classes/interfaces), but a single COM object. I believe there are some examples in CodePro

              G 1 Reply Last reply
              0
              • A Antti Keskinen

                Hi ! COM offers language indepence, thus it is the most reasonable choice if you want your object to be usable from all languages which support COM. These include, but are not limited to, Visual C++/Basic/C#/.NET. Even PHP supports COM these days... However, back into the issue. The object-oriented approach is correct on this problem, but it seems you've started with wrong presumptions. First of, you don't need multiple COM objects. A single COM object which has multiple interfaces is enough. One interface for enumerating the available PLC devices and offering an index of the device, a second interface for connecting and disconnecting from the PLC and possibly a third interface which allows reading/writing from the device. And 1...n classes which implement these interfaces. 3 in the biggest case, 1 in the simplest case. The keyword here is multiple inheritance. Consider this example:

                class IEnumPLCDevices
                {
                public:
                virtual DWORD GetPLCList(int* nArray, int& nAmountOfDevices) = 0;
                };

                class IConnectPLCDevice
                {
                public:
                virtual DWORD ConnectToDevice(int nIndex, IPLCDevice** plcDeviceInterface) = 0;
                };

                class IPLCDevice
                {
                public:
                virtual DWORD Read(int nByteCount, void** pDestination) = 0;
                virtual DWORD Write(int nByteCount, void* pSource) = 0;
                };

                class PrivatePLCCollection : public IEnumPLCDevices, public IConnectPLCDevice, public IPLCDevice
                {
                public:
                .
                // Implementation of the virtual methods to enumerate, connect and interact with the devices
                // A routine which will return the required interface pointer
                .
                };

                Here is the simplest model I can use to fathom an object-oriented DLL. It is not a COM example, but it follows the 'interface' idealism I showed earlier. You don't need to seperate the communication and connections to different COM objects. They can co-exist peacefully inside a single object. You must remember here that a COM object is not the same thing as a C++ class. A COM object can have multiple C++ classes inside it. For an example, consider DirectX. It has multiple interfaces, and even more classes. Some classes implement more than one interface. However, each DirectX component is a single, independent COM object, such as Direct3D. You don't need the DirectSound object to use the Direct3D object's services, but the Direct3D object offers all the services to create, populate and manipulate 3D scenes. Lots of services (classes/interfaces), but a single COM object. I believe there are some examples in CodePro

                G Offline
                G Offline
                Geert van Horrik
                wrote on last edited by
                #7

                Thanks a lot! Thank god I can still use COM :) I have read some tutorials and can get a dll server and client communicate. One question left, and you are the best :) I tried to set return values of COM interface methods to BOOL or double. But, it says I MUST use HRESULT. Then why can I choose for the other ones??? And with your example, is it possible to call a plc connect function like this: MyObject->GetPLCConnection(index)->Connect(). In other words, can I return a pointer to another interface class with a function in a COM object?? Geert http://geert.yoki.org

                A 1 Reply Last reply
                0
                • G Geert van Horrik

                  Thanks a lot! Thank god I can still use COM :) I have read some tutorials and can get a dll server and client communicate. One question left, and you are the best :) I tried to set return values of COM interface methods to BOOL or double. But, it says I MUST use HRESULT. Then why can I choose for the other ones??? And with your example, is it possible to call a plc connect function like this: MyObject->GetPLCConnection(index)->Connect(). In other words, can I return a pointer to another interface class with a function in a COM object?? Geert http://geert.yoki.org

                  A Offline
                  A Offline
                  Antti Keskinen
                  wrote on last edited by
                  #8

                  Hi Tischnoetentoet wrote: One question left, and you are the best I'm far from the best, but I know my stuff. Guess that's one of the hazards of being a professional :D Thanks anyway :D All COM methods must return a HRESULT to the client. This is by design, because the clients use SUCCEEDED and FAILED macros to determine if they should continue with or retry the process, and the HRESULT values are designed to support these macros. This way, the client does not need to know what return values the server gives, other than the knowledge that SUCCEEDED and FAILED macros determine if it can continue using the object. If you must return a value to indicate the amount of PLC objects, you can use a reference variable or a pointer. Just create a function that takes an int& as variable, fill in the number of devices, and return a HRESULT that the enumeration was succesfull. The client can then check the integer to know how many devices there are. If you follow the standard, like you should, then a call chain like the one you describe is not possible, because each function must return a HRESULT. If you break the standard, you can do whatever you please, but your component is no longer COM compliant, and it might fail to work on a different language. Generally, you shouldn't require the client to build large call chains, instead, implement the HRESULT GetPLCConnection(int nIndex, IPLCDevice** pDeviceInterface). For this function, you pass the index value of the desired device and the interface pointer's address, and it returns you with a success code and a working pointer to the correct interface. IF the device doesn't exist, it NULLs the pointer and returns a failure code. Another reason for avoiding call chains is the reference counting. Whenever a COM object refers an interface, it increments the counter. When all interfaces are released, the counter goes zero, and the object can free the class responsible for serving this interface. If you build long call chains, the reference counting will not work, and your COM object does not act like a COM object should. Again, because different languages offer different levels of access to COM, your object might work on C++ (which has pointers) but fail on Visual Basic (which doesn't have them). In general, avoid call chains when dealing with COM. It makes your code and documentation much easier to follow for those people who have used COM earlier and know the way it should function. Breaking the standard will cause profe

                  G 1 Reply Last reply
                  0
                  • A Antti Keskinen

                    Hi Tischnoetentoet wrote: One question left, and you are the best I'm far from the best, but I know my stuff. Guess that's one of the hazards of being a professional :D Thanks anyway :D All COM methods must return a HRESULT to the client. This is by design, because the clients use SUCCEEDED and FAILED macros to determine if they should continue with or retry the process, and the HRESULT values are designed to support these macros. This way, the client does not need to know what return values the server gives, other than the knowledge that SUCCEEDED and FAILED macros determine if it can continue using the object. If you must return a value to indicate the amount of PLC objects, you can use a reference variable or a pointer. Just create a function that takes an int& as variable, fill in the number of devices, and return a HRESULT that the enumeration was succesfull. The client can then check the integer to know how many devices there are. If you follow the standard, like you should, then a call chain like the one you describe is not possible, because each function must return a HRESULT. If you break the standard, you can do whatever you please, but your component is no longer COM compliant, and it might fail to work on a different language. Generally, you shouldn't require the client to build large call chains, instead, implement the HRESULT GetPLCConnection(int nIndex, IPLCDevice** pDeviceInterface). For this function, you pass the index value of the desired device and the interface pointer's address, and it returns you with a success code and a working pointer to the correct interface. IF the device doesn't exist, it NULLs the pointer and returns a failure code. Another reason for avoiding call chains is the reference counting. Whenever a COM object refers an interface, it increments the counter. When all interfaces are released, the counter goes zero, and the object can free the class responsible for serving this interface. If you build long call chains, the reference counting will not work, and your COM object does not act like a COM object should. Again, because different languages offer different levels of access to COM, your object might work on C++ (which has pointers) but fail on Visual Basic (which doesn't have them). In general, avoid call chains when dealing with COM. It makes your code and documentation much easier to follow for those people who have used COM earlier and know the way it should function. Breaking the standard will cause profe

                    G Offline
                    G Offline
                    Geert van Horrik
                    wrote on last edited by
                    #9

                    Antti Keskinen wrote: Hope this helps And IF it is helpful! Thanks for all your time and effort! It really helped me a lot! I think I know the basics so I can start trying to develop my own object. Thanks! Geert http://geert.yoki.org

                    1 Reply Last reply
                    0
                    Reply
                    • Reply as topic
                    Log in to reply
                    • Oldest to Newest
                    • Newest to Oldest
                    • Most Votes


                    • Login

                    • Don't have an account? Register

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • World
                    • Users
                    • Groups