I have a DLL written in C++ that wraps FindFirstFile/FindNextFile/FindClose to provide a file-search function:
std::vector<std::wstring> ELFindFilesInFolder(std::wstring folder, std::wstring fileMask = TEXT(""), bool fullPath = false);
This function returns a std::vector containing a list of filenames within the given folder matching the given filemask. So far so good; the function works as expected.
I need to write a C wrapper around this library, though, because I can't pass a vector across DLL boundaries. This is leading to no end of headaches.
I initially thought I would just set up a function that would receive a two-dimensional wchar_t array, modify it to contain the filename list, and return it:
bool ELFindFilesInFolder(const wchar_t* folderPath, const wchar_t* fileMask, const bool fullPath, wchar_t* filesBuffer[], size_t* filesBufferSize);
This proved to be a bad idea, however, as at least the second dimension's size has to be known at compile-time. I suppose I could just force the caller to make the second dimension MAX_PATH (so the function would receive a variable-length list of filename buffers, each MAX_PATH long), but this seems messy to me.
I considered a wrapper in the style of the Windows APIs:
bool ELFindNextFileInFolder(const wchar_t* folderPath, const wchar_t* fileMask, const bool fullPath, wchar_t* fileBuffer, size_t* fileBufferSize, HANDLE* searchToken);
This would perform the search, return the first filename found, and save the search handle provided by FindFirstFile. Future calls to ELFindNextFileInFolder would provide this search handle, making it easy to pick up where the last call left off: FindNextFile would just get the saved search handle. However, such handles are required to be closed via FindClose, and C doesn't seem to have the C++ concept of a smart pointer so I can't guarantee the searchToken will ever be closed. I can close some of the HANDLEs myself when FindNextFile indicates there are no more results, but if the caller abandons the search before that point there'll be a floating HANDLE left open. I'd very much like my library to be well-behaved and not leak HANDLEs everywhere, so this is out. I'd also prefer not to provide an ELCloseSearchHandle function, since I'm not sure I can trust callers to use it properly.
Is there a good, preferably single-function way to wrap these Windows APIs, or am I simply going to have to pick one from a list of imperfect solutions?
What about something like this?
In the DLL module:
#include <windows.h>
#include <vector>
#include <unordered_map>
unsigned int global_file_count; //just a counter..
std::unordered_map<unsigned int, std::vector<std::wstring>> global_file_holder; //holds vectors of strings for us.
/** Example file finder C++ code (not exported) **/
std::vector<std::wstring> Find_Files(std::wstring FileName)
{
std::vector<std::wstring> Result;
WIN32_FIND_DATAW hFound = {0};
HANDLE hFile = FindFirstFileW(FileName.c_str(), &hFound);
if (hFile != INVALID_HANDLE_VALUE)
{
do
{
Result.emplace_back(hFound.cFileName);
} while(FindNextFileW(hFile, &hFound));
}
FindClose(hFile);
return Result;
}
/** C Export **/
extern "C" __declspec(dllexport) unsigned int GetFindFiles(const wchar_t* FileName)
{
global_file_holder.insert(std::make_pair(++global_file_count, Find_Files(FileName)));
return global_file_count;
}
/** C Export **/
extern "C" __declspec(dllexport) int RemoveFindFiles(unsigned int handle)
{
auto it = global_file_holder.find(handle);
if (it != global_file_holder.end())
{
global_file_holder.erase(it);
return 1;
}
return 0;
}
/** C Export **/
extern "C" __declspec(dllexport) const wchar_t* File_Get(unsigned int handle, unsigned int index, unsigned int* len)
{
auto& ref = global_file_holder.find(handle)->second;
if (ref.size() > index)
{
*len = ref[index].size();
return ref[index].c_str();
}
*len = 0;
return nullptr;
}
/** C Export (really crappy lol.. maybe clear and reset is better) **/
extern "C" __declspec(dllexport) void File_ResetReferenceCount()
{
global_file_count = 0;
//global_file_holder.clear();
}
extern "C" __declspec(dllexport) bool __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, void* lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL);
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return true;
}
Then in the C code you can use it like:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main()
{
HMODULE module = LoadLibrary("CModule.dll");
if (module)
{
unsigned int (__cdecl *GetFindFiles)(const wchar_t* FileName) = (void*)GetProcAddress(module, "GetFindFiles");
int (__cdecl *RemoveFindFiles)(unsigned int handle) = (void*)GetProcAddress(module, "RemoveFindFiles");
const wchar_t* (__cdecl *File_Get)(unsigned int handle, unsigned int index, unsigned int* len) = (void*)GetProcAddress(module, "File_Get");
void (__cdecl *File_ResetReferenceCount)() = (void*)GetProcAddress(module, "File_ResetReferenceCount");
unsigned int index = 0, len = 0;
const wchar_t* file_name = NULL;
unsigned int handle = GetFindFiles(L"C:/Modules/*.dll"); //not an actual handle!
while((file_name = File_Get(handle, index++, &len)) != NULL)
{
if (len)
{
wprintf(L"%s\n", file_name);
}
}
RemoveFindFiles(handle); //Optional..
File_ResetReferenceCount(); //Optional..
/** The above two functions marked optional only need to be called
if you used FindFiles a LOT! Why? Because you'd be having a ton
of vectors not in use. Not calling it has no "leaks" or "bad side-effects".
Over time it may. (example is having 500+ (large) vectors of large strings) **/
FreeLibrary(module);
}
return 0;
}
It seems a bit dirty to be honest but I really don't know any "amazing" ways of doing it. This is just the way I do it.. Most of the work is done on the C++ side and you don't really have to worry about leaks.. Even exporting a function to clear the map would be nice too..
It would be better if the C exports were added to a template class and then export each of those.. That would make it re-useable for most C++ containers.. I think..
Change wchar_t* filesBuffer[] to wchar_t** *filesBuffer, then the caller can pass in a pointer to a wchar_t** variable to receive the array and does not need to know anything about any bounds at compile time. As for the array itself, the DLL can allocate a one-dimensional array of wchar_t* pointers that point to null-terminated strings. That way, your size_t* filesBufferSize parameter is still relevant - it receives the number of strings in the array.
bool ELFindFilesInFolder(const wchar_t* folderPath, const wchar_t* fileMask, const bool fullPath, wchar_t** *filesBuffer, size_t* filesBufferSize);
wchar_t **files;
size_t numFiles;
if (ELFindFilesInFolder(..., &files, &numFiles))
{
for(size_t i = 0; i < numFiles; ++i)
{
// use files[i] as needed ...
}
// pass files back to DLL to be freed ...
}
Another option is to do something similar to WM_DROPFILES does. Have ELFindFilesInFolder() return an opaque pointer to an internal list, and then expose a separate function that can retrieve a filename at a given index within that list.
bool ELFindFilesInFolder(const wchar_t* folderPath, const wchar_t* fileMask, const bool fullPath, void** filesBuffer, size_t* filesBufferSize);
bool ELGetFile(const wchar_t* fileName, size_t fileNameSize, void* filesBuffer, size_t fileIndex);
void *files;
size_t numFiles;
wchar_t fileName[MAX_PATH + 1];
if (ELFindFilesInFolder(..., &files, &numFiles))
{
for(size_t i = 0; i < numFiles; ++i)
{
ELGetFile(fileName, MAX_PATH, files, i);
// use fileName as needed ...
}
// pass files back to DLL to be freed ...
}
Any way you do it, the DLL has to manage the memory, so you have to pass some kind of state info to the caller and then have that passed back to the DLL for freeing. There is no many ways around that in C, unless the DLL keeps track of the state info internally (but then you have to worry about thread safety, reentrancy, etc) and frees it after the last file is retrieved. But that would require the caller to reach the last file, whereas the other approaches allow the caller to finish earlier if desired.
Related
I am trying to execute a game function that displays text to the chat screen. I pulled the address from IDA that then calls _vsnprintf. I can get it to display text to the chat but its wonky random letters that changes whenever I mess with the argList. Heres the constructor for _vsnprintf.
int __cdecl _vsnprintf(char *const Buffer, const size_t BufferCount, const char *const Format, va_list ArgList) //0xA739FF
Whenever I change something in ArgList it changes the text result but the text displayed in chat is still random and wonky.
Also this is the function that calls _vsnprintf
int __cdecl print_to_chat(char *Buffer, size_t BufferCount, char *Format, char ArgList) //0x51D020
And here is the code I got so far
namespace bo2 {
constexpr uintptr_t say = 0x7EB870;
constexpr uintptr_t printf = 0xA739FF;
using say_t = void(*)();
using printf_t = void(*)(char* const Buffer, const size_t BufferCount, const char* const Format, va_list ArgList);
}
BOOL APIENTRY DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) {
if (reason == DLL_PROCESS_ATTACH) {
const auto say = reinterpret_cast<bo2::say_t>(bo2::say);
const auto printf = reinterpret_cast<bo2::printf_t>(bo2::printf);
char buf[255], format[255]; size_t size = 256; std::string rV = "does this work now??????";
va_list list;
va_start(list, rV);
say();
printf(buf, size, format, list);
}
}
Any help?
I tried editing Format to get a proper display to chat text but that doesn't seem to be it after realizing whatever was edited in ArgList contributed to a proper yet random and wonky return of text to chat.
EDIT: Im now only calling _vsnprintf instead of print_to_chat and using va_list instead of const char* or char*
we are having a discussion as what is a good way to return multiple strings from one dll function. Currently we have 8 strings, but there will be more. For simplicity I now consider all strings will have equal lengths.
extern "C" int DLLNAME_ _stdcall GetResult(TestResults* testResults);
where
struct TestResults
{
int stringLengths;
char* string1;
char* string2;
char* string3;
char* string4;
...
};
or second option: where
struct TestResults
{
int stringLengths;
char string1[64];
char string2[64];
char string3[64];
char string4[64];
...
};
third option:
extern "C" int DLLNAME_ _stdcall GetResult(int stringLengths, char* string1, char* string2, char* string3, ...);
The dll will communicate over a serial line and retrieve information that will be filled into the strings. Where the memory needs to be allocated is open for discussion and can be part of the answer.
The background is that we have a VB6 application team that prefers the second method and a C++/C# team that prefers the first method. Last method looks to suit both teams but looks a bit strange to me with so many parameters.
Maybe there are more options. What is common practice under Windows? Any examples from the Windows API or arguments to choose one over the other?
Edit: The strings have a meaning as in first name, last name, email. We currently have eight, but in the future we might add a couple for example for address. An array would not be the correct choice for this, but that was not clear from the original context.
The best way is probably using a safe array storing BSTR strings.
Both VB and C# understand safe arrays very well: in C#, a safe array of BSTR strings is automatically converted to a string[] array.
On the C++ side, you can use the ATL::CComSafeArray helper class to simplify safe array programming.
You will find interesting material in this MSDN Magazine article (in particular, take a look at the paragraph Producing a Safe Array of Strings).
From the aforementioned article: On the C++ side, you can implement a C-interface DLL, exporting a function like this:
extern "C" HRESULT MyDllGetStrings(/* [out] */ SAFEARRAY** ppsa)
{
try {
// Create a SAFEARRAY containing 'count' BSTR strings
CComSafeArray<BSTR> sa(count);
for (LONG i = 0; i < count; i++) {
// Use ATL::CComBSTR to safely wrap BSTR strings in C++
CComBSTR bstr = /* your string, may build from std::wstring or CString */ ;
// Move the the BSTR string into the safe array
HRESULT hr = sa.SetAt(i, bstr.Detach(), FALSE);
if (FAILED(hr)) {
// Error...
return hr;
}
}
// Return ("move") the safe array to the caller
// as an output parameter (SAFEARRAY **ppsa)
*ppsa = sa.Detach();
} catch (const CAtlException& e) {
// Convert ATL exceptions to HRESULTs
return e;
}
// All right
return S_OK;
}
On the C# side, you can use this PInvoke declaration:
[DllImport("MyDll.dll", PreserveSig = false)]
public static extern void MyDllGetStrings(
[Out, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
out string[] result);
As you declare your function as extern "C" I suppose that you cannot use std::vector<std::string> as return type.
Another possibility would be:
struct String
{
int size; /* size of string */
const char* str; /* actual string */
}
struct TestResults
{
int size; /* number of strings */
String* arr; /* pointer to an array of String */
};
and then the same as before:
extern "C" int DLLNAME_ _stdcall GetResult(TestResults* testResults);
With that you are flexible to return as much strings as you like. Also loop through your TestResults is easy.
Edit #1: As said in the comments: use BSTR. So your struct would look like:
struct TestResults
{
int size; /* number of strings */
BSTR* arr; /* pointer to an array of BSTR */
};
A BSTR will be allocated by: BSTR MyBstr = SysAllocString(L"I am a happy BSTR");. This allocation also sets the member which contain the length of the string. You have to free the allocated memory with: SysFreeString(MyBstr);. Also you need to allocate the whole array BSTR*.
First, I am new to C++ (nearly a week into it), so forgive me if this is obvious. Also, I have hunted through many posts with similar issues. Either my understanding is just not developed enough, or none had relevant info to help me understand this issue.
In Metatrader 4, I am trying to figure out how to pass a structure variable to a dll, and modify variables stored in said structure. So far, I have had great success, even when dealing with structure arrays. Then I encountered an issue.
I have narrowed the problem down to the use of strings. If you will, please have a look at the following code, which I have used to focus on solving this problem, and help me understand why I keep getting this 'Access violation write to 0x00000000' error whenever I try and run the script in mt4.
The mql4 code:
struct Naming
{
string word;
} name;
#import "SampleDLLtest.dll"
bool NameTest(Naming &name);
#import
int init() { return(0); }
int start()
{
Print("original name: ", name.word);
if( NameTest( name ) )
{
Print("new name: ", name.word);
}
//---
return(0);
}
This is the relevant dll code:
#define WIN32_LEAN_AND_MEAN
#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
//---
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
//---
return(TRUE);
}
struct Naming
{
std::string n_name;
};
bool __stdcall NameTest(Naming *name)
{
name->n_name = "Captain Success";
return true;
}
From the documentation of mql4: http://docs.mql4.com/basis/preprosessor/import
The following can't be used for parameters in imported functions:
pointers (*);
links to objects that contain dynamic arrays and/or pointers.
Classes, string arrays or complex objects that contain strings and/or
dynamic arrays of any types cannot be passed as a parameter to
functions imported from DLL.
The imported function takes a pointer and that is apparently not supported by mql4.
You should probably use a fixed size array of characters to pass data to and from the dll:
like:
struct Naming {
char m_name[255];
}
The function would need to accept a reference to this struct (but this is probably not supported either) or accept the struct directly and return the struct.
Naming NameTest(Naming name) {
strncpy(name.m_name, "New Content", sizeof(name.m_name) -1);
if (sizeof(name.m_name) > 0) {
name.m_name[sizeof(name)-1] = 0;
}
return name;
}
Calling it would then look like this:
name = NameTest(name);
I know this is a bit odd, but I am answering my own question because I figured out what was going on....mostly at least.
So, here is the deal. Technically speaking, you can pass a structure that contains a string. What you cannot do is edit the string. There is no automatic conversion of a string to a char[] in the structure. So, when the dll attempts to edit the string, it throws up the access violation because a string is not really a string in C++, but is a char array disguised as a string.
That said, I did resolve how to pass a structure containing a string, and modify the value in the dll. Here is how I did it.
---Starting with the mql4 code---
First, I declared the struct with a char[] instead of a string.
struct Naming
{
char word[65];
} name;
Then I initialized the char[] with null value, checked it, passed the struct, and checked to see if the value was set correctly.
ArrayInitialize(name.word, '\0');
Print("original name: ", CharArrayToString(name.word));
if( NameTest( name ) )
{
Print("new name: ", CharArrayToString(name.word));
}
---now to the C++ code---
I declared the same struct.
struct Naming
{
char n_name[65];
};
Then the function. I first had to capture the string literal in a temporary char[]. The I cycled a for loop to distribute the elements to the char[] in the struct. The problem is, the char[] from the struct is not a const, and the char temp[] is. I got around this by capturing each char to a char variable, and then storing that variable value in the struct char[].
bool __stdcall NameTest(Naming *name)
{
char temp[] = "Captain Success";
for (int i = 0; temp[i] != '\0'; i++)
{
char t = temp[i];
name->n_name[i] = t;
}
return true;
}
This code works beautifully.
I hava a class likeļ¼
class SomeClass
{
void initFromBuffer(void* buffer,int length);
void initFromString(const std::string& str);
}
Using tolua++, got the binding like:
static int SomeClass_initFromBuffer00(lua_State* tolua_S)
{
SomeClass* self = (SomeClass*) tolua_tousertype(tolua_S,1,0);
void* buffer = ((void*) tolua_touserdata(tolua_S,2,0));
int length = ((int) tolua_tonumber(tolua_S,3,0));
self->initFromBuffer(buffer,length);
}
and:
static int SomeClass_initFromString00(lua_State* tolua_S)
{
SomeClass* self = (SomeClass*) tolua_tousertype(tolua_S,1,0);
const std::string str = ((const std::string) tolua_tocppstring(tolua_S,2,0));
self->initFromString(str);
tolua_pushcppstring(tolua_S,(const char*)str);
}
Now,i want to pass binary data from lua to c++,the binary has '\0' in it,so if i use initFromString to pass it, the binary data will be trimed. But if i use initFromBuffer to pass it, i got bad ptr at `void* buffer = ((void*) tolua_touserdata(tolua_S,2,0));, the pointer is null.
So, how could i pass binary string from lua to c++?
Maybe you should stop using Tolua's bad APIs and use plain Lua's actually good APIs. Both std::string and Lua strings are capable of storing embedded null characters. The only reason tolua_tocppstring causes truncation is because the function name is a lie. It doesn't convert it to a C++ string; it converts it to a C string, a const char*.
The correct answer is to use the proper API function:
std::string fromLuaStack(lua_State *lua, int stackIx)
{
size_t len;
const char *str = lua_tolstring(lua, stackIx, &len);
return std::string(str, len);
}
Similarly, you can use lua_pushlstring to push a std::string onto the stack.
It's unfortunate that Tolua doesn't have better documentation, as there may be a function to do this all directly. If there is, I couldn't find it.
For our C/C++ app we are using Security Transforms API for doing some basic encryption/decryption.
And now we need to calculate hash (especially SHA256) of data, and though documentation claims that Security Transforms also provides a way of hashing, but seems there is no details of how to do it. And seems google doesn't bring any example or details on it as well.
So question is:
Is it really possible to calculate hash (SHA256 if possible) using Security Transforms?
And if no, then is there any other API (provided by Apple) to calculate it using C/C++?
I don't know about Security Transforms. You can use Apple's CommonCrypto library for this, though.
Oddly much of CommonCrypto does not seem to be well documented (at least that I can find), but in https://opensource.apple.com//source/CommonCrypto/CommonCrypto-7/CommonCrypto/CommonDigest.h.auto.html find the following declarations:
extern int CC_SHA256_Init(CC_SHA256_CTX *c);
extern int CC_SHA256_Update(CC_SHA256_CTX *c, const void *data, CC_LONG len);
extern int CC_SHA256_Final(unsigned char *md, CC_SHA256_CTX *c);
After digging a lot it turned out that it's possible with Security Transforms API though it was not documented. To make it work, crafted samples of AES encryption with SecDigestTransformCreate and used list of available hashing algorithms there.
Here is a C and C++ friendly solution:
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
#ifdef __cplusplus
#include <vector>
#else // C
#include <stdbool.h> // For adding boolean support
#endif // __cplusplus
// Convenience define for cleanup
#define _CLEANUP_IF(a) if ((a)) goto Cleanup;
#ifdef __cplusplus
// Wrap into class in case of C++
class Sha256Calculator {
public:
#endif // __cplusplus
// Calculates SHA256 hash from given array of data and returns array
// Note: Parameter "outHash" is manually allocated so consider calling free(outHash) after using it
static bool calculateSha256(uint8_t** outHash, size_t* outHashSize, const uint8_t *data, const size_t dataSize)
{
bool result = false;
CFErrorRef error = NULL;
SecTransformRef digestTransform = NULL;
CFDataRef sourceData = NULL;
CFDataRef outDataRef = NULL;
const UInt8 * outData = NULL;
CFIndex outDataSize = 0;
// Create a CFData object from the source
sourceData = CFDataCreate(kCFAllocatorDefault, (const UInt8*)data, dataSize);
_CLEANUP_IF(!sourceData);
digestTransform = SecDigestTransformCreate(kSecDigestSHA2, 256, &error);
_CLEANUP_IF(error);
SecTransformSetAttribute(digestTransform, kSecTransformInputAttributeName, (CFDataRef)sourceData, &error);
_CLEANUP_IF(error);
outDataRef = (CFDataRef)SecTransformExecute(digestTransform, &error);
_CLEANUP_IF(error);
_CLEANUP_IF(!outDataRef);
// Extract data from CFDataRef to array
outData = CFDataGetBytePtr(outDataRef); // Returns read-only (UInt8*) pointer to the data
outDataSize = CFDataGetLength(outDataRef);
if (outHash) {
*outHash = (uint8_t*)malloc(outDataSize);
if (*outHash) {
memcpy(*outHash, outData, outDataSize);
if (outHashSize) {
*outHashSize = (size_t)outDataSize;
}
result = true;
}
}
// Notes:
// * All the objects are released except "outData" since it's handled and cleaned by using outDataRef
// * CFRelease throws error if the passed object is NULL, so check objects before releasing
Cleanup:
// Use CFShow(error) for getting details about error
if (error) { CFRelease(error); }
if (digestTransform) { CFRelease(digestTransform); }
if (sourceData) { CFRelease(sourceData); }
if (outDataRef) { CFRelease(outDataRef); }
return result;
}
#ifdef __cplusplus
// Convenience method for cpp using vectors
static bool calculateSha256(std::vector<uint8_t>& outHash, const std::vector<uint8_t>& data)
{
// Call original method
uint8_t * outHashArray = nullptr;
size_t outHashSize;
bool result;
result = calculateSha256(&outHashArray, &outHashSize, data.data(), data.size());
if (!result)
return false;
// Put resulting array in vector
outHash.clear();
outHash.insert(outHash.end(), &outHashArray[0], &outHashArray[outHashSize]);
// Clean allocated array
if (outHashArray)
free(outHashArray);
return result;
}
};
#endif // __cplusplus
Note:
In order to use any other hashing algorithgm instead of SHA256 feel free to modify the line:
SecDigestTransformCreate(kSecDigestSHA2, 256, &error);
with desired available hashing algorithm name and appropriate length.
PS Hope, Apple will guys will update their documentation...