3D Rad - Free 3D game maker - Forum

This forum is now archived!

This forum is locked, and is a read-only version. A new community-ran forum can be found at classdev.net

News:

The 3DRad community can be found at classdev.net.

Pages: [1] 2

Author Topic: Bridging from 3D Rad to 3rd Party Dll's  (Read 5849 times)

jestermon

« on: May 25, 2010, 08:01:03 PM »
I've seen a lot of questions in the forums regarding using 3rd party dll's to extend the functionality of 3d Rad.

Since I'm on a c++ writing spree for a change, I thought I'd knock up a little demo in hopes that it may help.

The idea is to write a dll that acts as a bridge between 3D Rad, and the 3rd party dll, and wrap the 3rd party dll in your own dll, and then use a script to wrap your own dll... hope this makes sense..

Anyway, here's some sample code

A 3D Rad sample script

Code: [Select]
//Example project for setting up a dll bridge call to another dll

//global dll handle
int DLLHandle = 0;

//------------------------------------------
//return the ascii value of a character
int ascii(string s)
{
   string ASCIISET = " !'#$%&`(*+'-./0123456789;:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[/]^_'abcdefghijklmnopqrstuvwxyz{|}~";
   int p = iStringFind(ASCIISET,s,0,true);
   return p+32;
}

//------------------------------------------
//set string in dll
void DllSetString(string txt)
{
   int i, asc;
   string s;
   for(i=0;i<iStringLen(txt);i++)
   {
      iStringMid(s,txt,i+1,1);
      asc = ascii(s);
      iDLLArraySet(i,asc);
   }
   iDLLArraySet(iStringLen(txt),0); //null terminate string
   iDLLCall(DLLHandle,"SetString",0);
}

//------------------------------------------
//set int in dll
void DllSetInt(int n)
{
   iDLLArraySet(n,0);
   iDLLCall(DLLHandle,"SetInt",0);
}

//------------------------------------------
//get string from dll
string DllGetString()
{
   int i;
   string str="";
   float f;
   bool done = false;
   i=0;
   while(!done)
   {
      f=iDLLArrayGet(i);
      i++;
      if(f != 0)
      {
         str+=" ";
         str[i] = f;
      }
      else
         break;
      if(i>1000) break;  //limit release
   }
   return str;
}

//------------------------------------------
void DllDosomething()
{
      iDLLCall(DLLHandle,"ExecSomething",0);
}

//========================================
void Main()
{

   if (iInitializing())
   {
      DLLHandle = iDLLLoad(".\\3DRad_res\\objects\\Script\\raddllbridge.dll");
      if (DLLHandle != 0)
      {
         string txt = "This is some text to write to a file";
         int len = iStringLen(txt);
         DllSetString(txt);
         DllSetInt(len);
         DllDosomething();
      }
   }
   else if (iDeinitializing())
   {
      if (DLLHandle != 0) iDLLUnload(DLLHandle);
   }
}


A sample 3d Rad wrapper dll in c

Code: [Select]
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

//reference to function in worker dll (remember to set the lib/a link)
extern int DoSomething(char* name,int length);

//3D Rad dll wrapper for DoSomething function above
__declspec(dllexport) void ExecSomething(float* myData);

//export for 3D Rad dll calls
__declspec(dllexport) void SetString(float* myData);
__declspec(dllexport) void GetString(float* myData);
__declspec(dllexport) void SetInt(float* myData);
__declspec(dllexport) void getInt(float* myData);
__declspec(dllexport) void SetFloat(float* myData);
__declspec(dllexport) void GetFloat(float* myData);
__declspec(dllexport) void SetChar(float* myData);
__declspec(dllexport) void GetChar(float* myData);

char bridgeStr[1000];
float bridgeF;
int bridgeI;
char bridgeC;

//----------------------------------------
//Accepts float array from 3D Rad, and stores it as a char array
void SetString(float* myData)
{
   int i;
   char c;
   for(i=0;i<1000;i++)
      bridgeStr[i]=0;
   for(i=0;i<1000;i++){
      c = myData[i];
      if(c)
         bridgeStr[i]=c;
      else
         break;
   }
}

//----------------------------------------
//returns a char array as a float array to 3D Rad
void GetString(float* myData)
{
   int i,L;
   char c;
   L = strlen(bridgeStr);
   for(i=0;i<L;i++){
      c = bridgeStr[i];
      myData[i] = c;
   }
   myData[L]=0;
}

//----------------------------------------
void SetInt(float* myData)
{
   bridgeI = myData[0];
}

//----------------------------------------
void GetInt(float* myData)
{
   myData[0] = bridgeI;
}

//----------------------------------------
void SetFloat(float* myData)
{
   bridgeF = myData[0];
}

//----------------------------------------
void GetFloat(float* myData)
{
   myData[0] = bridgeF;
}

//----------------------------------------
void SetChar(float* myData)
{
   bridgeC = myData[0];
}

//----------------------------------------
void GetChar(float* myData)
{
   myData[0] = bridgeC;
}

//----------------------------------------
void ExecSomething(float* myData)
{
   //int not retuened in this example, but simple
   //to return to 3D Rad with GetInt()
   int res;
   res = DoSomething(bridgeStr,bridgeI);
}


A Sample - Possible 3rd party dll - in c

Code: [Select]
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

__declspec(dllexport) int DoSomething(char* name,int length);

int DoSomething(char* name,int length)
{
   FILE *fp;
   fp = fopen("test.dat","w");
   fprintf(fp,"I received %s,%d\n",name,length);
   fclose(fp);
   return 0;
}

« Reply #1 on: May 25, 2010, 10:20:01 PM »
Now that's code, and some! 8)

I've been looking for some good 3DRad/DLL examples.......this does it for me!

Thanks a lot, jestermon!
AKA: The 3D Raddict http://www.3draddict.com/

jestermon

« Reply #2 on: May 26, 2010, 07:03:55 AM »
Now that's code, and some! 8)

I've been looking for some good 3DRad/DLL examples.......this does it for me!

Thanks a lot, jestermon!

Thanks Allan. Always a pleasure.
« Reply #3 on: May 26, 2010, 08:00:59 AM »
I will try on weekends. thank for your efforts
« Reply #4 on: August 01, 2010, 06:53:15 AM »
thanks a lot!
« Reply #5 on: August 01, 2010, 07:36:45 AM »
i wrote this function in PUREBASIC but 3drad crashes on your script

Code: [Select]
ProcedureDLL SetString(Array strfloat.f(1))

i.i
c.c
bstr.s

For i = 1 To 1000
c = strfloat(i)
If c
bstr = bstr + Str(c)
Else
Break
EndIf
Next

MessageRequester("string",bstr,#PB_MessageRequester_Ok)

EndProcedure

jestermon

« Reply #6 on: August 01, 2010, 08:34:12 AM »
The dll is meant to be a template example for C/C++ developers who wish to write dll's to be used with Rad. I have no idea how to use PureBasic. But I recall from VB that you need to pass and array "by reference" to pass an array pointer..

In the c code, this is what is happening.

Code: [Select]
   for(i=0;i<1000;i++){   //loop
      c = myData[i];         //Get the float and convert to an ascii char (built in c->ascii conversion)
      if(c)                        //if c is not 0 (a NULL)
         bridgeStr[i]=c;     //place the ascii character in the string offser
      else                       //if the ascii character is a NULL, this is the end of the string
         break;                //so stop getting the info
    }

So you need to duplicate this process and logic  exactly (ascii conversion is not so obvious. And checking for a valid character value (not NULL) is a specific c logic shortcut )
« Last Edit: August 01, 2010, 08:38:03 AM by jestermon »
« Reply #7 on: August 03, 2010, 01:25:40 AM »
i understand what is happening as i am selfstudying c++
but the thing is that i dont know how to pass a float array to purebasic dll procedure.. i have tried sth from the docs but 3drad crashes...
so i am gonna try to write a c++ dll that converts c-style pointer-based string to c++ STL string type... hope that works...
==============================

edit: used LPSTR instead of std::string

adapted your setstring function ,, works perfectly when tested with host c++ application

tried it in RAD .. rad crashes,, can you see the atachment and tel me why?
« Last Edit: August 03, 2010, 05:12:44 AM by mohdumar »

jestermon

« Reply #8 on: August 03, 2010, 08:57:59 AM »
Hi mohdumar,
It's always great to learn new stuff, and expand one's knowledge in any arena.
I don't mind helping out with questions directly related to 3D Rad, since this is a technical support forum.

I also don't mind helping out on any tools that I personally post this forum, in the hope of adding something useful to the Rad community, and fixing any latent bugs.

However ..Direct support for dll addons made by other members, falls outside my scope of involvement. I don't mind making small suggestions where I can help, but investigating code that is anything other that a 3D Rad script, is off topic, and should be discussed in other forums dedicated to those specific languages.

Keep on learning though, and get all your nuts and bolts in place. I don't mind being "dethroned" as the "dll queen" (as shadmar calls me). There are some great c/c++ developers in this forum, and you will be very welcome among them.
« Last Edit: August 03, 2010, 09:03:07 AM by jestermon »
« Reply #9 on: August 04, 2010, 04:42:35 AM »
the problem is RAD CRASING? ?? ??

jestermon

« Reply #10 on: August 04, 2010, 10:53:19 AM »
If Rad does not crash before you use your dll, and it crashes WHEN you use your dll, then logic dictates that there is a problem with the dll, and not with Rad. I have posted many dll examples.. but I cannot help you with personal coding problems.. sorry.

Edit:
After looking at your code, just out of curiosity as to why you get the crash, I can only repeat my statement.. I don't have the time to fix other people's bugs.
However I have a very useful suggestion that can help solve a lot of problems.

1.. Write a normal exe that calls a 3rd party dll, to make sure that your code works
2.. Move the working code into a dll project, and remove the main() function
3.. Write another exe to test your own new dll
4.. Use the tested working copy of your dll with Rad

If you follow these simple steps, then you know for sure that you have a stable dll that wont crash anything.

Edit2: Since this problem relates to text to speech, I actually created a working dll, with the script to call it. You will notice that I used the linked version of sapi in that project, so that I did not have to worry directly about 3rd party dll's
With c/c++ this is always the better option if it is available, since you have less files to distribute, and less things that can go wrong.
http://www.3drad.com/forum/index.php?topic=4960.msg41196#msg41196
« Last Edit: August 04, 2010, 10:39:11 PM by jestermon »
« Reply #11 on: August 06, 2010, 06:51:08 AM »
how about i write a exe that calls a dll and then run the exe in 3drad?

jestermon

« Reply #12 on: August 06, 2010, 12:25:39 PM »
how about i write a exe that calls a dll and then run the exe in 3drad?
That way you can pass command line parameters to the .exe . You will need some other method of getting data beck from the dll to Rad though. A text file or some other storage could work for that. It wont be as fast as a direct bridge, but it can do the job.
« Reply #13 on: September 19, 2010, 12:13:37 AM »
Hi Jestermon ! Really nice work !
If i understand correctly, we need to insert some code into the ExecSomething procedure to call the dosomething.dll ?

jestermon

« Reply #14 on: September 19, 2010, 03:08:00 AM »
Hi Jestermon ! Really nice work !
If i understand correctly, we need to insert some code into the ExecSomething procedure to call the dosomething.dll ?
What you would do is create a "bridge" function for every function in the 3rd party dll, in order to wrap it and be able to call it from the script.

So, yes, you need to add some "dll-calling" code inside the function.

Edit: Corrected.
« Last Edit: September 19, 2010, 10:13:24 PM by jestermon »
Pages: [1] 2