Solved

Create ActiveX DLL???

Posted on 2000-04-25
45
696 Views
Last Modified: 2013-12-14
Any true expert can teach me the steps to build an ActiveX DLL(COM Object) in VC++6.0 ??

I know how to create ActiveX Control(.ocx), but ActiveX DLL(.dll) is not the same thing.

I need to access the methods & properties defined in this ActiveX DLL from my form-less VB dll.

Thank you!
0
Comment
Question by:yu_zhang_denver
  • 24
  • 12
  • 8
  • +1
45 Comments
 
LVL 3

Expert Comment

by:mnewton022700
Comment Utility
Use the Microsoft App Wizard (dll) and specify support for automation.

This will give your project an odl file and allow your DLL to be registered when it is compiled.
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
I certainly know App Wizard(dll) has an "Automation" option and I did check that option.

Your answer is just too brief, it does not really help me. May you please explain in detail what I should do after that?

For example, in ClassWizard/automation, I should add a class to this project right? And then add property and methods?

And how to specify the ProgID?
Do I need to export any thing in .def file?

Thank you!

0
 

Author Comment

by:yu_zhang_denver
Comment Utility
I checked many books, they usually provide examples for ActiveX Control creation, but they all say "ActiveX DLL" is an advanced topic thus not covered.

I don't think it is very difficult to create an ActiveX DLL, I just need a simple example which guides me thru the steps.

I just cannot find any example in any book or MSDN library. MSDN does have detail help on how to create ActiveX DLL in VB, but not in VC++6.
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
What should I do to export class in ActiveX DLL?

I know how to create DLL's which exports functions.
0
 
LVL 3

Expert Comment

by:mnewton022700
Comment Utility
You didn't need to reject my answer in order to get more information.

Anyway, here's some more help for you:

* You don't need to put anything in the .def file.

* So that you can see the kind of code you will need:
   * Use the class wizard to create a new class which supports automation derived from CButton.
   * Use class wizard to add some methods and properties to the this class.

* From this you should be able to work out how to create your own classes.
0
 
LVL 3

Expert Comment

by:mnewton022700
Comment Utility
When you create a class using the class wizard it lets you specify the type ID that you can use to create it.

Let me know if you need more information.
0
 
LVL 3

Expert Comment

by:mnewton022700
Comment Utility
You should probably derive your classes from CCmdTarget actually. Making your own classes from scratch will require alot more work.
0
 
LVL 1

Expert Comment

by:sunj
Comment Utility
The recommended way to create an ActiveX control is through ATL because it's much lighter. And it's very easy too, through VC's ATL COM AppWizard. Follow the following procedures:

1. Crate a new project using ATL COM AppWizard. Make sure you check "Support MFC" if you want MFC support.

2. From menu "Insert", choose "New ATL Object...".

3. Choose "Simple Object".

4. In the C++ short name text field, type "MyATLObject", the rest of the field will be filled in automatically.

5. In the ClassView tree, right click on the interface IMyATLObject. You can add method or property from the context menu.

6. In the ClassView tree, expand CMyATLObject and IMyATLObject, you will see the list of methods and get/set methods for properties. Double click to add the methods.

7. Once you are done, build the project and it will register automatically, and is ready to be used in Visual Basic.

Hope it helps.
0
 
LVL 3

Expert Comment

by:GlennDean
Comment Utility
The only things I would add to suni's description, and suni is right - use ATL - is on Step I) of the ATL COM Wizard is you'll notice the options for Server Type.  It does default to DLL but atleast you'll know why you're getting a .dll file instead of a .exe file.
   I've never created ActiveX controls using VB, but when you create them via ATL and then use them in a VB form I've run into 2 problems that I'm sure is a result of me not knowing enough about VB internals, but they are
  1.  When the VC++ created ActiveX implements property pages, I can't get VB to show these pages at runtime (I've had to do hacks to get them to show up in VB at runtime)
  2.  Implementing control persistence just doesn't work as ATL advertises.  When you test your control in the VC++ Control Container, your ActiveX's properties do persist from one session to the next.  BUT, in VB, they don't seem to.
   Glenn
0
 
LVL 3

Expert Comment

by:GlennDean
Comment Utility
Oh, one other thing yu that you may not be famaliar with coming from a VB environment.  VB has complete control over the controls GUIDs via the Project/Binary Compatibility options.  BUT, in ATL, you have all the control.  ATL generates default IID/CLSIDs, but you can leave them as they are or change them whenever you want.
   Glenn
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
Thank you guys for the help.

To mnewton:

Sorry that I rejected your answer, I am new at this stuff so did not know the rule.

So if you do not export anything in .def, how can the class be exposed to other application? Also what's the difference between CButton and CCmdTarget? It looks like CCmdTarget is the right one, but i am not sure.
I fully understand how ActiveX Control is built, I just have no idea how ActiveX DLL is built, i somehow need to know the mechanism. Thank you!

To sunj and GlennDean:

Seem you two were talking about ActiveX Control, again, I know how to build ActiveX Control, what I need to know is how to build ActiveX DLL, these are two different concept. Thanks!
0
 
LVL 3

Expert Comment

by:GlennDean
Comment Utility
We were talking about an ActiveX DLL.  The finish product IS a .DLL file (it just so happens that the component in the .dll is what's considered an ActiveX control, but it need not be via ATL COM wizard).
   Glenn
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
To mnewton:

When I created ActiveX Control(OCX), the wizard creates a "shell", then I used ClassWizard to add a class which supports automation, i remember the shell is the interface thru which other application access the inner class, thus i added properties & methods to the "shell" which access the inner class' properties & methods, other applications call the shell's methods not the inner class' methods.

So should I do the same thing for ActiveX DLL?

Btw, how to award you points?
Thanks alot man!
0
 
LVL 3

Expert Comment

by:GlennDean
Comment Utility
You can click on the "Accept Comment As Answer" button to the right of any of mnewton's comments.
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
to mnewton:

yes i added typeID, but i am curious in which file and which line in the file will this ID be?

thanks!
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
to mnewton:

after i added a class derived from CCmdTarget, then i added properties and methods to this class, however it gave me error when it was updating the .h and .cpp files for that class.

headache... maybe i should try to use CButton instead..
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
ok i tried to use CButton as well, and it gave me same error while updating .h and .cpp for that new class i added..
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
Sunj and Glenn,

I am trying to use you guys' way to create ActiveX DLL.

Can you tell me where I can specify the ProgID, VB application needs to know ProgID of this DLL in order to call it, right?

thanks
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
to Glenn,

Btw, my VB application which will call my ActiveX DLL is a formless one, there is no form, just code. If it has forms, I can just make an ActiveX Control in VC++6, since it is form-less, i have to create it as ActiveX DLL instead of Control.

thanks

0
 

Author Comment

by:yu_zhang_denver
Comment Utility
Adjusted points from 200 to 250
0
 
LVL 3

Expert Comment

by:GlennDean
Comment Utility
>Can you tell me where I can specify >the ProgID, VB application needs to >know ProgID of this DLL in order to >call it, right?
   Yes and no.  If you use CreateObject then you do need the ProgID.  When you create an ActiveX DLL via ATL, ALL will give the object a default ProgID, which you can feel free to change.  When you add an object to your ATL project, there are two ways to record the ProgID.  First, when you insert the object into your project, when you enter a name for the object, just record the ProgID box that ATL fills in for you.  OR, go to the .IDL file in the Sources Folder and look the library statement.  You'll see a coclass section and the GUID in the header which precedes the coclass is your ProgID.  
   OTOH, if you just add a reference to the object in VB then you can create the object via the normal
 Dim myObject As New ....
line.

    Glenn
   

0
 

Author Comment

by:yu_zhang_denver
Comment Utility
Thanks Glenn,

I added methods to IMyATLObject, say it's called download(CString server, CString login, CString passwd, CString filename)

Then I tried to build this project, it gave me error says it expects data type near CString.

When i created this ATL COM i did check the box which says "supports MFC" so it should support CString data type, right?

What is wrong.

This thing is sorta headache...
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 3

Accepted Solution

by:
mnewton022700 earned 250 total points
Comment Utility
I haven't used ATL before so I can't comment on whether it would be better for you to use it. However the little I do know points to the fact that MFC is much easier to use.

Anyway, what was the error you were getting when you tried to add methods and properties?

Try creating a new DLL, add a class derived from CCmdTarget (which supports automation) and give it some ActiveX methods and properties. It should compile without any problems. The typeID will be in cpp file. Now try creating this object in VB.

ps.
You can't use CString as a parameter to ActiveX methods, you need to use BSTR instead.
0
 
LVL 3

Expert Comment

by:GlennDean
Comment Utility
When you check "Support MFC" that basically means you can use MFC for your code, BUT you must still "obey" the rules of COM and use types which are indigenous to COM.  As mnewton mentioned, you must use BSTR instead.  ATL has a class called CComBSTR and a constructor that takes a CString and converts it to CComBSTR.
  Glenn
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
Hey guys,

you are all great, is there any way I can dive this 250 points and give each of you 1/3 of the points?

Glenn and Newton, guess ya have been a geek working in computer industry for ages? ;-)

thanks again!
P.S.
If i can't divide the point, i will just give it to newton since he answered my question first, is this okay with Glenn and the other gentleman?
0
 
LVL 3

Expert Comment

by:mnewton022700
Comment Utility
If you decided to use ATL then I am quite happy for you to give the points to Glenn and/or sunj.

I'm not sure how to give points to more than one person. I don't think there is any easy way to do it. My guess is that you need to create bogus questions that are just meant to give out points to particular people. (I actually think that EE needs a good way of doing this because it something that people often want to do.)
0
 
LVL 3

Expert Comment

by:GlennDean
Comment Utility
Yep, EE remains firm on one person getting the points.  
   You're very gracious mnewton to suggest if ATL is the way yu goes then to award somebody else the points.  
   Yu, if you decided to go the MFC route then give mnewton the points.  Also Yu, thanxs for the compliment above.  I wish I could say I was a stud in programming and had been in the industry for decades, but nope.  I'm still a student and work hard to learn more and more each day.  
    Happy programming trails everyone,
        Glenn
         
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
Hello Newton,

I decided to use your way, so I will give you points.

Just one more thing, in the class I added, i added a method called "fileGet()" to this class, in this method I declared:
  CFtpConnection* Ftp_ptr;

I #include <afxinet.h> at the begining of this .cpp file, but when i build it,
it says:
   error C2065: 'CFtpConnection' : undeclared identifier

So I can't use MFC class in this piece of code? But my goal is to set up an FTP connection and download a file from a remote FTP server.

May you pls tell me what's the problem?
Millions of Thanks !!!
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
Hello Newton,

I decided to use your way, so I will give you points.

Just one more thing, in the class I added, i added a method called "fileGet()" to this class, in this method I declared:
  CFtpConnection* Ftp_ptr;

I #include <afxinet.h> at the begining of this .cpp file, but when i build it,
it says:
   error C2065: 'CFtpConnection' : undeclared identifier

So I can't use MFC class in this piece of code? But my goal is to set up an FTP connection and download a file from a remote FTP server.

May you pls tell me what's the problem?
Millions of Thanks !!!
0
 
LVL 3

Expert Comment

by:mnewton022700
Comment Utility
I had no trouble adding the code you mentioned to a method of my own. I didn't get a compile error. However, if you show me your entire method and which line the error occurs on I might be able to see what is wrong.
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
Hello Newton,

I decided to use your way, so I will give you points.

Just one more thing, in the class I added, i added a method called "fileGet()" to this class, in this method I declared:
  CFtpConnection* Ftp_ptr;

I #include <afxinet.h> at the begining of this .cpp file, but when i build it,
it says:
   error C2065: 'CFtpConnection' : undeclared identifier

So I can't use MFC class in this piece of code? But my goal is to set up an FTP connection and download a file from a remote FTP server.

May you pls tell me what's the problem?
Millions of Thanks !!!
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
Okay here is the code:

// Download.cpp : implementation file
//

#include <stdlib.h>
#include <afx.h>
#include <afxinet.h>
#include <stdio.h>
#include <conio.h>
#include <process.h>
#include <time.h>

#include "stdafx.h"
#include "ftpnpgp.h"
#include "Download.h"

#define MAX 255

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CDownload

IMPLEMENT_DYNCREATE(CDownload, CCmdTarget)

CDownload::CDownload()
{
      EnableAutomation();
      
      // To keep the application running as long as an OLE automation
      //      object is active, the constructor calls AfxOleLockApp.
      
      AfxOleLockApp();
}

CDownload::~CDownload()
{
      // To terminate the application when all objects created with
      //       with OLE automation, the destructor calls AfxOleUnlockApp.
      
      AfxOleUnlockApp();
}


void CDownload::OnFinalRelease()
{
      // When the last reference for an automation object is released
      // OnFinalRelease is called.  The base class will automatically
      // deletes the object.  Add additional cleanup required for your
      // object before calling the base class.

      CCmdTarget::OnFinalRelease();
}


BEGIN_MESSAGE_MAP(CDownload, CCmdTarget)
      //{{AFX_MSG_MAP(CDownload)
            // NOTE - the ClassWizard will add and remove mapping macros here.
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()

BEGIN_DISPATCH_MAP(CDownload, CCmdTarget)
      //{{AFX_DISPATCH_MAP(CDownload)
      DISP_PROPERTY_NOTIFY(CDownload, "errReason", m_errReason, OnErrReasonChanged, VT_BSTR)
      DISP_PROPERTY_NOTIFY(CDownload, "fileName", m_fileName, OnFileNameChanged, VT_BSTR)
      DISP_PROPERTY_NOTIFY(CDownload, "count", m_count, OnCountChanged, VT_I2)
      DISP_FUNCTION(CDownload, "fileGet", fileGet, VT_EMPTY, VTS_BSTR VTS_BSTR VTS_BSTR VTS_BSTR VTS_BSTR VTS_BSTR VTS_BSTR VTS_BSTR VTS_I2 VTS_BSTR)
      DISP_FUNCTION(CDownload, "getCount", getCount, VT_I2, VTS_NONE)
      DISP_FUNCTION(CDownload, "setCount", setCount, VT_EMPTY, VTS_I2)
      //}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()

// Note: we add support for IID_IDownload to support typesafe binding
//  from VBA.  This IID must match the GUID that is attached to the
//  dispinterface in the .ODL file.

// {39E98881-1BD6-11D4-B053-00C04F01C12E}
static const IID IID_IDownload =
{ 0x39e98881, 0x1bd6, 0x11d4, { 0xb0, 0x53, 0x0, 0xc0, 0x4f, 0x1, 0xc1, 0x2e } };

BEGIN_INTERFACE_MAP(CDownload, CCmdTarget)
      INTERFACE_PART(CDownload, IID_IDownload, Dispatch)
END_INTERFACE_MAP()

// {39E98882-1BD6-11D4-B053-00C04F01C12E}
IMPLEMENT_OLECREATE(CDownload, "ftpnpgp.Download", 0x39e98882, 0x1bd6, 0x11d4, 0xb0, 0x53, 0x0, 0xc0, 0x4f, 0x1, 0xc1, 0x2e)

/////////////////////////////////////////////////////////////////////////////
// CDownload message handlers

void CDownload::OnErrReasonChanged()
{
      // TODO: Add notification handler code

}

void CDownload::OnFileNameChanged()
{
      // TODO: Add notification handler code

}

void CDownload::OnCountChanged()
{
      // TODO: Add notification handler code

}

void
CDownload::fileGet(
                                     LPCTSTR server,                // FTP server name
                                     LPCTSTR login,              
                                     LPCTSTR passwd,                // password
                                     LPCTSTR remote_dir,            // remote directory
                                     LPCTSTR remote_file,           // remote file name
                                     LPCTSTR inner_file,            // inner file name
                                     LPCTSTR local_dir,             // local directory
                                     LPCTSTR local_file,            // local file name
                                     short file_type,               // file type:
                                                                    //   0: plain text
                                                                                               //   1: PGP
                                                                                               //   2: Compressed
                                                                                               //   3: PGP & Compressed
                                     LPCTSTR compress_passwd){      // password used in compression
      try{
            CFtpConnection* Ftp_ptr;                                        // pointer to FTP connection
            int i;                                      // loop counters
            int ftp_success;                            // 1: success 0: failure
            CString pgp = "c:\\progra~1\\networ~1\\pgpnt\\pgp.exe";   // path of pgp.exe
            int nPort = 21;                             // FTP port number (default is 21)
            time_t rest = 120;                          // break time before next try
            int n_try = 15;                             // try at most n_try times
            time_t previous, now;                       // time


            CInternetSession connection("ftpnpgp.dll", // create an internet session
                                                      1,
                                 INTERNET_OPEN_TYPE_PRECONFIG,
                                                            NULL,
                                                                                    NULL,
                                                                                       0);
            ftp_success = 0;
            for(i=0;i<n_try;++i){
                  time(&previous);
                  try{
                        Ftp_ptr = connection.GetFtpConnection(
                                                                                      server,
                                                                     login,
                                                                             passwd,
                                                                                 nPort,
                                                                                           1);
                        ftp_success = 1;
                        break;
                  }catch(...){             //CInternetException E)
                        printf("Trying to connect to %s....%d\n", server, i);
                        for(;;){
                              time(&now);
                              if((now-previous) > rest)
                                    break;
                        }
                  }
            }

            if(!ftp_success)
                  goto TERMINATE;

            if(!Ftp_ptr->SetCurrentDirectory(remote_dir))  // True if success
                  goto TERMINATE;

            if(!Ftp_ptr->GetFile(remote_file,          // True if success
                            local_file,
                                     0,
                                     FILE_ATTRIBUTE_NORMAL,
                                     FTP_TRANSFER_TYPE_BINARY,
                                     1)){
                  goto TERMINATE;
            }


            if(file_type)                                             // decrypt PGP file
                  _execl((LPCTSTR)pgp, (LPCTSTR)pgp, local_file, NULL);

      TERMINATE:
            if(ftp_success)
                  Ftp_ptr->Close();
            connection.Close();
            return;
      }
   catch(...){   // CException E){
            //E.GetErrorMessage(ErrMsg, MAX, NULL);
            //E.Delete();
            return;
      }
}


short CDownload::getCount()
{
      // TODO: Add your dispatch handler code here
      return m_count;
}

void CDownload::setCount(short number)
{
      // TODO: Add your dispatch handler code here
      m_count = number;
      return;
}
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
the code is not well formatted here, but the error occurs in the line:
   CFtpConnection* Ftp_ptr;      
in function:
   void CDownload::fileGet( )


thanks
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
seems it cannot recognize CFtpConnection, but i did include the correct .h file
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
btw, after i award you points, this question will be locked, right?
0
 
LVL 3

Expert Comment

by:mnewton022700
Comment Utility
Make sure the "stdafx.h" is first file included.

ie. Change:

#include <stdlib.h>
#include <afx.h>
#include <afxinet.h>
#include <stdio.h>
#include <conio.h>
#include <process.h>
#include <time.h>

#include "stdafx.h"
#include "ftpnpgp.h"
#include "Download.h"

To:

#include "stdafx.h"
#include "ftpnpgp.h"
#include "Download.h"

#include <stdlib.h>
#include <afx.h>
#include <afxinet.h>
#include <stdio.h>
#include <conio.h>
#include <process.h>
#include <time.h>

0
 
LVL 3

Expert Comment

by:mnewton022700
Comment Utility
After you accept one of my comments as an answer this question will be moved to the Answered section. We can still add comments to it though.
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
so why must i move "stdafx.h" to the front?
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
Newton,

Thanks for your help and here is your 250 points.

I just feel it's strange that there is no documentation about how to create ActiveX DLL in those books or MSDN.
They usually all talk about ActiveX Control tho'

This stuff is not hard at all, but it just frustrates me when there is no simple example available to illustrate these simple steps.

Thanks again!
0
 
LVL 3

Expert Comment

by:mnewton022700
Comment Utility
Something to do with precompiled headers. I don't understand it fully, but basically the header file that the precomiled header is built through must always be included first.
0
 
LVL 3

Expert Comment

by:mnewton022700
Comment Utility
Yeah, MSDN is great, but it certainly does get on my nerves sometimes :)

Thanks,
Mike.
0
 
LVL 3

Expert Comment

by:GlennDean
Comment Utility
Yeah, MSDN can really get to anyone.  You have this incredibly complex function and about 5 or 6 lines of explanation on how to use it!
 
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
btw, newton and Glenn,

i finished my DLL using VC++ and my VB application can call it.

There is only one problem, in my DLL i used _spawnl() to execute pgp.exe,
but each time pgp.exe runs, it brings the VB program down, i mean pgp.exe does execute and it works well, but after it's executed it terminates the VB program.

Do I have to use something like wait(), signal()..etc

Could you pls show me just a simple example? Thanks man!
0
 
LVL 3

Expert Comment

by:mnewton022700
Comment Utility
What mode are you using for the spawn method? It sounds like you are using _P_OVERLAY.

You should use _P_WAIT or _P_NOWAIT.
0
 

Author Comment

by:yu_zhang_denver
Comment Utility
in sunj's suggestion, what does he mean by "it's much lighter"???

So if I use MFC AppWizard(dll) to create my ActiveX DLL, it will be "heavier"?


thanx again,
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

Suggested Solutions

Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The viewer will learn how to use and create keystrokes in Netbeans IDE 8.0 for Windows.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now