error in wiki documentation + communication for ISXDK + .NET

Discussion of Inner Space

Moderators: Lavish Software Team, Moderators

Post Reply
Evilfairy
GamingTools Subscriber
Posts: 7
Joined: Sat Jun 22, 2013 9:24 am

error in wiki documentation + communication for ISXDK + .NET

Post by Evilfairy » Sat Jul 06, 2013 10:28 am

Sorry in advance, this post turned out quite a lot longer than I'd hoped... if there's some other support channel I should be contacting you through (or if I should just be posting less) please let me know

I was reading through the wiki while trying to figure out how to communicate with my ISXDK extension from my hosted .NET application and I noticed this example on exposing API: http://www.lavishsoft.com/wiki/index.ph ... ap#Example

As you can see in the first function it reads

Code: Select all

static void * __stdcall GetAPI(const char *Name, unsigned int Version)
	{
		static map<string,void*> APIMap;
		static bool bInitialized=false;
		/* initialize map */
		if &#40;!bInitialized&#41;
		&#123;
			APIMap["Echo"]=Echo;

			bInitialized=true;
		&#125;

 		/* map has been initialized, retrieve function */
		map<string,void*>&#58;&#58;iterator i=APIMap.find&#40;Name&#41;;
		if &#40;i==APIMap.end&#40;&#41;&#41;
			return 0;
		return i->second;
	&#125;
notice how the definitions for APIMap and bInitialized are declared and assigned inside the function; wouldn't that mean that "if(!bInitialized)" is essentially "if(true)". Should they be declared outside of the function or am I misunderstanding something fundamental?

I also noticed a minor typo in the comment at the top of http://www.lavishsoft.com/wiki/index.ph ... API_layout

Second question is how to actually communicate: My situation is as follows

1. I have the DX application with my ISXDK extension loaded
2. I also want to host a seperate .NET application within the context of the DX app
3. I need to transfer data between the ISXDK and .NET extensions and preferably be able to call functions between them as well

My understanding is that I can either use TLOs or I can expose API; I couldn't find any other ways of communicating except maybe by calling LavishScript commands registered by my ISXDK extension and getting the ToString result (which might not even work, I haven't looked into that heavily because it seems very messy)

Additionally, while researching how to create a custom TLO and transfer data from ISXDK to my .NET app via the TLO, I struggled to find a way to actually get the data I wanted

The data I'm trying to access is a byte[40] located in my ISXDK extension

Running unsafe code is not a problem for me, I don't mind directly accessing memory but I just couldn't figure out how to do it. I tried having the TLO in ISXDK return a pBytePtrType which in Initialize is defined as

Code: Select all

pBytePtrType=pISInterface->FindLSType&#40;"byteptr"&#41;;
but then I couldn't figure out how to access it from my C# application. GetObject().GetValue<IntPtr>(); throws an InvalidCastException as seen here: Image

The code I use (after verifying the TLO) is as follows:

Code: Select all

LavishVMAPI.Frame.Lock&#40;&#41;;
                byte[] key = new byte[40];
                StringBuilder sb = new StringBuilder&#40;&#41;;
                LavishScriptObject ob = LavishScript.Objects.GetObject&#40;"MyTLO"&#41;;
                IntPtr keyAddr = ob.GetValue<IntPtr>&#40;&#41;;
                for &#40;int i = 0; i < 39; ++i&#41;
                &#123;
                    key[i] = Marshal.ReadByte&#40;keyAddr + i&#41;;
                    sb.Append&#40;String.Format&#40;"&#123;0&#58;x&#125; ", key[i]&#41;&#41;;
                &#125;
                InnerSpace.Echo&#40;"Key&#58; " + sb.ToString&#40;&#41;&#41;;
                LavishVMAPI.Frame.Unlock&#40;&#41;;
Changing

Code: Select all

ob.GetValue<IntPtr>&#40;&#41;;
to

Code: Select all

ob.GetValue<String>&#40;&#41;;
and printing it out in a messagebox displays the text "18" which makes me wonder if something is wrong with my ISXDK code, but even if it is that's not the problem I'm having

An alternative way I found to do it was to simply have my TLO return a byte based on the value I passed to it and then call that 39 times, but that... seems wrong. It also takes a few seconds to execute on my machine and my machine is hardly slow, which makes me worry about performance on lower spec machines. If returning a pointer to the array and then reading the pointer is not what I should be doing, can you tell me what is? The only "array" I found was limited to 4 bytes and I couldn't seem to be able to extend that.

But is using a TLO even the right thing to do? I'm currently looking into using API to get what I want and I _think_ I can just do something like

Code: Select all

// ISXDK
static byte* __stdcall GetKey&#40;&#41;
&#123;
return &keyArray; // byte[40]
&#125;
and then access that as described in http://www.lavishsoft.com/wiki/index.ph ... _Bootstrap but I'm not sure, I'm still looking into that

So seeing as this turned into yet another essay, I suppose my questions would be

1. Is the mistake I pointed out at the top actually a mistake, or am I misunderstanding something fundamental?
2. How should I communicate between my ISXDK extension and my .NET application? the ISXDK ext can run standalone but the .NET application requires the ISXDK ext. I can call custom commands I've registered just fine, but I don't know how to transfer data (e.g. C# requesting the 40 byte array from the ISXDK extension) or how to allow the ISXDK extension to actively message the .NET application (which would be preferred to just, say, looping forever and checking for new messages every 15ms from within the .NET app)
3. Are TLOs the only thing I can access from .NET? From what I understand both from my own research and from what you said to me in my last thread, for most things I should probably be using a data type; I couldn't seem to find how to access those from C#. I'm looking into exposing API as a method of getting data from the ISXDK extension but again, I don't know if that's the right thing to be doing

Finally as I said, if this isn't where I should be asking for help please tell me where I should be; I'm trying my best to keep my questions non-game specific and non-memory (read/write) specific as I understand your primary focus with Inner Space these days seems to be as a multiboxing platform and I'm more interested in the concept of how to do things with IS + extensions than how to do things with specific games. I'm also trying my best to find the answers myself before asking and to test things to see if they work before asking about them so again, feel free to tell me if I should already know the answers to what I'm asking just from source code documentation and/or the wiki

Thank you (:
[/code]

Lax
Owner
Posts: 6634
Joined: Fri Jun 18, 2004 6:08 pm

Post by Lax » Wed Jul 10, 2013 10:26 am

Sorry for the delay in responding here, I have a lot of things I'm working on and this is pretty much a novel ;)

You probably don't need to bootstrap any API directly into .NET. It's much easier to just use LavishScript from .NET.

Alternatively if you're not actually going to use LavishScript in a LavishScript context, you can just write all of the memory access code directly in .NET instead of bothering to write an extension to read it in Native code and then marshal it over to .NET. I'm going to recommend this instead of what you're doing now. As with writing your C++ code, your hosted .NET app is in-process and can directly read or write any of the hosted process's memory...
notice how the definitions for APIMap and bInitialized are declared and assigned inside the function; wouldn't that mean that "if(!bInitialized)" is essentially "if(true)". Should they be declared outside of the function or am I misunderstanding something fundamental?
You're missing something fundamental. The variable is static.
Running unsafe code is not a problem for me, I don't mind directly accessing memory but I just couldn't figure out how to do it. I tried having the TLO in ISXDK return a pBytePtrType which in Initialize is defined as

Code:
pBytePtrType=pISInterface->FindLSType("byteptr");
The reason this type exists is for you to be able to access a single byte of memory in LavishScript land, and retrieve or set its value. .NET land already has this capability...

You're better off just passing a memory address to .NET as an integer, and use .NET to read the memory at the address. Or don't pass it to .NET, make your .NET code get the address instead of an extension.

Evilfairy
GamingTools Subscriber
Posts: 7
Joined: Sat Jun 22, 2013 9:24 am

Post by Evilfairy » Thu Jul 11, 2013 1:18 pm

Lax wrote:Sorry for the delay in responding here, I have a lot of things I'm working on and this is pretty much a novel ;)

You probably don't need to bootstrap any API directly into .NET. It's much easier to just use LavishScript from .NET.

Alternatively if you're not actually going to use LavishScript in a LavishScript context, you can just write all of the memory access code directly in .NET instead of bothering to write an extension to read it in Native code and then marshal it over to .NET. I'm going to recommend this instead of what you're doing now. As with writing your C++ code, your hosted .NET app is in-process and can directly read or write any of the hosted process's memory...
notice how the definitions for APIMap and bInitialized are declared and assigned inside the function; wouldn't that mean that "if(!bInitialized)" is essentially "if(true)". Should they be declared outside of the function or am I misunderstanding something fundamental?
You're missing something fundamental. The variable is static.
Running unsafe code is not a problem for me, I don't mind directly accessing memory but I just couldn't figure out how to do it. I tried having the TLO in ISXDK return a pBytePtrType which in Initialize is defined as

Code:
pBytePtrType=pISInterface->FindLSType("byteptr");
The reason this type exists is for you to be able to access a single byte of memory in LavishScript land, and retrieve or set its value. .NET land already has this capability...

You're better off just passing a memory address to .NET as an integer, and use .NET to read the memory at the address. Or don't pass it to .NET, make your .NET code get the address instead of an extension.
Thank you for replying!

The main reason I am using C++ over .NET is because my C++ application uses inline asm and that looked to be difficult if not impossible to do in .NET (I know about ILasm which is why I figured it would be better to just use C++)

Well I wanted to use LavishScript but the problem I had was with passing this 40 byte array out from my C++ extension to my other components. I couldn't figure out how to do that from LavishScript. My .NET application is in place because the larger project I'm building uses components that are just much easier to do in .NET than in C++, and I'm pretty sure it's not even possible in LavishScript. My ideal setup would be to have:

C++ extension handling memory read/write stuff and offering an API that allows me to interact with the host application. I want to be able to re-use this across applications/scripts so it's nice to be able to keep as much logic as I can here and just return the results

C# application is basically required for what I'm trying to do but I'd also like to be able to interact with the C++ extension in as many ways as possible, whether that's by calling LavishScript or creating APIs doesn't matter too much to me

The application I'm writing is going to use some form of scripting anyway so it'd be great to be able to use LavishScript. The problem I have is that I'd need these scripts to run based on events fired by the C# application (whether those are "true" events or just switch statements doesnt matter). I was originally going to embed a Lua engine to do this but that was when I was trying to stay out of process. Now that I'm using Inner Space and have access to LavishScript, it seems to make sense to just use that, especially seeing as a quick look at LavishScript wiki makes it seem as though event driven code in LavishScript is even more painless than in Qt
You're better off just passing a memory address to .NET as an integer, and use .NET to read the memory at the address.
I knew I was doing something dumb x.x things have been a little stressful for me lately so sorry for missing the obvious

This should work just fine, I'll do this and let you know if I have any problems with it

Again, thanks for your reply; I seriously appreciate both the help on how to do what i'm asking and that you point out alternatives to what I'm doing when it's probably the wrong thing and I should reconsider my methods

I'm still interested in how I'd go about passing something like a 40 byte array to LavishScript though. I won't need this for my application (only the C# component needs it) but it'd be nice to know

Thank you!

Post Reply