Sign in to follow this  
byte

Dynamically Load Dll Functions from Text File Info

Recommended Posts

Hi,

here is how to load functions from dll using a text file to tell your application the name of the function and .dll file to use at runtime :

Application : 

Main.Cpp

#include <windows.h>
#include <atlstr.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <filesystem>
#include <conio.h>
#include <string>
#include <iostream>
#include <clocale>
#include <locale>
#include <vector>
#pragma once
#ifdef UNICODE //Test to see if we're using wchar_ts or not.
typedef std::wstring StringType;
#else
typedef std::string StringType;
#endif
//
///////////////////////////
///////////////////////////
//
//start of struct definitions//
//
///////////////////////////
///////////////////////////
//
//the parameter struct that is both input and output from our function
extern "C" struct DllFunctionParams
{
	std::vector<bool>vectorofbools;
	std::vector<int>vectorofints;
	std::vector<double>vectorofdoubles;
	std::vector<HWND>vectorofhwnds;
	std::vector<CString>vectorofcstrings;
};
//our function definition
extern "C"
{
	typedef DllFunctionParams(*f_funci)(DllFunctionParams&);
}
//the parameter struct that holds the data about our current dll function
extern "C" struct DllFunction
{
	StringType DllName;
	StringType DllFunctionName;
	int Priority;
	f_funci function;
};
//
///////////////////////////
///////////////////////////
//
//start of struct definitions//
//
///////////////////////////
///////////////////////////
//

//
///////////////////////////
///////////////////////////
//
//start of string functions namespace//
//
///////////////////////////
///////////////////////////
//
namespace StringManipulation
{
	StringType pathAppend(const StringType & p1, const StringType & p2);
	std::string wstrtostr(const std::wstring & wstr);
	double StringToDouble(StringType input);
	int StringToInt(StringType input);
	StringType GetExtension(StringType filename);
	StringType GetBaseFilename(StringType filename);
	StringType GetCurrentPath();
	std::vector<StringType> GetListOfFiles(StringType path);
	bool PathExists(const StringType & s);
	inline bool FileExists(const StringType & name);
	std::vector<StringType> GetLinesFromFile(StringType filename);
	std::vector<StringType> split(StringType stringToBeSplitted, StringType delimeter);
}
//
///////////////////////////
///////////////////////////
//
//end of string functions namespace//
//
///////////////////////////
///////////////////////////
//

//
///////////////////////////
///////////////////////////
//
//start of string functions//
//
///////////////////////////
///////////////////////////
//
StringType StringManipulation::pathAppend(const StringType& p1, const StringType& p2) {

	char sep = '/';
	StringType tmp = p1;

#ifdef _WIN32
	sep = '\\';
#endif

	if (p1[p1.length()] != sep) { // Need to add a
		tmp += sep;                // path separator
		return(tmp + p2);
	}
	else
		return(p1 + p2);
}
std::string StringManipulation::wstrtostr(const std::wstring &wstr)
{
	std::string strTo;
	char *szTo = new char[wstr.length() + 1];
	szTo[wstr.size()] = '\0';
	WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, szTo, (int)wstr.length(), NULL, NULL);
	strTo = szTo;
	delete[] szTo;
	return strTo;
}
double StringManipulation::StringToDouble(StringType input)
{
	CString c_str = input.c_str();
	// Convert a TCHAR string to a LPCSTR
	CT2CA pszConvertedAnsiString(c_str);
	// construct a std::string using the LPCSTR input
	std::string strStd(pszConvertedAnsiString);
	return atof(strStd.c_str()); /*c_str is needed to convert string to const char*/
}
int StringManipulation::StringToInt(StringType input)
{
	CString c_str = input.c_str();
	// Convert a TCHAR string to a LPCSTR
	CT2CA pszConvertedAnsiString(c_str);
	// construct a std::string using the LPCSTR input
	std::string strStd(pszConvertedAnsiString);
	return atoi(strStd.c_str()); /*c_str is needed to convert string to const char*/
}

StringType StringManipulation::GetExtension(StringType filename)
{
	//store the position of last '.' in the file name
	int position = filename.find_last_of(_T("."));

	//store the characters after the '.' from the file_name string
	StringType result = filename.substr(position + 1);

	//print the result
	return result;
}
StringType StringManipulation::GetBaseFilename(StringType filename)
{
	size_t pos = filename.rfind(_T("."));
	if (pos == StringType::npos)  //No extension.
		return filename;

	if (pos == 0)    //. is at the front. Not an extension.
		return filename;

	return filename.substr(0, pos);
}
StringType StringManipulation::GetCurrentPath()
{
#ifdef UNICODE //Test to see if we're using wchar_ts or not.
	wchar_t buffer[MAX_PATH];
#else
	char buffer[MAX_PATH];
#endif
	GetModuleFileName(NULL, buffer, MAX_PATH);
	StringType::size_type pos = StringType(buffer).find_last_of(_T("\\/"));
	return StringType(buffer).substr(0, pos);
}
std::vector<StringType> StringManipulation::GetListOfFiles(StringType path)
{
	std::vector<StringType>stringvector;
	WIN32_FIND_DATA fileData;
	memset(&fileData, 0, sizeof(WIN32_FIND_DATA));
	CString string;
	string.Format(_T("%s\\*"), path.c_str());
	HANDLE handle = FindFirstFile(string, &fileData);

	if (handle != INVALID_HANDLE_VALUE)
	{
		do
		{
			if (_tcscmp(fileData.cFileName, _T(".")) != 0 && // ignore "." and ".."
				_tcscmp(fileData.cFileName, _T("..")) != 0)
			{
				stringvector.push_back(fileData.cFileName);
			}
		} while (FindNextFile(handle, &fileData));

		FindClose(handle);
	}

	return stringvector;
}
bool StringManipulation::PathExists(const StringType &s)
{
	struct stat buffer;

	CString c_str = s.c_str();
	// Convert a TCHAR string to a LPCSTR
	CT2CA pszConvertedAnsiString(c_str);
	// construct a std::string using the LPCSTR input
	std::string strStd(pszConvertedAnsiString);
	return (stat(strStd.c_str(), &buffer) == 0);
}
inline bool StringManipulation::FileExists(const StringType& name)
{
	CString c_str = name.c_str();
	// Convert a TCHAR string to a LPCSTR
	CT2CA pszConvertedAnsiString(c_str);
	// construct a std::string using the LPCSTR input
	std::string strStd(pszConvertedAnsiString);
	struct stat buffer;
	return (stat(strStd.c_str(), &buffer) == 0);
}
std::vector<StringType> StringManipulation::GetLinesFromFile(StringType filename)
{

	auto count = 0;
	std::vector<StringType> stringvector;
	if (FileExists(filename))
	{
		std::ifstream file(filename);
		std::string str;
		while (std::getline(file, str))
		{
			CString c_str = str.c_str();
			StringType stringtype(c_str);
			stringvector.push_back(stringtype);
			count++;
			// Process str
		}
	}
	return count > 0 ? stringvector : std::vector<StringType>(0);
}


std::vector<StringType> StringManipulation::split(StringType stringToBeSplitted, StringType delimeter)
{
	std::vector<StringType> splittedString;
	int startIndex = 0;
	int  endIndex = 0;
	while ((endIndex = stringToBeSplitted.find(delimeter, startIndex)) < stringToBeSplitted.size())
	{

		StringType val = stringToBeSplitted.substr(startIndex, endIndex - startIndex);
		splittedString.push_back(val);
		startIndex = endIndex + delimeter.size();

	}
	if (startIndex < stringToBeSplitted.size())
	{
		StringType val = stringToBeSplitted.substr(startIndex);
		splittedString.push_back(val);
	}
	return splittedString;

}
//
///////////////////////////
///////////////////////////
//
//end of string functions//
//
///////////////////////////
///////////////////////////
//
//
///////////////////////////
///////////////////////////
//
//start of GetProcAddress header//
//
///////////////////////////
///////////////////////////
//
bool GetProcAddresses(HINSTANCE * hLibrary,
#ifdef UNICODE //Test to see if we're using wchar_ts or not.
	LPCWSTR lpszLibrary, INT nCount, ...);
#else

LPCSTR lpszLibrary, INT nCount, ...);
#endif
//
///////////////////////////
///////////////////////////
//
//end of GetProcAddress header//
//
///////////////////////////
///////////////////////////
//
//
///////////////////////////
///////////////////////////
//
//start of GetProcAddress function//
//
///////////////////////////
///////////////////////////
//
//GetProcAddresses
//Argument1: hLibrary - Handle for the Library Loaded
//Argument2: lpszLibrary - Library to Load
//Argument3: nCount - Number of functions to load
//[Arguments Format]
//Argument4: Function Address - Function address we want to store
//Argument5: Function Name -  Name of the function we want
//[Repeat Format]
//
//Returns: FALSE if failure
//Returns: TRUE if successful
bool GetProcAddresses(HINSTANCE *hLibrary,
#ifdef UNICODE //Test to see if we're using wchar_ts or not.
	LPCWSTR lpszLibrary, INT nCount, ...)
#else

LPCSTR lpszLibrary, INT nCount, ...)
#endif
{
	va_list va;
	va_start(va, nCount);

	if ((*hLibrary = LoadLibrary(lpszLibrary))
		!= NULL)
	{
		FARPROC * lpfProcFunction = NULL;
#ifdef UNICODE //Test to see if we're using wchar_ts or not.
		LPCWSTR lpszFuncName = NULL;
#else
		LPSTR lpszFuncName = NULL;
#endif
		INT nIdxCount = 0;
		while (nIdxCount < nCount)
		{
			lpfProcFunction = va_arg(va, FARPROC*);
#ifdef UNICODE //Test to see if we're using wchar_ts or not.
			lpszFuncName = va_arg(va, LPCWSTR);
			auto string = StringManipulation::wstrtostr(lpszFuncName);
#else
			lpszFuncName = va_arg(va, LPSTR);
			StringType string(lpszFuncName);
#endif
			if ((*lpfProcFunction =
				GetProcAddress(*hLibrary,
					string.c_str())) == NULL)
			{
				lpfProcFunction = NULL;
				return FALSE;
			}
			nIdxCount++;
		}
	}
	else
	{
		va_end(va);
		return FALSE;
	}
	va_end(va);
	return TRUE;
}
//
///////////////////////////
///////////////////////////
//
//end of GetProcAddress function//
//
///////////////////////////
///////////////////////////
//
//
///////////////////////////
///////////////////////////
//
//start of CompareByPriority header//
//
///////////////////////////
///////////////////////////
//
bool CompareByPriority(const DllFunction & a, const DllFunction & b);
//
///////////////////////////
///////////////////////////
//
//end of CompareByPriority header//
//
///////////////////////////
///////////////////////////
//

//
///////////////////////////
///////////////////////////
//
//start of CompareByPriority function//
//
///////////////////////////
///////////////////////////
//
bool CompareByPriority(const DllFunction &a, const DllFunction &b)
{
	return a.Priority < b.Priority;
}
//and then use std::sort in the header #include <algorithm>:
//
///////////////////////////
///////////////////////////
//
//end of CompareByPriority function//
//
///////////////////////////
///////////////////////////
//

//
///////////////////////////
///////////////////////////
//
//start of DynamicallyLoadDllFunctionsFromFile header//
//
///////////////////////////
///////////////////////////
//
void DynamicallyLoadDllFunctionsFromFile(StringType &path, StringType &targetextension, StringType &resourcefilename);
//
///////////////////////////
///////////////////////////
//
//end of DynamicallyLoadDllFunctionsFromFile header//
//
///////////////////////////
///////////////////////////
//

//
///////////////////////////
///////////////////////////
//
//start of DynamicallyLoadDllFunctionsFromFile function//
//
///////////////////////////
///////////////////////////
//
void DynamicallyLoadDllFunctionsFromFile(StringType &path, StringType &targetextension, StringType &resourcefilename)
	{
		std::vector<DllFunction> FunctionVector;

		auto list = StringManipulation::GetListOfFiles(path);

		for (auto listitem : list)
		{

			//get the current files extension
			auto extension = StringManipulation::GetExtension(listitem);
			//get the current filename without extension
			auto basefilename = StringManipulation::GetBaseFilename(listitem);
			if (extension == targetextension)
			{
				if (basefilename == resourcefilename)
				{

					
					//get a vector of lines from the current file
					auto itempath = StringManipulation::pathAppend(path, listitem);

					auto lines = StringManipulation::GetLinesFromFile(itempath);
					if (!lines.empty())
					{
						for (auto line : lines)
						{

							DllFunction function;
							auto count = 0;
							//get a vector of each "word" in the current line
							auto splitlines = StringManipulation::split(line, _T(" "));
							for (auto splitline : splitlines)
							{

								//use a switch statement to assign values based on the position of the number in the line
								switch (count)
								{
								case 0:
									function.DllName = splitline;
									break;
								case 1:
									function.DllFunctionName = splitline;
									break;
								case 2:
									function.Priority = StringManipulation::StringToInt(splitline);
									break;


								}
								//CString strMessage;
								//strMessage.Format(_T("Base FileName = %s Extension = %s Line = %s SplitLine = %s"), basefilename.c_str(), extension.c_str(), line.c_str(), splitline.c_str());
								//auto pszFileName = _T("File");
								//auto msgboxID = MessageBox(NULL, strMessage, pszFileName, MB_OK);
								count++;
							}

							FunctionVector.push_back(function);

						}
					}
				}
			}
		}

		std::sort(FunctionVector.begin(), FunctionVector.end(), CompareByPriority);
		DllFunctionParams GlobalParams;
		std::vector< f_funci> functionvect;
		for (auto function : FunctionVector)
		{

			bool succf;
			f_funci f_funci;
			HINSTANCE hLib;
#ifdef UNICODE //Test to see if we're using wchar_ts or not.
			if (GetProcAddresses(&hLib, (LPCWSTR)function.DllName.c_str(), 1,
#else

			if (GetProcAddresses(&hLib, (LPCSTR)_T(function.DllName.c_str()), 1,
#endif

				&f_funci, function.DllFunctionName.c_str()))
			{
				succf = true;
			}
			if (hLib != NULL)
				if (succf)
					FreeLibrary(hLib);
			
			auto newparams = f_funci(GlobalParams);
			GlobalParams = newparams;
		}
	
}
//
///////////////////////////
///////////////////////////
//
//end of DynamicallyLoadDllFunctionsFromFile function//
//
///////////////////////////
///////////////////////////
//
//
///////////////////////////
///////////////////////////
//
//main entry point start//
//
///////////////////////////
///////////////////////////
//
int main()
{
	StringType resourcefilename = _T("Functions");

	//filter only text files
	StringType targetextension = _T("txt");

	StringType subfolder = _T("chooks");
	//get out current working directory
	auto currentpath = StringManipulation::GetCurrentPath();
	//get the list of the files in our current working directory
	auto path = StringManipulation::pathAppend(currentpath, subfolder);
	MessageBox(NULL, path.c_str(), path.c_str(), MB_OK);
	DynamicallyLoadDllFunctionsFromFile(path, targetextension, resourcefilename);

	return 0;

}
//
///////////////////////////
///////////////////////////
//
//main entry point end//
//
///////////////////////////
///////////////////////////
//

Dll File :

DLLExport.cpp

#include <windows.h>
#include <atlstr.h>
#include <vector>
extern "C" struct DllFunctionParams
{
	std::vector<bool>vectorofbools;
	std::vector<int>vectorofints;
	std::vector<double>vectorofdoubles;
	std::vector<HWND>vectorofhwnds;
	std::vector<CString>vectorofcstrings;
	std::vector<HINSTANCE>vectorofhinstance;
};
extern "C"
{
	 __declspec(dllexport) DllFunctionParams funci(DllFunctionParams &paramsin)
	 {
		 if (!paramsin.vectorofcstrings.empty())
		 {
			 auto pszFileName = _T("File");
				 auto msgboxID = MessageBox(NULL, paramsin.vectorofcstrings[0], pszFileName, MB_OK);
		 }
		CString output;
		output.Format(_T("Output Received"));
		DllFunctionParams params;
	    params.vectorofcstrings.push_back(output);
	
		return params;
		// ...
	}
};

Then in the folder where your .exe file is create a subfolder called chooks and place a file called Functions.txt

Functions.txt contains these 2 lines

C:\Users\username\source\repos\Ikommand\Release\chooks\DllExport1.dll funci 1
C:\Users\username\source\repos\Ikommand\Release\chooks\DllExport1.dll funci 2

//parameter 1 -> the function path parameter this Is where the dll file must be && 2 -> the function name parameter && parameter 3 -> the function priority

https://github.com/PeterRussellEvans/DllExport

https://github.com/PeterRussellEvans/DynamicallyLoadDll

I will make an example that is embedded in a chook soon.

It will work for both MCBS and UNICODE character set

This should  allow Dll files to be replaced without restarting Mastercam, which can be a headache when writing chooks..

  • Like 1

Share this post


Link to post
Share on other sites
Posted (edited)

Though I cannot say I know exactly what you're doing here.
It seems like a lot of code for just for doing: LoadLibrary / GetProcAddress

BTW - 
If you're running this in a Mastercam add-in, your add-in is "MFC", so it's better to use -> AfxLoadLibrary & AfxFreeLibrary 
https://docs.microsoft.com/en-us/cpp/build/loadlibrary-and-afxloadlibrary?view=vs-2019

This  -

#ifdef UNICODE //Test to see if we're using wchar_ts or not.
        LPCWSTR lpszFuncName = NULL;
#else
        LPSTR lpszFuncName = NULL;
#endif

Could be replaced with -> LPCTSTR lpszFuncName = NULL;

LPCTSTR  - An LPCWSTR if UNICODE is defined, an LPCSTR otherwise.
https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types

 

Edited by Roger Martin from CNC Software
  • Like 1

Share this post


Link to post
Share on other sites
double StringManipulation::StringToDouble(StringType input)
{
	CString c_str = input.c_str();
	// Convert a TCHAR string to a LPCSTR
	CT2CA pszConvertedAnsiString(c_str);
	// construct a std::string using the LPCSTR input
	std::string strStd(pszConvertedAnsiString);
	return atof(strStd.c_str()); /*c_str is needed to convert string to const char*/
}

int StringManipulation::StringToInt(StringType input)
{
	CString c_str = input.c_str();
	// Convert a TCHAR string to a LPCSTR
	CT2CA pszConvertedAnsiString(c_str);
	// construct a std::string using the LPCSTR input
	std::string strStd(pszConvertedAnsiString);
	return atoi(strStd.c_str()); /*c_str is needed to convert string to const char*/
}

These functions smell funny;  atoi and atof both return 0 on failure and that's not great. 

Consider using std::stoi or std::stod.  They accept a std::string or std::wstring so there is no need to do whatever your doing to convert the input.  They also throw an exception on failure rather than an ambiguous value.

 

Share this post


Link to post
Share on other sites
3 hours ago, Roger Martin from CNC Software said:

Though I cannot say I know exactly what you're doing here.

The load library function is a bit long because it is setup to load more than 1 function at a time.

Overall I am loading the information and functions at runtime. I want Mastercam to Release the dll's containing the c++ code when the chook ends so I won"t have to reload mastercam, I also want to try reusing code without recompiling it.

3 hours ago, Roger Martin from CNC Software said:

AfxLoadLibrary & AfxFreeLibrary 

 

3 hours ago, Roger Martin from CNC Software said:

Could be replaced with -> LPCTSTR lpszFuncName = NULL;

^Thanks for the tips.

Maybe I can add a macro to use AfxLoadLibrary and AfxFreeLibrary if there is a mastercam version..

2 hours ago, Zaffin_D said:

using std::stoi or std::stod. 

Cool, thanks for the information, I was not aware of that option..

Share this post


Link to post
Share on other sites
11 hours ago, Roger Martin from CNC Software said:

AfxLoadLibrary & AfxFreeLibrary 

From what I can see Mastercam won't release the dll even if I call AfxFreeLibrary. 

The actual process lets Mastercam successfully call as many dll's are stacked in the process, but it will not allow us to call free library.

Share this post


Link to post
Share on other sites
On 4/2/2020 at 9:48 AM, Zaffin_D said:

atoi and atof both return 0 on failure and that's not great. 

In this case it were to return 0 the functions would be pushed to the front of the queue, 

I could  check the vector of  DllFunction structs and if the struct Priority parameter has a value less than one,

send an error message to the event logger and abort the process.

The priority value tells Mastercam what order the functions need to be run in.

 

The other options would be your suggestion,

or wrapping  the .net function that returns nullptr on failure.

I have not actually used exceptions before in my code..

Share this post


Link to post
Share on other sites
On 4/1/2020 at 5:07 PM, Peter from S.C.C.C. said:

auto splitlines = StringManipulation::split(line, _T(" "));

 

was changed to :

auto splitlines = StringManipulation::split(line, _T("|"));

Since using a whitespace as a delimeter is a bad choice when loading paths that could have folder names or files with whitespaces in them..

Share this post


Link to post
Share on other sites
Quote

Maybe I can add a macro to use AfxLoadLibrary and AfxFreeLibrary if there is a mastercam version.

#if defined(_AFXEXT) || defined(_AFXDLL)
      // Use the AFX versions of LoadLibrary/FreeLibrary
#else
      // Use the standard versions of LoadLibrary/FreeLibrary
#endif
Quote

…but it will not allow us to call free library

Maybe this? -  If a DLL is referenced (loaded) in a Function Table (FT) file, it cannot be unloaded while Mastercam is running.

Share this post


Link to post
Share on other sites

Enjoying this topic keep pushing Peter your really thinking outside of the box and keep it up!!!

Share this post


Link to post
Share on other sites
17 minutes ago, Roger Martin from CNC Software said:

Maybe this? -  If a DLL is referenced (loaded) in a Function Table (FT) file, it cannot be unloaded while Mastercam is running.

This applies also to DLL's which are called by the ft referenced dll's. Would an external application called by Mastercam be able to call the functions then release the dll's.

I believe there is a RunUserApplication function in the chook sdk.

 

Share this post


Link to post
Share on other sites
Quote

This applies also to DLL's which are called by the ft referenced dll's.

I don't believe so. Mastercam is concerned the the DLL specified in the FT file

Now depending on how any other DLLs the (FT listed)  DLL uses and how they are loaded/referenced may have an effect.

Quote

 believe there is a RunUserApplication function in the chook sdk.

There are 2 versions of RunUserApp in the SDK .  (Declared in interfaces\GUI\RunApp_CH.h)

Share this post


Link to post
Share on other sites
On 4/3/2020 at 5:48 PM, Roger Martin from CNC Software said:
Quote

This applies also to DLL's which are called by the ft referenced dll's.

I don't believe so. Mastercam is concerned the the DLL specified in the FT file

Maybe I need to call the function before I call afxfreelibrary?

 

On 4/1/2020 at 5:07 PM, Megabyte said:

FreeLibrary(hLib); auto newparams = f_funci(GlobalParams);  GlobalParams = newparams; }

^ I will try switching these

Share this post


Link to post
Share on other sites
5 hours ago, Megabyte said:

Maybe I need to call the function before I call afxfreelibrary?

Not sure what you are referring to here.

You mean call a function in the DLL between the AfxLoadLibrary that loaded it and the and AfxFreeLibrary  that unloads it?

If so, I don't see how that would make any difference.

 

 

Share this post


Link to post
Share on other sites
13 minutes ago, Roger Martin from CNC Software said:

You mean call a function in the DLL between the AfxLoadLibrary that loaded it and the and AfxFreeLibrary  that unloads it?

Yes.

14 minutes ago, Roger Martin from CNC Software said:

If so, I don't see how that would make any difference.

Right, I was looking at this morning and thought I was on to something, now that I had my coffee, I remember Mastercam was crying about an access violation when I tried to call freelibrary, my mistake. 

Share this post


Link to post
Share on other sites

@Roger Martin from CNC Software

Got it, I changed the project from a Managed Cli NEThook to an unmanaged Chook it unloads fine now!

I think on a another topic I saw u say how nethooks don't unload the way chooks do, something to do with .NET

:guitar:

Share this post


Link to post
Share on other sites

 

Here is a more straightforward example.

//.exe file code

Header Files :

//Pch.h
#pragma once
#include <windows.h>
#include <iostream>
//LoadDll.h
#pragma once
//the function definition
#include "Pch.h"
extern "C" typedef void(*functiontype)();

extern "C" void GetFunctionAddress(functiontype &function, const HINSTANCE &hGetProcIDDLL, const char * functiontypename, int &returnflag)
{
#pragma region GetFunctionAddress
	// resolve function address here
	function = (functiontype)GetProcAddress(hGetProcIDDLL, functiontypename);
	//handle errors
	function ?
		std::cout << "located the function named : " << functiontypename << std::endl :
		std::cout << "could not locate the function : " << functiontypename << std::endl;
	function ? returnflag = 0 : returnflag = 1;
#pragma endregion
}
extern "C" void LoadDll(HINSTANCE &hGetProcIDDLL, const char * path, int &returnflag)
{
#pragma region LoadDll
	// resolve the library address here
	hGetProcIDDLL = LoadLibrary(path);
	//handle errors
	hGetProcIDDLL ?
		std::cout << "loaded the dynamic library : " << path << std::endl :
		std::cout << "could not load the dynamic library : " << path << std::endl;
	hGetProcIDDLL ? returnflag = 0 : returnflag = 1;
#pragma endregion
}
//FileManager.h
#pragma once
#include "Pch.h"
#include <vector>
#include <atlstr.h>

#ifdef UNICODE //Test to see if we're using wchar_ts or not.

typedef std::wstring standardstring;

#else

typedef std::string standardstring;

#endif
//Get the current working directory
std::string GetWorkingDir() {
	char path[MAX_PATH] = "";
	GetCurrentDirectoryA(MAX_PATH, path);
	PathAddBackslashA(path);
	return path;
}
//Get a list of the files in the specified folder
std::vector<standardstring> GetListOfFiles(standardstring path)
{
	std::vector<standardstring>stringvector;

	WIN32_FIND_DATA fileData;

	memset(&fileData, 0, sizeof(WIN32_FIND_DATA));

	CString string;

	string.Format(_T("%s\\*"), path.c_str());

	HANDLE handle = FindFirstFile(string, &fileData);

	if (handle != INVALID_HANDLE_VALUE)
	{
		do
		{
			if (_tcscmp(fileData.cFileName, _T(".")) != 0 && // ignore "." and ".."

				_tcscmp(fileData.cFileName, _T("..")) != 0)
			{
				stringvector.push_back(fileData.cFileName);
			}
		} while (FindNextFile(handle, &fileData));
		FindClose(handle);
	}
	return stringvector;
}
//Get the extension of the filename
standardstring GetExtension(standardstring filename)

{
	//store the position of last '.' in the file name
	int position = filename.find_last_of(_T("."));
	if (position > 0)
	{
		//store the characters after the '.' from the file_name string
		standardstring result = filename.substr(position + 1);
		//print the result
		return result;
	}
	else
	{
		return "";
	}
}

.cpp Files :

//LoadDll.cpp
#include "LoadDll.h"
#include "FileManager.h"

extern "C" int main()
{
	//Get the current directory of our program
	auto workingdirectory = GetWorkingDir();
	//Modify the path to point to a folder called Libraries
	//Libraries is located in the same folder as the program
	workingdirectory = workingdirectory + "Libraries/";
	//Get a list of files from the Libraries folder
	auto files = GetListOfFiles(workingdirectory);
	//Loop through the list of files
	for (auto file : files)
	{
		//Get the extension from the filename
		auto extension = GetExtension(file);
		//check if the file is a dll
		if (extension == "dll")
		{
			//Modify the path to point to a .dll file.
			//The dll file is located in the folder called Libraries
			auto path = workingdirectory + file.c_str();

#pragma region Program Variables
	//the dll hinstance
			HINSTANCE hGetProcIDDLL;
			//the functions signature
			functiontype function;
			//the functions signature as a string
			auto functiontypename = "function";
			//the program error code
			auto returnflag = 0;
#pragma endregion

			//main program loop

#pragma region Program Main Loop
			while (returnflag == 0)
			{
				//get the hinstance
				LoadDll(hGetProcIDDLL, path.c_str(), returnflag);
				//get the function address
				GetFunctionAddress(function, hGetProcIDDLL, functiontypename, returnflag);
				//call function
				function();

				FreeLibrary(hGetProcIDDLL) ?
					std::cout << "Call to free Library succeeded" << std::endl :
					std::cout << "Call to free Library failed" << std::endl ;
				break;
			}
#pragma endregion
		}
	}
		//windows message loop
#pragma region Message Loop
		MSG Msg;
		while (GetMessage(&Msg, 0, 0, 0) > 0)
		{
			TranslateMessage(&Msg);
			DispatchMessage(&Msg);
		}
#pragma endregion
		//return from program

	return 0;
}

 

https://github.com/PeterRussellEvans/LoadDynamicLinkLibraries

//.dll file code:

//library.cpp
#include <iostream>
extern "C" __declspec(dllexport) void function()
{
	std::cout << "function executed!" << std::endl;
}

https://github.com/PeterRussellEvans/library

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

Join us!

eMastercam - your online source for all things Mastercam.

Together, we are the strongest Mastercam community on the web with over 56,000 members, and our online store offers a wide selection of training materials for all applications and skill levels.

Follow us