Search code examples
c++windowsdllheader-filesdllexport

Building a DLL with VC++ function is inaccessible


Today I needed a small library to recursively list all the files in a folder and all the subfolders. So I decided to create a small library, it is very simple and only contains two functions:

bool __cdecl isDir(std::string dir);
void __cdecl listDir(std::string dir, std::vector<std::string> &files, bool recursive);

The function of these are quiet self explanatory.

It contains one header file which defines a class FR and I export that using

__declspec( dllexport )

The reason for me bothering to do this small library is that it can be used in future projects without having to incorporate the source files into my projects all the time.

This is how I try to call one of the functions:

FR *clazz = new FR();
clazz->isDir("C:/path/to/dir");

And this is the error generated:
IntelliSense: function "FR::isDir" (declared at line 11 of "C:\dev\FileRecursionDLL\inc\fr.h") is inaccessible

[fr.cpp]

#include "fr.h"

using namespace std;

BOOL APIENTRY DllMain(HANDLE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved)
{
    return TRUE;
}

DllExport bool __cdecl FR::isDir(string dir){
    struct stat fileInfo;
    stat(dir.c_str(), &fileInfo);
    if (S_ISDIR(fileInfo.st_mode)){
        return true;
    }
    else{
        return false;
    }
}

DllExport void __cdecl FR::listDir(string dir, vector<string> &files, bool recursive){
    DIR *dp; //create the directory object
    struct dirent *entry; //create the entry structure
    dp = opendir(dir.c_str()); //open directory by converting the string to const char*
    if (dir.at(dir.length() - 1) != '/'){
        dir = dir + "/";
    }
    if (dp != NULL){ //if the directory isn't empty
        while (entry = readdir(dp)){ //while there is something in the directory
            if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0){ //and if the entry isn't "." or ".."
                if (isDir(dir + entry->d_name) == true && recursive == true){//check if the new path is a directory, and if it is (and recursion is specified as true), recurse.
                    files.push_back(string(entry->d_name)); //add entry to the list of files
                    listDir(dir + entry->d_name, files, true); //recurse
                }
                else{
                    files.push_back(string(entry->d_name));//add the entry to the list of files
                }
            }
        }
        (void)closedir(dp); //close directory
    }
    else{
        perror("Couldn't open the directory.");
    }
}

[fr.h]

#ifndef FR_H
#define FR_H

#define DllExport   __declspec( dllexport ) 

#include<dirent.h>
#include<vector>

class DllExport FR
{
    bool __cdecl isDir(std::string dir);
    void __cdecl listDir(std::string dir, std::vector<std::string> &files, bool recursive);
};
#endif

NOTE: A reference to a library already doing this would also be appreciated!

Thanks in advance!


Solution

  • class members are private by default, struct members are public by default.


    That said, why not do a general and simple to create and use header-only module instead of adding the complexity of a compiler-specific DLL.

    Also, for Windows programming better use wide character strings (i.e. Unicode).


    Example:

    #pragma once
    // Copyright (c) 2014 Alf P. Steinbach
    
    #undef UNICODE
    #define UNICODE
    #include <windows.h>
    
    #include <string>           // std::wstring
    #include <vector>           // std::vector
    
    namespace filesystem{
        using std::wstring;
        using std::vector;
    
        inline
        auto path_join( wstring const& a, wstring const& b )
            -> wstring
        {
            int const len_a = a.length();
            int const len_b = b.length();
    
            if( len_a == 0 ) { return b; }
            if( len_b == 0 ) { return a; }
    
            wstring result = a;
            if( a[len_a - 1] == L'\\' )
            {
                if( b[0] == L'\\' ) { result.resize( len_a - 1 ); }
            }
            else if( b[0] != L'\\' )
            {
                result += L'\\';
            }
            result += b;
            return result;
        }
    
    
        enum Recursion { no_recursion, recursive };
    
        inline
        auto directory_entries( wstring const& directory_path, Recursion const r = no_recursion )
            -> vector<wstring>
        {
            vector<wstring> result;
            WIN32_FIND_DATA state = {};
            HANDLE const h = FindFirstFile( path_join( directory_path, L"*.*" ).c_str(), &state );
            for(
                bool more = (h != INVALID_HANDLE_VALUE);
                more;
                more = !!FindNextFile( h, &state )
                )
            {
                result.push_back( state.cFileName );
                if( r == recursive && !!(state.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
                {
                    // TODO: Check that this isn't a "." or ".." or (hard problem) circular symlink entry.
                    bool const is_true_subdirectory = false;        // <-- Here.
                    if( is_true_subdirectory )
                    {
                        auto const sub_entries = directory_entries(
                            path_join( directory_path, state.cFileName ), recursive
                            );
                        for( auto const& e : sub_entries )
                        {
                            result.push_back( e );
                        }
                    }
                }
            }
            FindClose( h );
            return result;
        }
    
    }  // namespace filesystem