Giter VIP home page Giter VIP logo

conari's Introduction

๐Ÿงฌ An unmanaged memory, modules, and raw data in one-touch.

Conari engine represents most flexible platform for working with unmanaged memory, modules, related P/Invoke features, and more around libraries, executable modules, runtime dynamic use of the unmanaged native C/C++ in .NET world and other raw data just in a few easy steps without configuring something, and... Even accessing to complex types like structures without their declaration at all.

Build status release-src License NuGet package Tests

Build history

[ Quick start ] [ Complex types and strings ] -> { Wiki }

Why Conari ?

It was designed to be loyal to your needs on the fly!

๐Ÿ” Easy to start

using ConariL l = new("...");

๐Ÿงฐ Powerful types

No more manual type conversions and memory management complexities. Because nothing easier than just use it,

[โฏ]

using dynamic l = new ConariX("regXwild.dll");

string data = "number = 888;";
bool found = l.replace<bool>(ref data, "+??;", "2034;");
// found: true; data: number = 2034;

๐Ÿ”จ Its amazing DLR features

using dynamic l = new ConariX("...");
l.<whatever_you_want>(curl, 10002, "https://");

Still not convinced? Here's full workable code example for regXwild:

using var c = ConariL.Make(new("regXwild"), out dynamic l);
// ready for everything even without configuring

using var u = NativeStruct.Make.f<UIntPtr>("start", "end").Struct;
/* Hey! We just generated a structure like
[StructLayout(LayoutKind.Sequential)]
private struct MatchResult
{
    public UIntPtr start;
    public UIntPtr end;
}*/

if(l.match<bool>("n = '888';", "'*'", 2/*MATCH_RESULT*/, u))
{
    /* Now we just generated and invoked this
    REGXWILD_API_L bool match
    (
        const rxwtypes::TCHAR* input,
        const rxwtypes::TCHAR* pattern,
        rxwtypes::flagcfg_t options,
        EssRxW::MatchResult* result
    )
    */
    dynamic v = u.Access; // just access the EssRxW::MatchResult* result
    // v.start == 4; v.end == 9;
}
// Yes, a 4 lines and your task is done; Free memory, Free hands.

๐Ÿš€ Awesome speed

Optional caching of 0x29 opcodes (Calli) and more.

test of regXwild's algorithms [340x10000 Unicode] +icase [x32] +icase [x64] `
regXwild native C++ EXT algorithm ~50ms ~26ms <<
regexp-c++11(regex_search) ~59309ms ~53334ms
regexp-c++11(regex_match with endings .*) ~59503ms ~53817ms
.NET Regex engine [Compiled] ~38310ms ~37242ms
.NET Regex engine ~31565ms ~30975ms
regXwild via Conari v1.3 (Lambda) - EXT ~54ms ~35ms <<
regXwild via Conari v1.3 (DLR) - EXT ~214ms ~226ms

๐Ÿ”ง The easiest (most ever) access to any data in unmanaged memory

// Everything will be generated at runtime
memory.Native()
    .f<WORD>("Machine", "NumberOfSections") // IMAGE_FILE_HEADER (0xF4)
    .align<DWORD>(3)
    .t<WORD>("SizeOfOptionalHeader")
    .t<WORD>("Characteristics")
    .region()
    .t<WORD>("Magic") // IMAGE_OPTIONAL_HEADER (0x108)
    .build(out dynamic ifh);

if(ifh.SizeOfOptionalHeader == 0xF0) { // IMAGE_OPTIONAL_HEADER64
    memory.move(0x6C);
}

// Use it !

ifh.NumberOfSections // 6
ifh.Characteristics  // IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE | IMAGE_FILE_DLL
ifh.Machine          // IMAGE_FILE_MACHINE_AMD64
ifh.Magic            // PE64
dynamic l = ptr.Native().f<int>("x", "y").build();
l.x // 17
l.y // -23

๐Ÿ„ Most powerful PInvoke and even most convenient use of WinAPI without preparing something

Conari will generate and adapt everything at runtime! Specially for you! For example, below we don't provide neither user32.ShowWindow() nor user32.MessageBoxA(), even no kernel32.GetModuleHandleA/W()

dynamic user32 = new User32();

    user32.ShowWindow(0x000A0A28, 3);
    user32.MessageBoxA(0, "Conari in action", "Hello!", 0);
dynamic kernel32 = new Kernel32();

    kernel32.GetModuleHandleA<IntPtr>("libcurl-x64");
    kernel32.GetModuleHandleW<IntPtr>((WCharPtr)ustr);

Because our recipe is simple, Just use it! and have fun.

๐Ÿ”– Modern .NET Core

Conari is ready for .NET Core starting from 1.4. Even for .NET Standard 2.0 which does not cover unmanaged EmitCalli due to missing implementation for System.Private.CoreLib. Now this is another one of independent solution for everyone as https://github.com/3F/UnmanagedEmitCalli

๐Ÿฐ Open and Free

Open Source project; MIT License; Fork! Star! Contribute! Share! Enjoy!

Conari is available for everyone from 2016 ๐ŸŽ‰

๐Ÿ—ธ License

The MIT License (MIT)

Copyright (c) 2016-2021  Denis Kuzmin <[email protected]> github/3F

[ โ˜• Make a donation ]

Conari contributors https://github.com/3F/Conari/graphs/contributors

We're waiting for your awesome contributions!

Take a look closer

Conari generally provides two mode,

Fully automatic way through its dynamic features (DLR). For example, when using the unmanaged code:

var ptr     = d.test<IntPtr>(); //lambda ~ bind<Func<IntPtr>>("test")();
var codec   = d.avcodec_find_encoder<IntPtr>(AV_CODEC_ID_MP2); //lambda ~ bind<Func<ulong, IntPtr>>("avcodec_find_encoder")(AV_CODEC_ID_MP2);
              d.push(); //lambda ~ bind<Action>("push")();
              d.create<int>(ref cid, out data); //lambda ~ bind<MyFunc<Guid, object>>("create")(ref cid, out data);

This (or like) does not require the any configuration from you, because Conari will do it automatically.

Semi-automatic way through its custom lambda expressions. For example, when using the unmanaged code:

using(var l = new ConariL("Library.dll"))
{
    l.bind<Action<int, int>>("call")(2, 1); 
    double num = l.bind<Func<IntPtr, int, double>>("tonumber")(L, 4);
}

This also does not require neither the creation of any additional delegates nor the configuring something. Just a more control through l.bind<...>("...") methods that still make you happy;

// invoke it immediately
l.bind<Action<int, string>>("set")(-1, "Hello from Conari !");

// or later
set(-1, "Hello from Conari !");

Native C/C++ structures without declaration [?]:

// IMAGE_FILE_HEADER: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680313.aspx
dynamic ifh = binaryData.Native()
            .t<WORD, WORD>(null, "NumberOfSections")
            .align<DWORD>(3)
            .t<WORD, WORD>("SizeOfOptionalHeader")
            .build();
                
if(ifh.SizeOfOptionalHeader == 0xF0) { // IMAGE_OPTIONAL_HEADER64
    ... 
}

// IMAGE_DATA_DIRECTORY: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680305.aspx
binaryData.Native()
    .t<DWORD>("VirtualAddress")
    .t<DWORD>("Size")
    .build(out dynamic idd);

DWORD offset = rva2Offset(idd.VirtualAddress);
IntPtr ptr ...
Raw mt = ptr.Native()
            .align<int>(2, "a", "b")
            .t<IntPtr>("name")
            .Raw;
            
-     {byte[0x0000000c]} byte[]
        [0]    0x05    byte --
        [1]    0x00    byte   |
        [2]    0x00    byte   |
        [3]    0x00    byte --^ a = 5
        [4]    0x07    byte --
        [5]    0x00    byte   |
        [6]    0x00    byte   |
        [7]    0x00    byte --^ b = 7
        [8]    0x20    byte --
        [9]    0x78    byte   |_ pointer to allocated string: (CharPtr)name
        [10]   0xf0    byte   |
        [11]   0x56    byte --
...

A modern NativeData chains for everything (Memory, Streams, Local collections, ...)

.move(0x3C, Zone.D)
.read(out LONG e_lfanew)
.move(e_lfanew, Zone.D)
.eq('P', 'E', '\0', '\0')
.ifFalse(_ => throw new PECorruptDataException())
.Native()
.f<WORD>("Machine", "NumberOfSections")
.align<DWORD>(3)
.t<WORD, WORD>("SizeOfOptionalHeader", "Characteristics")
.region()
.t<WORD>("Magic") // start IMAGE_OPTIONAL_HEADER offset 0 (0x108)
.build(out dynamic ifh)
.Access
.move(ifh.SizeOfOptionalHeader == 0xF0 ? 0x6C : 0x5C)
.read(out DWORD NumberOfRvaAndSizes)
.Native() // DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
.t<DWORD>("VirtualAddress")
.t<DWORD>("Size")
.build(out dynamic idd)
.Access.move(8 * (NumberOfRvaAndSizes - 1))
...

// ifh.Machine;          - IMAGE_FILE_MACHINE_AMD64
// e_lfanew              - 0x110
// NumberOfRvaAndSizes   - 16
// idd.VirtualAddress    - VA 0x7070
// ifh.Characteristics;  - IMAGE_FILE_EXECUTABLE_IMAGE 
//                          | IMAGE_FILE_LARGE_ADDRESS_AWARE 
//                          | IMAGE_FILE_DLL
// ifh.Magic;            - PE64
// ifh.NumberOfSections; - 6
// ...

Calling Convention & Name-Decoration [?]

using(var l = new ConariL("Library.dll", CallingConvention.StdCall))
{
    //...
    l.Mangling = true; // _get_SevenStdCall@0 <-> get_SevenStdCall
    l.Convention = CallingConvention.Cdecl;
}

Exported Variables [?] & raw accessing [?]

l._.ADDR_SPEC // DLR, 0x00001CE8
l.V.get<UInt32>("ADDR_SPEC"); // lambda, 0x00001CE8
std_cin = l.addr("?cin@std@@3V?$basic_istream@DU?$char_traits@D@std@@@1@A");

Aliases [?]

// v1.3+
l.Aliases["Flag"] = l.Aliases["getFlag"] = l.Aliases["xFunc"]; //Flag() -> getFlag() -> xFunc()->...
// ...
l._.getFlag<bool>();

Additional types

  • TCharPtr, CharPtr, WCharPtr, float_t, int_t, ptrdiff_t, size_t, uint_t, ...
  • NativeString<T> (+NativeStringManager<T>) - Fully supports TCharPtr, CharPtr, WCharPtr;
  • NativeStruct - Fully automatic way of working with structures without declarations using NativeData chains;
  • NativeStruct<T> - Semi-automatic way of working with structures using CLR types declarations;
  • NativeArray<T>
  • ...
using var a = new NativeString<WCharPtr>("Hello");
using var b = a + " world!"; // unmanaged C-string, a Unicode characters
CharPtr name = c.to<CharPtr>(1, out size_t len);
//CharPtr name = c.bind<FuncOut3<int, size_t, IntPtr>>("to")(1, out size_t len);
string myName += name; // 8 bit C-string and managed string (UTF-16)
using NativeArray<short> nr = new(pointer); // points to ~0x2674F89EDF0
nr[0] = 1; nr[1] = 2;
using NativeArray<int> nr = new(1, 2, 3);
nr[0] = -1;
nr[1] = 0;
nr[2] = 1;

Assert.True(nr == new int[] { -1, 0, 1 });
using var u = new NativeStruct<MatchResult>();
l.match<bool>(
    "[system]", "Sys###", 
    EngineOptions.F_ICASE | EngineOptions.F_MATCH_RESULT, 
    u
);
u.Data.start // 1
u.Data.end   // 7
using ConariL l = new("regXwild.dll");
l._.replace<bool>
(
    l._T("number = 888;", out CharPtr result), 
    l._T("+??;"), l._T("2034;")
);
// result: number = 2034;
using dynamic l = new ConariX(RXW_X);

bool found = l.replace<bool>
(
    "Hello {p}".Do(out TCharPtr result),
    "{p}",
    "world!"
); // found: true; result: Hello world!

and more ...

How about regXwild (โฑ Superfast ^Advanced wildcards++? on native unmanaged C++) in your C# code?

using dynamic l = new ConariX("regXwild.dll");
if(l.match<bool>(input, "'+.#?'")) {
    // ... '1.4', '1.04', ...
}

Yes, you don't need to do anything else! Conari will prepare everything for binding with the following native method instead of you:

REGXWILD_API_L bool match
(
    const rxwtypes::TCHAR* input,
    const rxwtypes::TCHAR* pattern,
    rxwtypes::flagcfg_t options = 0,
    EssRxW::MatchResult* result = nullptr
);

How to get Conari

conari's People

Contributors

3f avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

conari's Issues

IUnknown. COM Interface support

Currently all works fine, but I need more flexible things like here #2

How we can play with current versions:

// the working half-declaration of original interface:
[Guid("23170F69-40C1-278A-0000-000600600000")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IInArchive
{
      void a(); void b();
 
0x02: uint GetNumberOfArchiveProperties();                             // <-- uint GetNumberOfItems();
                                                                            |
      void c(); void d(); void e(); void f(); void g();                     |
                                                                            |
0x08: uint GetNumberOfItems(); //uint GetNumberOfArchiveProperties();  // <-/  moreover, it can be like MySPecial001() for calling from our side.
}
...

IInArchive ar;
// DLR for STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
l.DLR.CreateObject<int>(ref cid, ref iid, out ar); 
ar.GetNumberOfItems() <--> GetNumberOfArchiveProperties()  // ok

How about of Inheritance:

In COM it does not mean code reuse, it means only that contract associated with an interface is inherited.

The coreclr could have better support for all IUnknown interfaces like a COW. I mean we already have contract for all this, why not to wrap this via optional allocation of new required records and remap pointers for new slot. But anyway, it requires any modifications of this, so... my time -_-

[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("23170F69-40C1-278A-0000-000300010000")]
public interface ISequentialInStream
{
    void Read(...);
}
 
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("23170F69-40C1-278A-0000-000300030000")]
public interface IInStream: ISequentialInStream
{
    void m(...);    // only as offset of position like above. The Read() from base we still can't use
    void Seek(...); // ok 
}

just to think

Undecorate functions from C++ compilers

the develop branch is already contains DLR features, but it's not possible for exported functions from C++ compiler.

i.e.:

#define LIBAPI_CPP  __declspec(dllexport) // will decorated like: ?getSeven@API@UnLib@Conari@r_eg@net@@YAGXZ
                                          // e.g.: unsigned short net::r_eg::Conari::UnLib::API::getSeven(void)
#define LIBAPI  extern "C" __declspec(dllexport) // will undecorated like from C compiler: getSeven()

thus we can't use this like l->?getSeven@API@UnLib@Conari@r_eg@net@@YAGXZ() even if it's possible, it is... omg :)

Currently, we can also use a standard bind methods, like:

l.bind<Func<ushort>>("?getD_Seven@API@UnLib@Conari@r_eg@net@@YAGXZ")();

// or

l.bind(Dynamic.GetMethodInfo(typeof(ushort)), "?getD_Seven@API@UnLib@Conari@r_eg@net@@YAGXZ")
                 .dynamic
                 .Invoke(null, new object[0]);

but it still not useful at all :)

For C++ compiler we can simply tell: export it, as it would be for C compiler i.e.

  • extern "C" __declspec(dllexport)

but of course, this should be from third party code.. so, what to do:

The main problem: the same functions cannot be same from different compilers :(

TODO: just to find already existing solution for mangling names

Then we should provide support for example:

If user wants to call this: net::r_eg::Conari::UnLib::API::getSeven(void)

l.Mangling  = true; // switch of decoration
l.Prefix    = "net::r_eg::Conari::UnLib::API::"; //for all other functions

ushort val  = dll.getSeven<ushort>();  // to call unsigned short getD_Seven(void)
// before calling we should get final name: ?getD_Seven@API@UnLib@Conari@r_eg@net@@YAGXZ
// then simply call

Decoration for a C functions (and C++ if used C linkage):

In a 64-bit environment, functions are not decorated.

- -
__cdecl Underscore character (_) is prefixed to names, except when __cdecl functions that use C linkage are exported.
__stdcall Leading underscore (_) and a trailing at sign (@) followed by the number of bytes in the parameter list in decimal
__fastcall Leading and trailing at signs (@) followed by a decimal number representing the number of bytes in the parameter list
__vectorcall Two trailing at signs (@@) followed by a decimal number of bytes in the parameter list

Speed

For planned v1.3 I implemented new caching of the binding in core provider

test via snet tool (part of regXwild)

x32 library:

Unicode: true
iterations(10000) x average(4)

.... regXwild via Conari (Lambda) - ESS version: ~61ms
.... regXwild via Conari (DLR)- ESS version: ~222ms
.... regXwild via Conari (Lambda) - EXT version: ~58ms
.... regXwild via Conari (DLR) - EXT version: ~218ms

....

x64 library:

.NET version via Conari engine

Unicode: true
iterations(10000) x average(4)

.... regXwild via Conari (Lambda) - ESS version: ~43ms
.... regXwild via Conari (DLR)- ESS version: ~245ms
.... regXwild via Conari (Lambda) - EXT version: ~37ms
.... regXwild via Conari (DLR) - EXT version: ~237ms

#####

The regex engine is much more slower (~30-90sec for 10000 iterations), please wait...


Compiled: true
iterations(10000) x average(4)

.... .NET Regex engine: ~37611ms
.... .NET Regex engine(only as ^match$ like a simple '=='): ~2ms

-------

Compiled: false
iterations(10000) x average(4)

.... .NET Regex engine: ~31034ms
.... .NET Regex engine(only as ^match$ like a simple '=='): < 1ms

Done.

looks good !

old result:

( <= v1.2) +icase [x32] +icase [x64]
regXwild via Conari (Lambda) - ESS ~1032ms ~1418ms
regXwild via Conari (DLR) - ESS ~1238ms ~1609ms
regXwild via Conari (Lambda) - EXT ~1117ms ~1457ms
regXwild via Conari (DLR) - EXT ~1246ms ~1601ms

but I'm not sure about that binding to specific values are correct for all cases. I added new unit-tests and this also looks good, so ...

Currently I implemented this via 0x29 opcode (Calli), and the all arguments should be pushed onto the stack before each calling.
Thus the cached TDyn should be valid for custom values via std. stack

for(int i = 0; i < mParams.Length; ++i) {
    il.Emit(OpCodes.Ldarg, i);
}

Use IProvider.Cache if not, and report about this here.

LoadLibrary/Ex vs Conari. Same memory regions between processes and threads

I had the opportunity to think briefly about this official OS "feature" in the context of the Conari project. Because we must understand this is not really a bug. But it can produce the bugs in user space.

LoadLibrary_Windows_Conari

Problems such as #12 (comment) are possible not only in multithreading but even between third processes.

Because Windows will prevent new loading and return the same handle as for the first loaded module due to used reference count for each trying to load the same module (dll or exe).

However, actual new loading and its new handle is possible when reference count is less than 1. Through Conari this means each decrementing when disposing is processed on implemented ConariL object.

That is, each new instance will increase total reference count by +1 and each disposing will decrease it by -1. Just think about this as for the new/delete rule in C++. WinAPI's Load/Free functions follows this rule too.

And this is what I'm talking about. Conari will not fix this "feature" but it will provide at least some option to configure this behavior.

I just think this is a bad idea to isolate this for all cases.

Anyway, I've already tested draft of the new feature for that "feature". Thus, it was already planned together with 1.4 release. Next week. Comment if you have questions.

Incorrect boolean values from unmanaged code

found problem from https://github.com/3F/regXwild

REGXWILD_API bool searchEss(const tstring& data, const tstring& filter, bool ignoreCase)
{
    core::ESS::AlgorithmEss alg;

    return alg.search(data, filter, ignoreCase);
}

always returns true:

l.DLR.searchEss<bool>(data, filter, false);

seems need to help understand that we want get 1byte of integer type -_-

I will look it tomorrow

Failed loading '...': Check used architecture or existence of file.[Error: 126]

Describe the bug
I have a net5 wpf x32 program that references a dynamic link library where a function opens a dialog box with the current program as its owner, the first call without any problems, but when the dynamic library is re-instantiated later and the call throws an exception like the title
What code is involved

image

Expected behavior

Screenshots

Unmanaged EmitCalli and netstandard2.0

In #12 I already mentioned about the main problem for netstandard2.0. And this is what I'm talking about:

An unmanaged EmitCalli is available only with netcoreapp2.1+ https://github.com/dotnet/corefx/issues/9800

But System.Reflection.Emit.ILGeneration is just metadata while mscorlib/src/System/Reflection/Emit/DynamicILGenerator implements this since dotnet/coreclr#16546

See System.Private.CoreLib.dll

More probably we can try inject this logic at runtime o_O Or does exist something related? Cecil is extra cost for just single EmitCalli <_<

The type or namespace name 'DotNet' does not exist

error CS0234: The type or namespace name 'DotNet' does not exist in the namespace 'net.r_eg' (are you missing an assembly reference?)

using net.r_eg.DotNet.System.Reflection.Emit
namespace not found. some module is missing from the Conari-master package

How to properly use the "NativeStruct" from current Conari Version?

In your video: https://www.youtube.com/watch?v=QXMj9-8XJnY

you used the obsolete-way with UnmanagedStructure, now you suggest using the NativeStruct way, can u maybe give me a short example of how to make use of those properly, to be able to call it from C++/Delphi?

Because, when i compile the following code:
image

I get the error you can see in the "Error-dialogbox" below in the screenshot.

How to adapt to that new change you have done for Conari?

Much thanks!

logo

just noticed :) maybe this variant will be better:

continued thoughts ... like:

conari_v1

sketch ==>

_conari_logo_test nyaaaa :)

anyway, not important of course, just drawing a some logo
and yes, need to redraw ugly strong borders of image and very dark spiral

The BreakPionts Not Work

Help me!The BreakPionts Not Work!

This my code:
using (var conariL = new ConariL(@".\x64\libcurl-x64.dll"))
{
var curl = conariL.DLR.curl_easy_init();
conariL.DLR.curl_easy_setopt(curl, 10002, "http://www.baidu.com");
var res = conariL.DLR.curl_easy_perform(curl);
}

Failed loading '...': Check used architecture or existence of file.[Error: 193]

Failed loading '...': Check used architecture or existence of file.[Error: 193]

Details

Error 193 (0xC1)

ERROR_BAD_EXE_FORMAT

    193 (0xC1)
    %1 is not a valid Win32 application.

How to fix

Probably you need to check Target Platform of your project.

The Any CPU (?) will give a 64bit pointers for x64 system and 32bit pointers for x32 system (except for anycpu32bitpreferred when your application runs in 32-bit mode on systems that support both 64-bit and 32-bit).

So how about to check library, that you want to load ?

The Conari supports x32 & x64 architecture, leaving the choice to you. Thus, to select compatible for library that's should be loaded for your project:

  • Properties - Build - Platform target:

_err193

File Not Found

2019-06-30_9-40-28

my code is just

MessageBox.Show(typeof(ConariL).FullName);

.Net Target: 4.5

ExVar.getVar returning wrong value

Hello,

I have a C# function that is getting invoked from a C++ executable. In this function, I am attempting to do the literal equivalent of

int number;
std::cin >> number;

Obviously I could do something like number = int.Parse(Console.ReadLine()), but in this case I really need to do exactly what C++ is doing (and besides, what fun would that be?). Leveraging a decompiler to get the exact mangled names, I came up with this code:

            int number= 0;
            using (var l = new ConariL(@"c:\windows\system32\MSVCP140.dll"))
            {                
                var cin = l.ExVar.getVar<IntPtr>("?cin@std@@3V?$basic_istream@DU?$char_traits@D@std@@@1@A");
                
                l.bind<FuncOut2<IntPtr, int, IntPtr>>("??5?$basic_istream@DU?$char_traits@D@std@@@std@@QEAAAEAV01@AEAH@Z").Invoke(cin, out number);
            }

The function binding works correctly, but it throws an access violation inside of the function because the address of cin is incorrect. The intptr returned by getVar is 0x00007ffe2a0cc110, which the Visual Studio debugger tells me is the address of std::basic_istream<char,std::char_traits<char>>:: vbtable', not of std::basic_istream<char,std::char_traits<char>> std::cin. Indeed, if I put std::cout << &(std::cin); in the C++ app, it outputs 00007FFE2A0F7200, which Visual Studio agrees is correct.

If I force 00007FFE2A0F7200 into my cin variable instead of getting it with getVar, the function executes correctly, prompting for user input and storing it in number.

Aliases for exported-functions and variables

hmm, just thought that is a good additional variant for: Undecorate functions from C++ compilers #3

Moreover, it will be useful for any other cases like for DllImport

[PrefixL]procName -> [PrefixR]alias1
                  -> [PrefixR]alias2

where PrefixL/R it's a main IProvider.Prefix if used
etc.

TODO

Work with Native C/C++ structures without declaration

I want a more flexible using of native C/C++ complex types (like a struct), without additional declarations.
it would be nice to avoid some re-declaration of the same equivalents from C++ to C#

we can also skip some declaration if this required only inside unmanaged code, i.e.:

IntPtr codec; // we will store pointer to AVCodec struct
IntPtr context = IntPtr.Zero; // we will store pointer to AVCodecContext struct

l.bind<Action>("avcodec_register_all")();
codec   = l.bind<Func<int, IntPtr>>("avcodec_find_encoder")(AV_CODEC_ID_MP3);
context = l.bind<Func<IntPtr, IntPtr>>("avcodec_alloc_context3")(codec); // pass allocated AVCodec* to avcodec_alloc_context3
...

but if we need to work with the context above, we also should declare this type (see AVCodecContext in avcodec.h) and finally marshal it:

AVCodecContext context = (AVCodecContext)Marshal.PtrToStructure(ptr, typeof(AVCodecContext));

even if it all will be encapsulated by layer of upper level... just not so cool :)

However, we cannot provide this automatically, because final data does not have any markers of data etc.
Just byte-sequence, because the main idea it's headers, for example:

struct Spec
{
    int a;
    int b;
    Spec2* m;
};
~0x0572b018
-----------
[0]  | 0x05     <<< 4 bytes of integer type, value is 5 from a of struct Spec
[1]  | 0x00
[2]  | 0x00
[3]  | 0x00   ^
[4]  | 0x07     <<< 4 bytes of integer type, value is 7 from b of struct Spec
[5]  | 0x00
[6]  | 0x00
[7]  | 0x00   ^
[8]  | 0xd8     <<< 4 bytes of integer type, value is a pointer to struct Spec2
[9]  | 0xb1
[10] | 0x72
[11] | 0x05   ^
[12] | 0xfd
[13] | 0xfd
[14] | 0xfd
[15] | 0xfd
...

so, how about to define it automatically by size of types ? We can't detect what types are present in this sequences, but for work with complex native types, we can simply like a:

var c = get(context, int, int, long) as AVCodecContext;

c["sample_rate"]  = 44100;
c["channels"]     = 2;
c["bit_rate"]     = 64000;
...
ret = l.bind<FuncRef4<AVCodecContext, AVPacket, AVFrame, int, int>>("avcodec_encode_audio2")(c, pkt, frame, ref output);

the order-sensitive is similar for Marshal.PtrToStructure - not so good for both :)

need to think...

Support of .NET libraries

It probably should be useful features for work without domains and their common problems with unloading assemblies.

So main idea (noticed here 3F/DllExport#9) to provide unified work with managed and unmanaged code via lightweight bridge.

using(var l = new ConariL("managed_net_lib.dll")) {
    // any convenient work via Bridge & dynamic API layer
}
// fully unloaded !

Basic example is a https://github.com/3F/vsSolutionBuildEvent

where Provider in the role of the binder between API & main core:

But do not forget about ~ access security and partially-trusted code, etc.

I don't think about fully compatible way, but the any useful bridge, like in example above, this is what we need...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.