Welcome, Guest. Please login or register.

Author Topic: Executing c command in c  (Read 2206 times)

Description:

0 Members and 1 Guest are viewing this topic.

guest11527

  • Guest
Re: Executing c command in c
« Reply #59 from previous page: June 02, 2017, 05:02:30 PM »
Quote from: Thorham;826576
Why not implement simple things like that yourself?
For the OP and the problem at hand, this would make at least a good exercise with a learning experience. It's simple enough, and you'll understand that there is no "magic" going on in the stdlib.

Quote from: Thorham;826576
I usually don't bother with using the C runtime for strings at all. It bloats the executable for a few functions that are all a few lines of C. Furthermore, your own functions can be tailored to your exact needs.
In general, I would advice against this. Not only for the reasons Olaf gave (documentation, portability, readability), but also that some compilers offer compiler built-ins for the most used and most useful functions. SAS/C generates inline assembly code for strlen, strcpy, memset and memcpy. You'll hardly beat that by providing your own implementations. Many other string functions come with assembly language implementations (strcat, memchr, strchr, strrchr and others), so it's typically worth it.

C is of course not very good at string processing anyhow (given that it has no native datatype for strings, this is not a miracle) and other languages can do better by optimizing needless string copies or memory handling away. If you know the data flow in your application, you can certainly avoid some "costly" operations like strcat. E.g. if you know the string length anyhow, a strcpy to the right place will do.

Quote from: Thorham;826576
I would call it a mid level language. Too high level compared to assembly language, and too low level compared to things like C#. Pointers != very low level ;)
Given that we have now interpreted languages like javascript or languages like scala that run on the JVM, C is "pretty low" to me. It's probably the next possible "higher" language if you don't bother touching assembler. (Leaving some exotic intermediate languages like C-- apart).
 

Offline LiveForIt

Re: Executing c command in c
« Reply #60 on: June 02, 2017, 05:41:02 PM »
If wont to copy a string, I normally use

char *strdup(char *)

Because it bundles malloc() and strcpy()

there is also strndup() if you only need a part of a text string, might not be included older C standard lib's.

sprintf is best used for converting or formatting a text.

as for sprintf being unsafe, its only unsafe if don't calculate required buffer size in advanced, and use malloc to create a buffer.
Sure snprintf is safer, but it might be tiny bit slower, because it checks for if at end of buffer.

static buffer like

char mybuffer[33]; might really unsafe, imaging using this for file names, as old FFS files was only 32 chars, it was not a problem, but then newer versions of file systems started to support 128 char names.

It important to know etch function has It's own use, and don't try to make assumptions.

There is also

salloc()

The cool thing about it is that it allocates memory on the stack, so when exit a function, you get memory back with out freeing it, the disadvantage is that stack is predefined on AmigaOS and can't be auto increased, while program is running. so running out stack memory can be real issue.

maybe better to stick to malloc().

There are also AllovVec() and AllocMem() in Exec.library, this most not be mixed with malloc(), and free().
« Last Edit: June 02, 2017, 05:53:34 PM by LiveForIt »
 

guest11527

  • Guest
Re: Executing c command in c
« Reply #61 on: June 02, 2017, 07:12:51 PM »
Quote from: LiveForIt;826595
There is also

salloc()
Unfortunately, that is non-C, non-ANSI, non-POSIX. Linux does not have it either. Gcc suppors "alloca()" which does something similar, and ANSI-C99 has VLAs which do pretty much the same; but even then, support might be flakey as we just found out in another thread. VBCC does not support it correctly, SAS/C not at all.

Worse, as it usually takes memory from the stack, it may overrun the stack easily. With the standard 4K stack on classic Amigas, this just happens too quickly.

One way or another,  I would advise against using it.
 

Offline LiveForIt

Re: Executing c command in c
« Reply #62 on: June 02, 2017, 08:20:05 PM »
ah, its a macro.
« Last Edit: June 02, 2017, 08:32:17 PM by LiveForIt »
 

Offline foleyjoTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 608
    • Show only replies by foleyjo
Re: Executing c command in c
« Reply #63 on: June 02, 2017, 09:24:52 PM »
Apart from the mui specific stuff (Not sure if my question on getting items from a sorted list was missed or if nobody had an answer) my main problems have been strings. I'm used to languages where I don't have to worry about where they are in memory or remembering to have the end string characters. Now I have my head around those I'm getting the desired outputs and not getting any memory related errors.
It's nice to learn a different way of looking at them. I always knew they were arrays of characters but never thought too much about what the functions were actually doing.
 

Offline nyteschayde

  • VIP / Donor - Lifetime Member
  • Hero Member
  • *****
  • Join Date: Mar 2002
  • Posts: 643
    • Show only replies by nyteschayde
    • http://www.nyteshade.com
Re: Executing c command in c
« Reply #64 on: June 03, 2017, 04:44:49 AM »
Somewhat related, I am curious if anybody knows how power packer and similar crunchers work. From what I understand, they compress an executable and attach the compressed binary to program that decompresses and then *executes* the decompressed contents.

There are clearly several things happening here, but ultimately, the code from the cruncher needs to kick off the uncompressed binary. Since the compressed executable contents are attached to the decompressor binary, it would make sense that the binary needs to read itself and extract some code to memory.

My question is how does one execute arbitrary binary from within one's program.
Senior MTS Software Engineer with PayPal
Amigas: A1200T 060/603e PPC • A1200T 060 • A4000D 040 • A3000 (x2) • A2000 Vamp/V2 • A1200 (x4) • A1000 (x3) • A600 Vamp/V1 • A500
 

Offline olsen

Re: Executing c command in c
« Reply #65 on: June 03, 2017, 08:12:38 AM »
Quote from: foleyjo;826602
Apart from the mui specific stuff (Not sure if my question on getting items from a sorted list was missed or if nobody had an answer) my main problems have been strings.
How to use MUI is a subject all by itself. Not everybody who's written Amiga software over the years has used it, or is even sufficiently familiar with it to explain how to get things done. There is more than one way to knit an Amiga user interface. MUI, by virtue of being a framework, is one of the most complex toolboxes you could use.

Quote
I'm used to languages where I don't have to worry about where they are in memory or remembering to have the end string characters. Now I have my head around those I'm getting the desired outputs and not getting any memory related errors.
Now you know why these other languages exist ;)

Quote
It's nice to learn a different way of looking at them. I always knew they were arrays of characters but never thought too much about what the functions were actually doing.
The Amiga, and even the minicomputers, workstations, etc. which came before it, did not have a lot of memory or CPU power to spare. The programs running on these machines had to be very much in control of how memory was spent. There used to be a time when 2 Megabytes of RAM was quite a lot, and 512 Kilobytes was what you had to plan for, because most of your users likely had exactly this much available.

Languages such as Python, JavaScript or even Perl have to perform the same low level memory management operations for strings (among other data structures). The programs running in these interpreters don't have to bother, but the price is in that more memory is needed and more CPU power is needed.
 

Offline foleyjoTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 608
    • Show only replies by foleyjo
Re: Executing c command in c
« Reply #66 on: June 03, 2017, 08:41:30 AM »
I think I might change from mui to reaction. I have more of an understanding of how things are working now.
 

Offline olsen

Re: Executing c command in c
« Reply #67 on: June 03, 2017, 08:44:45 AM »
Quote from: nyteschayde;826613
My question is how does one execute arbitrary binary from within one's program.


At the most basic level, it boils down to knowing where the first instruction of the code to execute is located in, assign that address to a function pointer (if you are using 'C') and calling the code through the function pointer. There are no mechanisms present in the Amiga operating system which deny execution of arbitrary code. It's one shared address space for everything, and no sections are specifically restricted to either executable or non-executable content (on the 68030 and beyond some portions of the address space will be marked as cacheable or not cacheable, though).

Things changed a bit with the introduction of the 68030, and a bit more with the 68040, though. If the code you wanted to execute had to be pushed into memory, unpacked or auto-generated, you better made sure that the CPU data cache was flushed and the contents committed to memory (pipeline synchronization included). Sometimes things still worked out if you didn't know that you had to flush the cache and synchronize the pipelines, but you could not rely on being lucky all the time.

That's the basics. It gets more complicated if you need to load code into memory.

The easier case involves position-independent code, which references data, subroutines, etc. relative to the program counter (address of the instruction currently executing). With this code, you just reserve memory for it, copy the code into it and call it through the function pointer, etc. Yours truly once did that kind of thing for a certain Amiga hard disk controller which had to support booting from an FFS formatted partition. That was in the days when the FFS was not in ROM and had to be loaded from disk. However, the FFS at the time was one compact position independent chunk of code, so I stuck it into the hard disk driver's ROM and just ran it from there. Needless to say, don't try this at home, especially if you're 20 years old and under quite some time pressure ;)

The more difficult case requires that you load code from disk, or from ROM, without knowing beforehand where in memory exactly it will have to rest, this code not being position-independent. When you start a program from Workbench, the operating system will do exactly that: figure out how much memory is required to load the program, allocate memory for it, then load the program code and data into that memory. Finally, once everything is in place, the code and data are fixed up so that all the address references (data to data, code to code) match the respective memory addresses which code and data were loaded into (a process called "relocation", which is supported by the Amiga executable file format). The operating system provides all the tools to do this complicated business for you in dos.library, through the LoadSeg() function. If successful, LoadSeg() will return a special kind of pointer that refers to the first instruction of the code loaded (actually, it points to a 32 bit word in front of the first instruction). Again, you can use that code pointer with a 'C' function pointer and just invoke it to execute that code.

That's pretty much it, in a nutshell :)
 

Offline foleyjoTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 608
    • Show only replies by foleyjo
Re: Executing c command in c
« Reply #68 on: June 08, 2017, 12:50:07 PM »
Well I got a lot further with my program and am now ready to.... start again.
1 of the ways I learn is by going back over what I have already done and trying to do it better, using all the things I've learned. As some of the stuff I did at the start is probably a mess and can be done better now I understand things more.
I do have a few questions though.

1 - I've come across the variables STRPTR and UBYTE *. Should I use these or char * . They don't appear to do much different to each other from the examples I've seen. I like the idea of using STRPTR as to me it makes it clearer what it is. UBYTE I don't like and I've only seen it in early coding examples?

2 - Is Allocmem() better than malloc()?

3 - I'm probably going to stick with MUI for the GUI but am interested to know what you guys would recommend using?

4 - Should I allocate and free memory for every string or just ones that will be shared between functions.

These may seem like questions that I should have asked about at the start but thats why I like to go back over things. So currently in my code I have different functions using various things I've picked up and now I want to make it more consistant .
 

guest11527

  • Guest
Re: Executing c command in c
« Reply #69 on: June 08, 2017, 01:57:17 PM »
Quote from: foleyjo;826792
1 - I've come across the variables STRPTR and UBYTE *. Should I use these or char * .
That depends on what you want. As long as you only want to keep "strings", it makes no difference. However, depending on the compiler and compiler option, a "char" may be a signed datatype, whereas a "UBYTE" is unsigned. This makes a difference when comparing strings, i.e. when sorting strings and the like. In most cases, it is probably most helpful to use Stricmp() from the locale.library as it keeps track of local variations of the sorting order (for example, in German, the ü sorts as ue). For "char", all the "funny characters" have negative values, for UBYTE, they have positive values >= 128.

Quote from: foleyjo;826792
2 - Is Allocmem() better than malloc()?
No, it's different. Again, it depends on what you want. AllocMem() is the system function, malloc() is the C standard library function. Ultimately, malloc() boils down to AllocMem() in one way or another, however with quite some differences:

malloc() records how many bytes you have allocated, AllocMem() does not, and FreeMem() must be told how much bytes to release. (AllocVec() does, with FreeVec() as inverse).

Memory allocated with malloc() will be automatically released by the C startup (or rather shutdown) code, memory allocated with AllocMem() will not. Depending on what you want, this may either be desirable (because you have created some sort of resident program or data structure - then you need to use AllocMem()) or not - if you forget to release some memory, the C library will clean up behind you.

My general advice for novices is to stick with malloc() as it avoids memory holes, but as soon as you run into advanced system programming, switch over to AllocMem() and friends.


Quote from: foleyjo;826792
3 - I'm probably going to stick with MUI for the GUI but am interested to know what you guys would recommend using?
Really a matter of taste - and other constraints you may have. MUI is probably rather easy to handle, unlike other gadget toolkits I've seen, though for my personal taste, it was sometimes "a bit too much", and not precisely license-compatible with my software, so I didn't touch it. I personally used gadtools and (later) reaction. But this shouldn't really a recommendation - it is just my personal taste that I prefer to avoid third-party products and licencing issues.


Quote from: foleyjo;826792
4 - Should I allocate and free memory for every string or just ones that will be shared between functions.
Again, one cannot really recommend anything. It is not a matter of "sharing" strings between functions that makes memory allocation necessary. It is a matter of "lifetime". A character array has three drawbacks: 1) its size is fixed, 2) its life time is contrained to the function it is defined within (except if it is defined outside any function scope). 3) it takes up precious stack space if defined in function scope.

Allocating character arrays "from the heap" (aka "malloc()") has also drawbacks: 1) you need to remember to release the memory when you're done with it, which may or may not be so obvious, 2) if you do a lot of allocations, it may fragment the heap, i.e. slow down any further memory allocation (malloc() will typically limit this problem somewhat). 3) You somehow need to handle the situation gracefully if malloc() cannot find free memory.

Despite these technicalities, the question should really be: "do I need the string somewhere outside of the function (and its sub-functions) where I defined it?" If the answer is "yes", there is no other choice than to take it from the heap.

Maybe an example helps:
Code: [Select]
char *createUniqueName(void)
{
 char buffer[12]; /* borken! */

 sprintf(buffer,"%d",rand());
 return buffer;
}
will *NOT* work. Essentially, the character array "dies" as soon as the CPU leaves the function. It "may appear to work sometimes", but it will in general generate nonsense.

There are two solutions: 1) allocate from the heap:
Code: [Select]
char *createUniqueName(void)
{
 char *buffer = malloc(12);

 if (buffer)
  sprintf(buffer,"%d",rand());
 return buffer;
}
This has the drawback that the caller needs to release the string itself, otherwise we have a memory leak, plus, there is potentially a situation where the system runs out of heap, and malloc() returns (at least on the Amiga) NULL, and you need to handle this case gracefully, also in the caller, which is often not so easy.

Or, 2), you declare this as "somebody else's problem" and require that the caller prepares the memory for the function:

Code: [Select]
char *createUniqueName(char buffer[12])
{
 sprintf(buffer,"%d",rand());
 return buffer;
}
which also works, and sometimes avoids headaches - or rather, creates some headaches (hopefully less) at another place. This has the problem that the caller has to know how large the buffer has to be. While trivial in this case, it is not always obvious, and overrunning a buffer leads to hard to detect crashes. Note that there is *no* test whatsoever that the buffer is really 12 (or a sufficient number) of bytes large. The number in brackets behind the function argument is just "bogus". The following is completely equivalent:

Code: [Select]
char *createUniqueName(char *buffer)
{
 sprintf(buffer,"%d",rand());
 return buffer;
}

There is no general advice I can give. It really depends on the problem you want to solve.
 

Offline foleyjoTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 608
    • Show only replies by foleyjo
Re: Executing c command in c
« Reply #70 on: June 09, 2017, 08:30:08 AM »
Thanks Thomas. Just a few follow ups based on your answers

1 -So for strings I think I'll stick with char * .I have UBYTE in a couple of areas of my code but that was from early stuff when I was reading some example code but from what you said I'm guessing that's not a good idea because I'm mixing 2 slightly different formats.

2 -With AllocMem() and malloc() my concern is that I read that you need to store certain things (images, sound) in chip memory and to do this you would use AllocMem and specify chipmem as one of the parameters. What I was reading implied that malloc would just use any available memory.

3 - Rather than what you recommend i guess I just meant what do you use which you answered. I like MUI probably because its the one I was looking at when everything clicked into how it worked. The only thing I don't like is that some things use hooks and I just can't get my head around how the hooks work. Not so much what is happening within the function but the calls to the hooks themselves. Where the parameters are coming from and how the return values work.

4 - Your string exampels were great. It's kind of what I was thinking but you made it clearer for me.
Kind of related to strings there is one other thing that I was reading that there seems to be a bit of a debate about on different sites and forums so I'd like to know what you think about...
When declaring pointers i've read people say that you shold set them to null or 0. Then when you have freed them you should set them back to null or 0.
Some people say this is a must while others say it isn't important and just causes extra work.

*edit* More  relating to the issue I have with hooks. For the mui lists DisplayHook in order to show only 1 column I'm using a hook which is modified from code I found.
So  I have

Code: [Select]
struct Hook disphook;
This I'm guessing is my hook

Code: [Select]
init_hook(&disphook, (HOOKFUNC)dispfunct, NULL); //call to init hook

void init_hook(struct Hook *hook, HOOKFUNC entry, APTR data)  // hook function
{
hook->h_Entry = (HOOKFUNC)HookEntry;
hook->h_SubEntry = (HOOKFUNC)entry;
hook->h_Data = (APTR)data;
}
I guess this is setting up the values in the hook structure. Though I'm not sure what HookEntry is or what data would be expected.
I'm also guessing that the 2nd patameter passed is the function that you would call

Code: [Select]
LONG dispfunct(struct Hook *hook, const char **array, struct ListItems *item)
{
if (rom)
array[0] = item->Name;
else
array[0] = "\033bName";
return(0);
}

and this is where I really get confused. I call this hook in the MUI List with MUIA_List_DisplayHook, &disphook .
How does it know what array and items are as I don't appear to pass anything to them??
« Last Edit: June 09, 2017, 09:24:03 AM by foleyjo »
 

Offline Thomas

Re: Executing c command in c
« Reply #71 on: June 09, 2017, 02:38:06 PM »
Quote from: foleyjo;826825
2 -With AllocMem() and malloc() my concern is that I read that you need to store certain things (images, sound) in chip memory and to do this you would use AllocMem and specify chipmem as one of the parameters. What I was reading implied that malloc would just use any available memory.


You should avoid to use AllocMem with MEMF_CHIP. Rather use more specific functions like AllocBitMap or AllocRaster to get your portion of graphics mem. On an RTG system or when using FBlit, graphics mem does not necessarily be in Chip RAM and if you use MEMF_CHIP you waste valuable Chip RAM.

Quote
Though I'm not sure what HookEntry is


This is the high-level-language interface. h_Entry is called by the system with arguments in registers. HookEntry simply pushes the registers to the stack and calls h_SubEntry. h_SubEntry then finds the arguments on the stack like a C subroutine does.


Quote
or what data would be expected.


The h_Data field is for your personal needs. You can put anything there. It can for example be used by the hook routine to pass some data to the main program. Or vice versa.

Quote
and this is where I really get confused. I call this hook in the MUI List with MUIA_List_DisplayHook, &disphook .
How does it know what array and items are as I don't appear to pass anything to them??


It's not you who calls the hook function. You just tell MUI where the hook is and MUI calls the function. The MUI documentation tells you which arguments your routine has to expect. In case of a DisplayHook it is an array and an item.

guest11527

  • Guest
Re: Executing c command in c
« Reply #72 on: June 09, 2017, 03:30:16 PM »
Quote from: foleyjo;826825
2 -With AllocMem() and malloc() my concern is that I read that you need to store certain things (images, sound) in chip memory and to do this you would use AllocMem and specify chipmem as one of the parameters. What I was reading implied that malloc would just use any available memory.
Correct. If you need specific memory for a specific purpose, malloc() is not a good idea. malloc() works for the average ANSI-C program, though not for Amiga-specific stuff.


Quote from: foleyjo;826825
The only thing I don't like is that some things use hooks and I just can't get my head around how the hooks work.
The calls are made from the MUI code into your code so you can customize its function. The parameters are, of course, prepared by the MUI code. What exactly they are I cannot tell you, I do not know MUI precise enough, though the general principle is the same. A "hook" is essentially a function you provide as "plug in" to an interface of a third party. Essentially, a "function pointer" with a bit of added functionality. How that all works is - hopefully - documented in the MUI documentation.



Quote from: foleyjo;826825
When declaring pointers i've read people say that you shold set them to null or 0. Then when you have freed them you should set them back to null or 0.
Some people say this is a must while others say it isn't important and just causes extra work.
In general, setting them to zero after releasing them is a good safeguard against dangling pointers, and the overhead is typically not worth thinking about. In best case, the compiler will find out itself that the assignment is useless.

There are of course obvious cases where the "set to zero" is useless, and in such obvious cases, it does no harm just to leave it away:
Code: [Select]
void ReleaseString(char *name)
{
   free(name);
   name = NULL;  /* obviously pointless */
}
In this case, it is quite pointless to set "name" to NULL simply because it is not used afterwards, and because the caller of "ReleaseString" might still hold a pointer, namely the argument to the function just called, so it doesn't help either.

Nevertheless, the compiler will typically tell you that it removed a "dead assignment" and no overhead is created. Should you ever extend the function later on (unlikely in the above example, though), the assignment is already there,  so it is also a matter of "conservative programming" to leave it were it is.

Some people complain if the code is not super-optimized, but I disagree. First make the program run, then make it run fast. Writing fast code is an art by itself, and you typically get *not* fast code by only eliminating dead assignments.

 

Quote from: foleyjo;826825
Code: [Select]
init_hook(&disphook, (HOOKFUNC)dispfunct, NULL); //call to init hook

void init_hook(struct Hook *hook, HOOKFUNC entry, APTR data)  // hook function
{
    hook->h_Entry = (HOOKFUNC)HookEntry;
    hook->h_SubEntry = (HOOKFUNC)entry;
    hook->h_Data = (APTR)data;
}
I guess this is setting up the values in the hook structure.
Right. That's a little bit of data around the actual function.


Quote from: foleyjo;826825
Though I'm not sure what HookEntry is or what data would be expected.
hook->h_Data is for your own hook to use. Thus, it's not MUI that should read this pointer. It is for you to place something there you'd need.

hook->h_Entry is the entry point of your hook. This is where MUI goes if it "calls your hook". The tricky part is not hook->h_Entry, but hook>h_SubEntry. The reason for this is as follows: Some compilers require a short "set up" function to load the base registers correctly. In such a case, you would set hook->h_Entry to some "compiler trampile function", ideally provided by the compiler vendor. This trampoline function would load registers as needed for the specific compiler, and would then call by itself your function through "hook->h_SubEntry".

Whether you need that or your compiler needs that is something I cannot answer in general. The SAS/C compiler, for example, does not need it, though it is in general necessary to declare the hook function with "__saveds", a compiler magic that tells the compiler that it needs to reload some important registers from within the function to operate correctly, because the function is called from somewhere outside, plus a parameter "__asm" that also tells the compiler where to pick the arguments from.

Hence, a typical SAS/C hook function looks like this:
Code: [Select]
unsigned long __asm __saveds myHookFunction(register __a0 struct Hook *hk,register __a2 APTR object, register __a1 APTR message)
{
...
}
But again, this is very compiler specific, and the above magic only works for SAS/C. For any other compiler, hook->hk_Entry should be some compiler magic (documented, hopefully, in the compiler manual) and hook->hk_SubEntry points to your code.


Quote from: foleyjo;826825
I'm also guessing that the 2nd patameter passed is the function that you would call

Code: [Select]
LONG dispfunct(struct Hook *hook, const char **array, struct ListItems *item)
{
    if (rom)
        array[0] = item->Name;
    else
        array[0] = "\033bName";
    return(0);
}
and this is where I really get confused.
Hooks just receive three pointers (in registers a0,a2 and a1). What they actually *mean* is part of the infrastructure the hook is used for. In other words, the MUI documentation should say what the "object" and the "message" of the hook is. It seems, in this particular case (though I do not know) that "object" is a character array and "message" is a pointer to struct ListItems. Again, please check the MUI docs for this.



Quote from: foleyjo;826825
I call this hook in the MUI List with MUIA_List_DisplayHook, &disphook .
How does it know what array and items are as I don't appear to pass anything to them??
The array and the list items are prepared by MUI, and it calls your code with these arguments. the function should probably better be declared as

Code: [Select]
LONG dispfunct(struct Hook *hook, APTR carray, APTR citem)
{
const char **array = (const char **)carray;
struct ListItems *items = (struct ListItems *)citem;
....
}
because this would make more clear that the code actually receives carray and citem as "generic pointers", and you explicitly need to tell the compiler what they are. The hook declaration itself (as defined in the utility library) does *not* know. It only knows that three parameters are coming. One "struct Hook *", and two other generic pointers of unknown type. You have (or should) convert them manually to what they actually mean.

What they actually mean is specific to the use case of the hook, so in this case, MUI listviews. It should state somewhere in the manual.
 

Offline foleyjoTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 608
    • Show only replies by foleyjo
Re: Executing c command in c
« Reply #73 on: June 09, 2017, 09:28:27 PM »
Thanks guys, you've given me a lot to work with and to consider.

This is a steep learning curve for me and once I want to say how great you have all been.

Things have slowed down for me now. Going over everything I've done and everything you have all said very carefully.
After all the advice I've been given I feel committed to get something finished and not let you feel you have wasted time helping me.