[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 733
  • Last Modified:

Create ActiveX DLL???

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
yu_zhang_denver
Asked:
yu_zhang_denver
  • 24
  • 12
  • 8
  • +1
1 Solution
 
mnewton022700Commented:
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
 
yu_zhang_denverAuthor Commented:
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
 
yu_zhang_denverAuthor Commented:
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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
yu_zhang_denverAuthor Commented:
What should I do to export class in ActiveX DLL?

I know how to create DLL's which exports functions.
0
 
mnewton022700Commented:
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
 
mnewton022700Commented:
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
 
mnewton022700Commented:
You should probably derive your classes from CCmdTarget actually. Making your own classes from scratch will require alot more work.
0
 
sunjCommented:
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
 
GlennDeanCommented:
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
 
GlennDeanCommented:
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
 
yu_zhang_denverAuthor Commented:
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
 
GlennDeanCommented:
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
 
yu_zhang_denverAuthor Commented:
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
 
GlennDeanCommented:
You can click on the "Accept Comment As Answer" button to the right of any of mnewton's comments.
0
 
yu_zhang_denverAuthor Commented:
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
 
yu_zhang_denverAuthor Commented:
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
 
yu_zhang_denverAuthor Commented:
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
 
yu_zhang_denverAuthor Commented:
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
 
yu_zhang_denverAuthor Commented:
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
 
yu_zhang_denverAuthor Commented:
Adjusted points from 200 to 250
0
 
GlennDeanCommented:
>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
 
yu_zhang_denverAuthor Commented:
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
 
mnewton022700Commented:
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
 
GlennDeanCommented:
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
 
yu_zhang_denverAuthor Commented:
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
 
mnewton022700Commented:
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
 
GlennDeanCommented:
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
 
yu_zhang_denverAuthor Commented:
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
 
yu_zhang_denverAuthor Commented:
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
 
mnewton022700Commented:
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
 
yu_zhang_denverAuthor Commented:
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
 
yu_zhang_denverAuthor Commented:
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
 
yu_zhang_denverAuthor Commented:
the code is not well formatted here, but the error occurs in the line:
   CFtpConnection* Ftp_ptr;      
in function:
   void CDownload::fileGet( )


thanks
0
 
yu_zhang_denverAuthor Commented:
seems it cannot recognize CFtpConnection, but i did include the correct .h file
0
 
yu_zhang_denverAuthor Commented:
btw, after i award you points, this question will be locked, right?
0
 
mnewton022700Commented:
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
 
mnewton022700Commented:
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
 
yu_zhang_denverAuthor Commented:
so why must i move "stdafx.h" to the front?
0
 
yu_zhang_denverAuthor Commented:
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
 
mnewton022700Commented:
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
 
mnewton022700Commented:
Yeah, MSDN is great, but it certainly does get on my nerves sometimes :)

Thanks,
Mike.
0
 
GlennDeanCommented:
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
 
yu_zhang_denverAuthor Commented:
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
 
mnewton022700Commented:
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
 
yu_zhang_denverAuthor Commented:
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

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 24
  • 12
  • 8
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now