Hello, everyone,
I'm using xpcom/sample to experiment with xpcom. I added a simple class myEnumerator to nsSample. myEnumerator inherits nsISimpleEnumerator. In the WriteValue function of nsSample, I declared a pointer to myEnumerator.
When I compiled, I got
nsSample.o(.text+0x4f8): In function `nsSampleImpl::WriteValue(char const*)':
: undefined reference to `vtable for myEnumerator'


Could anyone tell me what I should do? I'm working on Redhat9 and I have little experience with programming on Linux.

Please take a look.
I attached nsSample.h and nsSample.cpp where I added myEnumerator.

Many thanks.

Adele
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Netscape Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/NPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is mozilla.org code.
 *
 * The Initial Developer of the Original Code is 
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1998
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Pierre Phaneuf <[EMAIL PROTECTED]>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or 
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the NPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the NPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */


/**
 *
 * A sample of XPConnect. This file contains an implementation nsSample
 * of the interface nsISample.
 *
 */
#include <stdio.h>

#include "nsSample.h"
#include "nsMemory.h"

#include "nsEmbedString.h"

NS_IMETHODIMP 
myEnumerator::HasMoreElements(PRBool* aResult) 
{ 
    if (!aResult) 
        return NS_ERROR_NULL_POINTER; 
 
    if (!mNode) { 
        *aResult = PR_FALSE; 
        return NS_OK; 
    } 
 
    *aResult = PR_TRUE; 
    return NS_OK; 
} 

NS_IMETHODIMP 
myEnumerator::GetNext(nsISupports** aResult) 
{ 
    if (! aResult) 
        return NS_ERROR_NULL_POINTER; 
 
    *aResult = nsnull; 
 
    if (!mNode) 
        return NS_ERROR_FAILURE; 
 
    if (!mCompMgr) { 
        NS_GetComponentManager(getter_AddRefs(mCompMgr)); 
        if (!mCompMgr)  
            return NS_ERROR_UNEXPECTED; 
    } 
 
    nsISupportsCString* stringSupports; 
    mCompMgr->CreateInstance(kSupportsCStringCID,  
                             nsnull,  
                             NS_GET_IID(nsISupportsCString),  
                             (void**)&stringSupports); 
    if (!stringSupports) 
        return NS_ERROR_UNEXPECTED; 
 
    nsEmbedCString str(mNode->urlString); 
    stringSupports->SetData(str); 

    *aResult = stringSupports; // addref'ed above. 
 
    mNode = mNode->next; 
 
    return NS_OK; 
} 

////////////////////////////////////////////////////////////////////////

nsSampleImpl::nsSampleImpl() : mValue(nsnull)
{
    mValue = (char*)nsMemory::Clone("initial value", 14);
}

nsSampleImpl::~nsSampleImpl()
{
    if (mValue)
        nsMemory::Free(mValue);
}

/**
 * NS_IMPL_ISUPPORTS1 expands to a simple implementation of the nsISupports
 * interface.  This includes a proper implementation of AddRef, Release,
 * and QueryInterface.  If this class supported more interfaces than just
 * nsISupports, 
 * you could use NS_IMPL_ADDREF() and NS_IMPL_RELEASE() to take care of the
 * simple stuff, but you would have to create QueryInterface on your own.
 * nsSampleFactory.cpp is an example of this approach.
 * Notice that the second parameter to the macro is name of the interface, and
 * NOT the #defined IID.
 *
 * The _CI variant adds support for nsIClassInfo, which permits introspection
 * and interface flattening.
 */
NS_IMPL_ISUPPORTS1_CI(nsSampleImpl, nsISample)

/**
 * Notice that in the protoype for this function, the NS_IMETHOD macro was
 * used to declare the return type.  For the implementation, the return
 * type is declared by NS_IMETHODIMP
 */
NS_IMETHODIMP
nsSampleImpl::GetValue(char** aValue)
{
    NS_PRECONDITION(aValue != nsnull, "null ptr");
    if (! aValue)
        return NS_ERROR_NULL_POINTER;

    if (mValue) {
        /**
         * GetValue's job is to return data known by an instance of
         * nsSampleImpl to the outside world.  If we  were to simply return 
         * a pointer to data owned by this instance, and the client were to
         * free it, bad things would surely follow.
         * On the other hand, if we create a new copy of the data for our
         * client, and it turns out that client is implemented in JavaScript,
         * there would be no way to free the buffer.  The solution to the 
         * buffer ownership problem is the nsMemory singleton.  Any buffer
         * returned by an XPCOM method should be allocated by the nsMemory.
         * This convention lets things like JavaScript reflection do their
         * job, and simplifies the way C++ clients deal with returned buffers.
         */
        *aValue = (char*) nsMemory::Clone(mValue, strlen(mValue) + 1);
        if (! *aValue)
            return NS_ERROR_NULL_POINTER;
    }
    else {
        *aValue = nsnull;
    }
    return NS_OK;
}

NS_IMETHODIMP
nsSampleImpl::SetValue(const char* aValue)
{
    NS_PRECONDITION(aValue != nsnull, "null ptr");
    if (! aValue)
        return NS_ERROR_NULL_POINTER;

    if (mValue) {
        nsMemory::Free(mValue);
    }

    /**
     * Another buffer passing convention is that buffers passed INTO your
     * object ARE NOT YOURS.  Keep your hands off them, unless they are
     * declared "inout".  If you want to keep the value for posterity,
     * you will have to make a copy of it.
     */
    mValue = (char*) nsMemory::Clone(aValue, strlen(aValue) + 1);
    return NS_OK;
}

NS_IMETHODIMP
nsSampleImpl::Poke(const char* aValue)
{
    return SetValue((char*) aValue);
}


static void GetStringValue(nsACString& aValue)
{
  aValue.Assign("GetValue");
}

NS_IMETHODIMP
nsSampleImpl::WriteValue(const char* aPrefix)
{
        urlNode* mRootURLNode;
        mRootURLNode->urlString = "www.sth.com";
        myEnumerator* enumerator = new myEnumerator(mRootURLNode); 
    if(!enumerator) return NS_ERROR_OUT_OF_MEMORY; 

    NS_PRECONDITION(aPrefix != nsnull, "null ptr");
    if (! aPrefix)
        return NS_ERROR_NULL_POINTER;

    printf("%s %s\n", aPrefix, mValue);

    // This next part illustrates the nsEmbedString:
    nsEmbedString foopy;
    foopy.Append(PRUnichar('f'));
    foopy.Append(PRUnichar('o'));
    foopy.Append(PRUnichar('o'));
    foopy.Append(PRUnichar('p'));
    foopy.Append(PRUnichar('y'));
    
    const PRUnichar* f = foopy.get();
    PRUint32 l = foopy.Length();
    printf("%c%c%c%c%c %d\n", char(f[0]), char(f[1]), char(f[2]), char(f[3]), 
char(f[4]), l);
    
    nsEmbedCString foopy2;
    GetStringValue(foopy2);

    //foopy2.Append(NS_LITERAL_CSTRING("foopy"));
    const char* f2 = foopy2.get();
    PRUint32 l2 = foopy2.Length();

    printf("%s %d\n", f2, l2);

    return NS_OK;
}
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Netscape Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/NPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is mozilla.org code.
 *
 * The Initial Developer of the Original Code is 
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1998
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or 
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the NPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the NPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

/**
 * A sample of XPConnect. This file is the header of an implementation
 * nsSample of the nsISample interface.
 *
 */

#include "nsISample.h"

#include "nsIGenericFactory.h"

#include "nsCOMPtr.h"
#include "nsXPCOM.h"
#include "nsIServiceManager.h"
#include "nsICategoryManager.h"
#include "nsIComponentManager.h"
#include "nsIObserver.h"
#include "nsXPCOMCID.h" 
#include "nsISupportsPrimitives.h"
//#include "nsIContentPolicy.h"                 // unfrozen component
//#include "nsIIOService.h"
//#include "nsIStreamListener.h"
//#include "nsIURI.h"
#include "nsISimpleEnumerator.h"

/**
 * SampleImpl is an implementation of the nsISample interface.  In XPCOM,
 * there can be more than one implementation of an given interface.  Class
 * IDs (CIDs) uniquely identify a particular implementation of an interface.
 * Interface IDs (IIDs) uniquely identify an interface.
 *
 * The CID is also a unique number that looks just like an IID
 * and uniquely identifies an implementation
 * {7CB5B7A0-07D7-11d3-BDE2-000064657374}
 */

#define NS_SAMPLE_CID \
{ 0x7cb5b7a0, 0x7d7, 0x11d3, { 0xbd, 0xe2, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }

#define NS_SAMPLE_CONTRACTID "@mozilla.org/sample;1"

static NS_DEFINE_CID(kSupportsCStringCID, NS_SUPPORTS_CSTRING_CID);
// a simple link list. 
struct urlNode 
{ 
    char* urlString; 
    struct urlNode* next; 
}; 

////////////////////// myEnumerator /////////////////////////
class myEnumerator : public nsISimpleEnumerator 
{ 
public: 
    NS_DECL_ISUPPORTS 
    NS_DECL_NSISIMPLEENUMERATOR 
 
    myEnumerator(urlNode* node) { mNode = node; } 
    ~myEnumerator(void) {} 
 
protected: 
    urlNode* mNode; 
    nsCOMPtr<nsIComponentManager> mCompMgr; 
}; 


class nsSampleImpl : public nsISample
{
public:
    nsSampleImpl();

    /**
     * This macro expands into a declaration of the nsISupports interface.
     * Every XPCOM component needs to implement nsISupports, as it acts
     * as the gateway to other interfaces this component implements.  You
     * could manually declare QueryInterface, AddRef, and Release instead
     * of using this macro, but why?
     */
    // nsISupports interface
    NS_DECL_ISUPPORTS

    /**
     * This macro is defined in the nsISample.h file, and is generated
     * automatically by the xpidl compiler.  It expands to
     * declarations of all of the methods required to implement the
     * interface.  xpidl will generate a NS_DECL_[INTERFACENAME] macro
     * for each interface that it processes.
     *
     * The methods of nsISample are discussed individually below, but
     * commented out (because this macro already defines them.)
     */
    NS_DECL_NSISAMPLE

    /**
     * The following is an explanation of how the interface header
     * file expands to for a c++ implementation. NS_DELC_NSISAMPLE
     * takes care of defining the right c++ implementation.
     *
     * The following if provided for more understanding.
     *
     * NS_IMETHOD expands to the standard XPCOM return type.  XPCOM methods
     * should never return any other type.  The return value is used
     * behind the scenes by the XPConnect runtime to figure out if the call
     * failed in any way.
     * These methods were generated by "attribute string Value" in 
     * nsISample.idl.  When reflected into JavaScript, XPCOM will use these
     * calls as Getter/Setter ops, so that they can be called transparently
     * as "sample.Value='foo';" and "var val = sample.Value"
     */
    /* NS_IMETHOD GetValue(char * *aValue); */
    /* NS_IMETHOD SetValue(char * aValue); */

    /**
     * The const came from the "in" specifier in nsISample.idl.  "in"
     * specifies that the value of this parameter is used only for input,
     * this method is not allowed to modify the contents of the buffer.
     */
    /* NS_IMETHOD WriteValue(const char *aPrefix); */

    /**
     * nsISample.idl specifies all of it's string types as string, instead
     * of wstring (wide string), the Unicode type.  If the world were a
     * perfect place, all normal strings in XPCOM interfaces would be unicode.
     * If this type had been specified as wstring, it would appear as
     * PRUnichar * in C++, which is the NSPR type for unicode characters.
     */
    /* NS_IMETHOD Poke(const char* aValue); */

private:
    ~nsSampleImpl();

    char* mValue;
};

Reply via email to