❔ PInvoke, Reflection or winapi for loading a DLL?
I need some advise for how to implement a dynamically loadable dll that ive written in c++ and exported with extern C function wrappers. Unfortunally im not that proefficient in C#. i cant seem to find a dynamic way to make calls via those function pointers.
110 Replies
for reference this is my importer so far
and incase that its relevant this is my exporter from within the dll project
additionally, this is my c++ sample of my working importer
i don't quite understand. what's with all the loadlibrary stuff? why not just dllimport the dll directly?
because i want to be able to unload it at runtime
if the implementation utilizing the lib wishes to do so
unlike the kernel32.dll the iniparser.dll can be replaced or deleted at runtime
but only if the reference count is 0
additionally the behavior could not be updated at runtime
why make it so difficult for yourself... i don't get it...
if using reflection
im writing a game in unity and i want my backend to be updateable without shutting the server down
to make it short xD
additionally i aim for similar behavior across the languages
and id prefer to refrain from using unsafe scopes because its from what ive seen not favored in the c# community.
yeah i bet #allow-unsafe-blocks would love to hear about that
completely bogus take
with those c++ definitions you can't avoid unsafe code anyway
because you chose to take pointers
well it would work with reflection
i mean it does
why write the parser in c++ at all?
so many questions
to load it in c, c++, c#, java, python etc
from one binary
without rewriting the entire definitions in every language
with the proper setup it can be compiled under windows and linux
to generate the different binary formats
and then be loaded by each language using their own importer
also the intptr returned by GetProcAddress is returning valid pointers already. i literally just need to be able to make calls to it
someone else will have to help you there. this is quite frankly a really bad setup and you should consider just dllimporting the library directly
isee
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.anyone?
the reflection method is for managed assemblies
what you probably want is
LoadLibrary
from win32
also why do you have pinvoke and winapi as two separate things?Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.im using LoadLibraryA yes
id love the second approach with function pointers but im not sure if having users enable the unsafe context for their project just to use my api is beginner friendly for the name might scare them or similar things
maybe im overthinking that though xD
id be optimal for across all the languages to just have the user include the header(importer) (or pseudo header like in c#), initialize the dll/so/lib/a etc library and ready to go.
if you want user frendliness write a wrapper in c#
if they know they have to pinvoke then they know they have to do unsafe stuff
why the ansi version
so a local unsafe scope wont require setting fiddling? okay to be fair i presumed that i had to change the attribute of the wrapper class itself if that works id be perfect, or did i missunderstand your answer?(cant test it as of rn)
because for now ive written the entire lib using chars
its really just a matter of copy paste to refactoring to / adding the utf format
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.
Was this issue resolved? If so, run /close
- otherwise I will mark this as stale and this post will be archived until there is new activity.may it be assumed that im using the function pointer correctly here?
with the constructors resulting in this
there is no reason in casting it to a function pointer if youre then casting it to an intptr
how else would i make a call to a function by a function pointer stored within an IntPtr
you didnt call it
you just casted it
yeah thats what im thinking
hm sec
to call it
ah right ty makes sense xD given i basically call it the same in c
yeah its pretty much the same
right thanks alot 😄
@Jester 😛 with this works just fine now
the line seperator is supposed to be the comma so it works
good
just one further question, do i need to delete Marshalled strings? regarding memory leaks
you need to delete
ptr
ah so i need to delete all of them
in every function
you need to delete everything thats unmanaged, when youre done with it of course
i presume the same then applies to this char? and the solution is to make a managed copy delete the unmanaged one and return the managed one?
no this isnt a pointer
you only need to delete objects that were are allocated on the heap
the getFileExtension returns a pointer pointing to a const char* tho
from unmanaged code
yes, thats an array on the heap (i assume)
on the stack
the const char* itself is on the stack
the array is on the stack?
ya
wait
if its on the stack then its deleted when the function returns
so the pointer you return is invalid
this is how my lib manages it this is the string class object and then its actually returned by this
and this const char* is what the IntPtr in points to
which is then to be marshalled to a C# string
so is what the C# importer actually interfaces with
so the returned value is on the stack while the actual value is on the heap within a std::string class thats encapsuled
so the string is on the heap
yea but its encapsuled and managed by the .dll itself
it only exposes a copy on the stack to the calling language
std::string frees the heap object when its destructed
but it looks like its a member of a class
it is
so it will get freed automatically when that class is destructed
yea
and i destruct the class like this
which is called by
those
yeah so you dont need to delete anything here, since its just returning a member of a class
so i wonder if i actually need to delete the ptr in
this should implement
IDisposable
hm
but in general, i dont need to delete anything here other than the m_pIniParser ptr ofc?
you dont need to delete that
from how i understand it now the delegate doesnt allocates new memory on the heap here
the std::string handles it when its destructed
kk
yup
yea i tried to write the actual library impelentation in a way that it manages itself
so other higher languages dont need to other than the actual IniParser object from the lib
yup thats good
id also make this a property
ill read into properties xD im not that versed in c#
in c# we use properties instead of get and set methods
hmm
checked microsofts documentation, seems the properties are getters and setters allowing for a more "natural" access to the values? just copied this from the msdocs
yup
you access them like fields
but instead they call
get
/set
/init
well if thats the way to go ill write the c# importer like that, always good to implement language specific features
yup
like C developers would tear my head off for an OOP approach xD
btw we have expression bodies now so
get => _seconds / 3600;
i think ive seen that in c++
this syntax
really?
which is a rather new feature
yea
xD
i thought cpp didnt have that
c++20 or so
its adopting alot of high level language features as of lately
i cant keep up with c++
found this and then they can be called like this found it online really quick xD though id need to dig myself deeper into that to actually utilize it
I think you misunderstood what 'expression bodied function' in c# is. Ie in some circumstances defining a method body without {}.
I don't think that's valid anywhere in c++
to be fair i just copied that quickly since i didnt use it myself for some time now esp since im mostly forced to write in c for my uni projects. rn im experimenting with properties in c#
like this?
yup
you might aswell declare the whole class as unsafe
though how do i manage multiple parameters for a setter?
you don't
you use a method
hm
then ill probably use getter setter methods to keep it uniform since i have to implement those as well
use properties for things they make sense to be properties
like this one
and ik suppressing a warning isnt the best idea but i tested throughly to figure that the IDE throws a false warning
hm so using a combination of both?
yes
i doubt that
it complained just the same with a char** allocated with malloc this way xD
it doesnt like me using values.size() to index the size somehow if i use a primitive int and iterate trough the vector til the end and increment the index and then use this index theres no problem whatsoever
Why pass the vector by value?
Why not use range based for loop?
Is ppArray too big to go on stack?
You literally allocate ppArray the line before checking if not null. Why?
i have so many questions
uh, is it possible to load C++ assemblies into Java, Python and such languages?
I didn't know that was a thing
They get loaded into memory. Yes python can run cpp DLLs via a C ffi layer. That's what python c extensions are, and why compiling/installing on Windows is an annoyance
I still have no clue what you're trying to do with your parser, why complicate your life so much?
If you want to share the same results across multiple languages, why don't you build a standalone parser which writes your desired data into a json or such files
1 sec
i can change it to reference, a range based for loop requires more time than using vector.size() to get the size, ppArray is not too big but i want it of dynamic size, i check if its not null because heap allocations can throw bad allocs
and then everything goes boom if i have a bad alloc
yes
heap alocations can throw bad allocswhat does this mean?
In order,
Highly doubtful, use std::array, if it throws bad alloc then you don't get to the next line so no need to check
well if you attempt to allocate memory on the heap and the underlying OS and to that extend kernel is not able to allocate the memory for you because, not enough ram, not enough consequtive free memory in ram, no or insufficient page file, corrupted hardware(RAM) etc etc then it returns a null pointer which tells u that the OS was not able to allocate memory for you
in which case, you have undefined behavior
new
can throw if there is insufficient memoryso the solution is to always null check whenever you allocate something?
that sounds terrible
well what is the alternative even std::vector can throw a bad alloc
xD
the alternative is to hope that nothing breaks
tbh if u dont play with ur OS settings and dont install faulty ram, most likely nothing ever happens but better safe than sorry
What you're doing doesn't help anything tho
how so
i mean if theres insufficient memory should your app continue running anyway?
up to the programmer whos using the lib to decide
Exceptions unwind the stack
its not really hard to change either implementation anyways
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.