May 01, 2024, 02:18:41 AM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


Can you use an exe made in C with an exe in IWB?

Started by Andy, June 11, 2016, 06:37:58 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Andy

What's the reason for the question?

Well, on the quest of the holy grail of very large number in IWB (I've still not quite given up on them), I was thinking C can handle them.

I could easily save the string number to a file, or via the registry, which the C program could read, and vice versa.

So, if I could pass a string "123454567789908877665443" to a C exe file,  I should be able to convert in to a large number in C.

Once I've done that, I could add, subtract, etc to that number.

I would of course have to pass that number back as a string to an IWB exe, but it would give a usable large number function for IWB which would be quick.

Does anyone think this is possible?

Does anyone here program in C as well?

If so, what is a good free IDE with integrated C compiler?

I had a look at MS Visual Studio, but not sure what I should install during setup - plus it wanted to use 10Gb of disk space - any good FREE alternatives anyone?

Thanks,
Andy.
:)


Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

Egil

QuoteI had a look at MS Visual Studio, but not sure what I should install during setup - plus it wanted to use 10Gb of disk space - any good FREE alternatives anyone?

Pelles C is free (and that's all I know about it....): http://www.smorgasbordet.com/pellesc/

I don't quite understand why it is impossible do the same in IWB as with C. But why not use C or C++ to make a DLL or LIB file containing a function that returns the answer you want as a string, and print it using the routines you already have?


Egil
Support Amateur Radio  -  Have a ham  for dinner!

jalih

Hi,

As an old OS/2 user, I would probably use REXX to handle big numbers.  It's easy and requires only a little shared library to be bundled with your program. I can write  simple example, if you are interested.

Egil

June 12, 2016, 01:45:51 AM #3 Last Edit: June 12, 2016, 01:52:54 AM by Egil
jalih,

A few years ago I visited a large data center to see how data collected from "my" sensors was used. Think  they used REXX in connection with their IBM computers.
Did not know that it also  could be used with ordinary pcs.  Do you know where to get that library and any documentation from?
And a small example would be very welcome.


Egil


EDIT:  Is this the package you mean?   http://rexxtk.sourceforge.net
Support Amateur Radio  -  Have a ham  for dinner!

jalih

Quote from: Egil on June 12, 2016, 01:45:51 AM
Do you know where to get that library and any documentation from?
And a small example would be very welcome.

EDIT:  Is this the package you mean?   http://rexxtk.sourceforge.net

You should probably get OOREXX, Regina REXX or r4 REXX. OS/2 has REXX support by default and some excellent tools available like VX-REXX, gpfREXX and VisPRO REXX.

I will try to find some time to write a demo program.

Egil

Support Amateur Radio  -  Have a ham  for dinner!

Andy

Jalih,

Yes, I would be very interested if you could find the time and post an example program - that could prove very useful.

Thanks,
Andy.
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

Andy

June 12, 2016, 05:59:33 AM #7 Last Edit: June 12, 2016, 06:21:23 AM by Andy
This is what I've got so far...

Created a dll called MyDll.dll in C  (accepts two INT numbers, a, b,  and returns a * b) which states has been created in Pelles C.

Question 1 - in IWB, do I now create a project or single file?

Question 2 - creating import library
The help file says you can import a dll and it creates a lib file, and moves it to the Libs folder.

All I get is "Error creating import library"

Providing I get around this, how do I pass two numbers to the C library?

Here is the C code Part 1


; This file was generated by the Win32 DLL Wizard.

; Syntax:
;
; NAME [appname]
; LIBRARY [libname]
; BASE address
; DESCRIPTION "text"
; STACKSIZE reserve[,commit]
; HEAPSIZE reserve[,commit]
; SECTIONS
;     name [{EXECUTE|READ|WRITE|SHARED}]
; EXPORTS
;     entryname[=internalname] [@ordinal] [DATA]
; VERSION major[.minor]

LIBRARY "MyDll"

EXPORTS
; TODO: Add your exports here!
"MyExportFunction"=_SampleFunction@8


C code Part 2:


/****************************************************************************
*                                                                          *
* File    : dllmain.c                                                      *
*                                                                          *
* Purpose : Generic Win32 Dynamic Link Library (DLL).                      *
*                                                                          *
* History : Date      Reason                                               *
*           00/00/00  Created                                              *
*                                                                          *
****************************************************************************/

#define WIN32_LEAN_AND_MEAN  /* speed up */
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <tchar.h>

#include "MYDLL.h"

/****************************************************************************
*                                                                          *
* Function: DllMain                                                        *
*                                                                          *
* Purpose : DLL entry and exit procedure.                                  *
*                                                                          *
* History : Date      Reason                                               *
*           00/00/00  Created                                              *
*                                                                          *
****************************************************************************/

BOOL APIENTRY DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            /*
             * Microsoft says:
             *
             * The DLL is being loaded into the virtual address space of the current
             * process as a result of the process starting up or as a result of a call
             * to LoadLibrary. DLLs can use this opportunity to initialize any instance
             * data or to use the TlsAlloc function to allocate a thread local storage
             * (TLS) index.
             */
            break;

        case DLL_THREAD_ATTACH:
            /*
             * Microsoft says:
             *
             * The current process is creating a new thread. When this occurs, the system
             * calls the entry-point function of all DLLs currently attached to the process.
             * The call is made in the context of the new thread. DLLs can use this opportunity
             * to initialize a TLS slot for the thread. A thread calling the DLL entry-point
             * function with DLL_PROCESS_ATTACH does not call the DLL entry-point function
             * with DLL_THREAD_ATTACH.
             *
             * Note that a DLL's entry-point function is called with this value only by threads
             * created after the DLL is loaded by the process. When a DLL is loaded using
             * LoadLibrary, existing threads do not call the entry-point function of the newly
             * loaded DLL.
             */
            break;

        case DLL_THREAD_DETACH:
            /*
             * Microsoft says:
             *
             * A thread is exiting cleanly. If the DLL has stored a pointer to allocated memory
             * in a TLS slot, it should use this opportunity to free the memory. The system calls
             * the entry-point function of all currently loaded DLLs with this value. The call
             * is made in the context of the exiting thread.
             */
            break;

        case DLL_PROCESS_DETACH:
            /*
             * Microsoft says:
             *
             * The DLL is being unloaded from the virtual address space of the calling process as
             * a result of unsuccessfully loading the DLL, termination of the process, or a call
             * to FreeLibrary. The DLL can use this opportunity to call the TlsFree function to
             * free any TLS indices allocated by using TlsAlloc and to free any thread local data.
             *
             * Note that the thread that receives the DLL_PROCESS_DETACH notification is not
             * necessarily the same thread that received the DLL_PROCESS_ATTACH notification.
             */
            break;
    }

    /* Return success */
    return TRUE;
}

/****************************************************************************
*                                                                          *
* Function: SampleFunction                                                 *
*                                                                          *
* Purpose : Sample function which does nothing useful.                     *
*                                                                          *
* History : Date      Reason                                               *
*           00/00/00  Created                                              *
*                                                                          *
****************************************************************************/

int WINAPI SampleFunction(int a, int b)
{
    /* TODO: Replace with your own code */
    return a * b;
}


And my attempt in IWB to use the library file:


'$use "C:\\win10\\MyDll.lib"

$main

declare extern __imp_SampleFunction@8(int aa,int bb),int

openconsole

int x,y

x = 10
y = 10

print __imp_SampleFunction(x,y)

do:until inkey$ <> ""
end


Clearly I've got things wrong here - can anyone shed any light on what I should do and why I cannot create a lib file for it?

Attached is the C dll file.

Thanks,
Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

Egil

I have only tried making a DLL once, in EB. Got a similar error message when trying to to make a LIB file, it turned out that I forgot to make an EXPORT statement before compiling the DLL.


Egil
Support Amateur Radio  -  Have a ham  for dinner!

LarryMc

I know nothing about 'c' but I do know this.

Until you get around this error
"Error creating import library"
anything else you try to do is moot.

I did remember something from years ago about c-compilers mangling function names and different compilers mangle different ways and to get around it you have to call the function(inside the c program) with  __declspec(dllexport)

so, once you get the get the above error resolved and get a clean import lib

then you have to figure out how you declare the function in your program(whether or not you have you use CDECL or not)

and you don't have to create a project to be able to use your import lib, you can use a single file exe.

that's about all I can offer in the way of help.
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

Thanks Larry,

Yes, I have to find a way to import the library first, everything else is academic until I can do that.

Maybe this is a bridge too far for me....

These are the days when you miss Sapero.

Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

jalih

Below is a simple example for IWBasic calling REXX to multiply two very large numbers. To compile, copy import lib into IWBasic libs folder or use IDE to create import library from regina.dll.

example program

Have fun!

Andy

Jalih,

I'm impressed with this!

Can you explain how it multiplies the two numbers, do I modify these lines?

const RXFUNCTION = 2
rc = RexxStart(2, &parameter, &name, &program, &environment, RXFUNCTION, 0, &rc15, &result)

Or do you actually need to create something in regina rex?

If so, could you post it so I can see it?

There is so much documentation with this (which is good), but it would take me weeks to read through it.

Thanks,
Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

jalih

Quote from: Andy on June 13, 2016, 11:46:12 PM
Can you explain how it multiplies the two numbers, do I modify these lines?

const RXFUNCTION = 2
rc = RexxStart(2, &parameter, &name, &program, &environment, RXFUNCTION, 0, &rc15, &result)

Or do you actually need to create something in regina rex?

RexxStart function actually calls REXX interpreter.  Now, it's given two arguments A1 and A2 these are RXSTRINGS. Program array has the rexx code as RXSTRINGS, array index 0 has textual version and array index 1 will get tokenized version. In my example statements string is the rexx function that will be passed for REXX interpreter: It parses two arguments as x and y and returns them multiplied together.

Andy


That's very useful Jalih, thank you for that.

But I have a question, how do I send the result to a string rather than just printing it?

$USE "regina.lib"

declare import,RexxStart(ArgCount as int, ArgArray as pointer, Name as pointer, Instore as pointer, Environment as pointer, CallType as int, ExitHandler as pointer, Rc as pointer, Result as pointer), int
DECLARE Import,GlobalFree(x as int), int


type RXSTRING
int length
pointer address
endtype

dim parameter[2] as RXSTRING
dim result as RXSTRING

dim rc15 as sword
dim rc as int

dim program[2] as RXSTRING

string name = "GIGANTIC"
string environment = "MINE"
string statements = "parse arg x, y; numeric digits 100; return x * y"

string A1 = "123456789012345678901234"
string A2 = "123456789012345678901234"

program[0].length = len(statements)
program[0].address = &statements
program[1].length = 0
program[1].address = 0

parameter[0].length = len(A1)
parameter[0].address = &A1
parameter[1].length = len(A2)
parameter[1].address = &A2

result.length = 0
result.address = 0

const RXFUNCTION = 2
rc = RexxStart(2, &parameter, &name, &program, &environment, RXFUNCTION, 0, &rc15, &result)

GlobalFree(program[1].address)
program[1].length = 0


openconsole
print string(result.address)

GlobalFree(result.address)
result.length = 0


do:until inkey$ <> ""
closeconsole
end


I mean this line:
print string(result.address)

Thanks,
Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

jalih

Quote from: Andy on June 14, 2016, 08:06:19 AM
I mean this line:
print string(result.address)

You can pass a default string buffer for result. If result is too large to fit inside default buffer then REXX allocates new buffer for the result. It's always smart to check that default buffer address is the same as result.address.


$USE "regina.lib"

declare import, RexxStart(ArgCount as int, ArgArray as pointer, Name as pointer, Instore as pointer, Environment as pointer, CallType as int, ExitHandler as pointer, Rc as pointer, Result as pointer), int
DECLARE Import, GlobalFree(x as int), int

type RXSTRING
int length
pointer address
endtype

dim parameter[2] as RXSTRING
dim result as RXSTRING

dim rc15 as sword
dim rc as int

dim program[2] as RXSTRING

string name = "GIGANTIC"
string environment = "MINE"
string statements = "parse arg x, y; numeric digits 100; return x * y"

string A1 = "12345678901234567890"
string A2 = "12345678901234567890"

program[0].length = len(statements)
program[0].address = &statements
program[1].length = 0
program[1].address = 0

parameter[0].length = len(A1)
parameter[0].address = &A1
parameter[1].length = len(A2)
parameter[1].address = &A2

string standard_result
result.length = 255
result.address = &standard_result

const RXFUNCTION = 2
rc = RexxStart(2, &parameter, &name, &program, &environment, RXFUNCTION, 0, &rc15, &result)

GlobalFree(program[1].address)
program[1].length = 0

If &standard_result = result.address then
print standard_result
else
print string(result.address)
GlobalFree(result.address)
result.length = 255
result.address = &standard_result
end if

do:until inkey$ <> ""

Andy

Jalih,

Thanks, that's great!

But if you use rex you will still need to bundle the rex dll with any exe file you create otherwise the program will produce an error - am I correct?

Thanks,
Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

Quote from: Andy on June 14, 2016, 11:37:44 PM

But if you use rex you will still need to bundle the rex dll with any exe file you create otherwise the program will produce an error - am I correct?
that is correct
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library