Theos PowerBasic Museum 2017

IT-Consultant: Patrice Terrier => Discussion => Topic started by: Patrice Terrier on April 06, 2013, 03:50:37 PM

Title: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Patrice Terrier on April 06, 2013, 03:50:37 PM
I would like to convert this piece of PB's code to C/C++, but i don't know how to do it.
Could you help?

FUNCTION IUnknown_Release (BYVAL pthis AS DWORD PTR) AS DWORD
    LOCAL DWRESULT AS DWORD
    IF pthis THEN
       CALL DWORD @@pthis[2] USING IUnknown_Release(pthis) TO DWRESULT
       FUNCTION = DWRESULT
    END IF
END FUNCTION
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Peter Weis on April 06, 2013, 07:01:27 PM
Hi Theo,

but not 2 bytes 8 bytes

pThis[0] offset 0 bytes
pThis[1] offset 4 bytes
pThis[2] offset 8 Bytes

You look at the test example


#COMPILER PBCC
#COMPILE EXE
#DIM ALL

FUNCTION PBMAIN () AS LONG

    DIM a (0 TO 10) AS DWORD
    a(0) = 1
    a(1) = 2
    a(2) = 3

    LOCAL b AS DWORD PTR
    LOCAL c AS DWORD PTR
    b = VARPTR(a(0))
    c = VARPTR(b)


    testf(c)

    WAITKEY$

END FUNCTION

SUB testf(BYVAL b AS DWORD PTR)

    PRINT @@b[2]


END SUB     



Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Patrice Terrier on April 06, 2013, 07:04:29 PM
In my case, pthis, is a stream pointer got from CreateStreamOnHGlobal(MemBuffer, FALSE, pthis)

long IUnknown_Release (IN LPSTREAM* pthis) {
    long NewReferenceCount = -1; // Means error
    if (pthis) {
         // what syntax should i use there?
    }
    return NewReferenceCount;
}
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Peter Weis on April 06, 2013, 07:17:25 PM
Hello Patrice Terrier
Since I unfortunately do not exercise more in C + +. I can only give you the tip you leave that translate from FreeBASIC with the C-emitter

The design is similar but the syntax is different!
Title: Is that something that would make sense?
Post by: Patrice Terrier on April 06, 2013, 07:33:02 PM
Is that something that would make sense?

long IUnknown_Release (IN LPSTREAM* pthis) {
    long NewReferenceCount = -1;
    if (pthis) {
        typedef long (__stdcall *zProc) (LPSTREAM*);
        zProc hProc = (zProc) pthis[2];
        if (hProc) { NewReferenceCount = hProc(pthis); }
    }
    return NewReferenceCount;
}
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Peter Weis on April 06, 2013, 07:46:22 PM
Yes could work this way.

Test it so
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: José Roca on April 06, 2013, 08:34:10 PM
Use IStream_Release(pthis).

IStream_Release is a macro defined in objidl.h.
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: José Roca on April 06, 2013, 08:38:18 PM
BTW the release method returns a DWORD, not a LONG.
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: José Roca on April 06, 2013, 09:19:20 PM
Alternatively, you can use
(pthis)->lpVtbl -> Release(pthis)
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Charles Pegge on April 06, 2013, 10:30:57 PM
Another variation:

typedef struct _fUnknown
{
HRESULT (*QueryInterface)(void* pvObject, REFIID riid, void **ppvObject);
ULONG (*AddRef)(void* pvObject);
ULONG (*Release)(void* pvObject);
} fUnknown,*pfUnk;



ULONG ReleaseObject(pfUnk*pthis)
{
if (pthis)
{
  return pthis[0]->Release(pthis);
}
}
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Patrice Terrier on April 06, 2013, 11:19:17 PM
Ok, thanks to all of you.

But just for my learning, do you think that my syntax could work with this COM thing?

long IUnknown_Release (IN LPSTREAM* pthis) {
    long NewReferenceCount = -1;
    if (pthis) {
        typedef long (__stdcall *zProc) (LPSTREAM*);
        zProc hProc = (zProc) pthis[2];
        if (hProc) { NewReferenceCount = hProc(pthis); }
    }
    return NewReferenceCount;
}
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Patrice Terrier on April 07, 2013, 12:49:13 AM
Charles

Does your code variation is intended to work on both 32 and 64-bit ?

...
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Mike Stefanik on April 07, 2013, 01:30:55 AM
I'd recommend just using CComPtr<IStream> and let it take care of the reference counting. Unless you're actually coding in plain C, you might as well take advantage of smart pointers for COM objects. I think this is where you can start getting into trouble if you simply do a line-by-line, verb-for-verb translation. Instead, consider what you're trying to do and see if there's a better way (easer to read, easier to maintain). When it comes to do with anything that has to deal with COM, I can guarantee you that ATL will make your coding appreciably easier.

Edit: Today is apparently not a good spelling day for me.
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Patrice Terrier on April 07, 2013, 10:18:51 AM
Form my learning, could you please answer to my question, if you understand the small code i posted, thanks?

So far, my verb for verb translation is the way i am learning, and the way i understand my own code ;)
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Charles Pegge on April 07, 2013, 10:53:31 PM
Quote from: Patrice Terrier on April 07, 2013, 12:49:13 AM
Charles

Does your code variation is intended to work on both 32 and 64-bit ?

...

Certainly. The trick is to ensure that pointers are always expressed as pointers, and are never dereferenced to an integer or some other number.

Your example requires an extra dereferencing step before using accessing the function array. The equivalent to my previous example looks like this:

int ReleaseObjectA(void*pthis)
{
if (pthis)                  // valid COM object pointer
{
  void**ppfunc=pthis;        //address object body
  void**pfunc=*ppfunc;       //address function table
  ULONG (*Release)(void*pthis);   //declare function
  Release= pfunc[2];        //assign function address by index
  return Release(pthis);     //make call with object
}
}
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Mike Stefanik on April 08, 2013, 03:51:18 AM
Quote from: Charles Pegge on April 07, 2013, 10:53:31 PM
Certainly. The trick is to ensure that pointers are always expressed as pointers, and are never dereferenced to an integer or some other number.

Or if you do, use the UINT_PTR or uintptr_t polymorphic integrals that are guaranteed to be wide enough to store a pointer. For example, the following would work on a 32-bit system, but the compiler should (but Visual Studio 2010 and later won't necessarily) warn you that it's not safe for 64-bit:


UINT ptrValue = (UINT)&objValue; // Wrong


However, either of these would be fine:


UINT_PTR ptrValue = (UINT_PTR)&objValue; // C-style cast
uintptr_t ptrValue = reinterpret_cast<uintptr_t>(objValue); // Use reinterpret_cast to cast between pointers and integers


One other thing that might be of interest. Handles are 32 bits wide on x86 Windows and 64 bits wide on x64 Windows, as to be expected. But what about code like this:


HANDLE hFile = CreateFile(....);
DWORD dwParam = (DWORD)hFile;

hFile = (HANDLE)dwParam;
bResult = ReadFile(hFile, ....);


Again, that would work without a problem on 32-bit Windows but the compiler would complain just as it would in the code above. Except in this case, that code would actually work. Why? Because in Windows, all handles to kernel objects (files, sockets, threads, etc.) are guaranteed to only have their lower 32 bits be significant; on 64-bit Windows, the upper 32 bits of a handle will always be zero. Microsoft did that primarily to help with portability because a lot of applications out there did that kind of casting between handles and integers.  That said, it's always best to cast them properly using UINT_PTR or uintptr_t, but I thought I'd throw out that bit of trivia.
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Patrice Terrier on April 08, 2013, 03:14:56 PM
Charles

The last syntax you posted works with GCC, but not with VS2010 C/C++

void**ppfunc=pthis;        //address object body
Error: unable to use a "void *" type value to initialize an entity of "void **" type.

I am trying to find a good tutorial  that would teach me how to use the obscure syntax of pointers in C/C++

???
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: James C. Fuller on April 08, 2013, 04:22:08 PM
Patrice,
  One thing I don't see mentioned here is 64bit vc++ does not support inline asm.
If you need it you will have to use a 64bit assembler to create an object module and then link it into your app.

There may just not be a c++ alternative to do some of things PowerBASIC does especially for 64bit.

James
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Mike Stefanik on April 08, 2013, 05:38:46 PM
This would work with Visual C++:


ULONG IUnknown_Release(void *pObject)
{
    if (pObject != NULL)
    {
        void **pvTable = (void **)(*(void **)pObject);
        ULONG (__stdcall *_Release)(void *pThis) = (ULONG (__stdcall *)(void *))pvTable[2];
        return _Release(pObject);
    }

    return 0;
}


Seriously though, look into using ATL and smart pointers. Using this kind of code in production software is just bad, both conceptually and practically when it comes to readability and long-term maintenance of the software. Looking behind the curtain is not necessary. By the way, that __stdcall there is necessary because COM methods are defined as STDMETHOD (which uses STDMETHODCALLTYPE which is defined as the stdcall calling convention).

Edit: And I should not post stuff like this before I've had my coffee. I threw in the check for NULL there just to be on the safe side.
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Patrice Terrier on April 08, 2013, 05:59:13 PM
James,

Yep, unfortunatly i also have to convert a few lines of ASM code to 64-bit as well  >:(

like this one (that could have been written by Charles himself)

FUNCTION Rgb2Gray (BYVAL RGBValue AS DWORD)  AS DWORD

    #REGISTER NONE

    !XOR ESI, ESI
    !XOR EDX, EDX
    !MOV ECX, RGBValue

  ' Red
    !MOV EAX, 19595
    !MOV DL, CL
    !MUL EDX
    !ADD ESI, EAX

  ' Green
    !MOV EAX, 38470
    !SHR ECX, 8
    !MOV DL, CL
    !MUL EDX
    !ADD ESI, EAX

  ' Blue
    !MOV EAX, 7471
    !SHR ECX, 8
    !MOV DL, CL
    !MUL EDX
    !ADD ESI, EAX

    !SHR ESI, 16
    !MOV EDX, ESI

  ' Put Gray Value to a DWORD (0GGG)
    !XOR EAX, EAX
    !OR AL, DL
    !SHL EAX, 8
    !OR AL, DL
    !SHL EAX, 8
    !OR AL, DL

    !MOV FUNCTION, EAX

END FUNCTION
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Mike Stefanik on April 08, 2013, 06:30:28 PM
Quote from: James C. Fuller on April 08, 2013, 04:22:08 PM
There may just not be a c++ alternative to do some of things PowerBASIC does especially for 64bit.

A quick search turned up the formula for converting RGB to grayscale as (0.299 * R + 0.587 * G + 0.114 * B)

Admittedly, I'd expect the assembler version to be faster than what's generated by a C++ compiler, but then the necessity of that would depend on an actual performance analysis of the code. If usage metrics show that the function is called infrequently over the lifetime of an application, that's not necessarily a good optimization choice.
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Patrice Terrier on April 08, 2013, 07:52:43 PM
Yes the assembler version was a replacement for the previous one, that was... too slow.

'    Red? = (RGBValue AND &H000000FF???) * .299
'    SHIFT RIGHT colorRGB???, 8
'    Green? = (RGBValue AND &H000000FF???) * .587
'    SHIFT RIGHT colorRGB???, 8
'    Blue? = (RGBValue AND &H000000FF???) * .114
'    Gray? = Red? + Green? + Blue?
'    FUNCTION = RGB(Gray?, Gray?, Gray?)
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Charles Pegge on April 08, 2013, 08:02:30 PM
Patrice,

You could create an overlay structure to access the color bytes directly, rather then bit shifting the RGB.

On the subject of void**, will VC10 let you use a cast, to override its  rules?

void**ppfunc= (void**) pthis;
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Mike Stefanik on April 08, 2013, 08:43:35 PM
You can do all kinds of dangerous stuff with C-style casting to void pointers that will make the compiler stop complaining. Enough rope to hang yourself and whatnot, you know? In terms of getting to the class vtable, keep in mind that the first member of the object is the vpointer (a pointer to the vtable, not the vtable itself) so you actually have to derference that. So you end up with funky looking stuff like what I posted up there:


void **pvTable = (void **)(*(void **)pObject);


In truth though, this code is all kinds of bad. First and foremost, it makes the assumption that in the layout of the object, the first member is the vpointer, but that's not guaranteed. While most compilers do place the vpointer at the beginning of the object, it also would be perfectly legitimate for the compiler to put it at the end. Technically, the standard doesn't define how the method dispatch should be implemented, so there's no requirement that the vtable even be an array of pointers. Bottom line, code like this is non-portable and that's why I say that it shouldn't be used.
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Charles Pegge on April 09, 2013, 04:59:31 AM
This technique is reliable for COM IUnkmown /IDispatch interfaces. But I agree, Mike, that it does not apply to other kinds of objects. For instance, Objects with multiple inheritance may use several function table pointers embedded in its structure. But objects which are not exported or imported, do not require any such pointers since the compiler can generate direct links for method calls. (I do this in OxygenBasic)
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Mike Stefanik on April 09, 2013, 08:17:52 AM
You're right, I was thinking in more general terms, but COM defines the layout of the vtable in the object as part of the standard. It still don't think it's a good idea to write code like this generally, but I shouldn't have characterized it as "dangerous" when it specifically comes to COM objects.
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Patrice Terrier on April 09, 2013, 02:13:16 PM
Charles--

QuoteYou could create an overlay structure to access the color bytes directly, rather then bit shifting the RGB.

Could you ellaborate on that, what kind of overlay structure?

...
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: James C. Fuller on April 09, 2013, 04:01:45 PM
Patrice,
  I have very little 64bit assembler knowledge but maybe this link might help you:

http://www.godevtool.com/GoasmHelp/64bits.htm#adapt

James
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Charles Pegge on April 09, 2013, 09:32:55 PM
Quote from: Patrice Terrier on April 09, 2013, 02:13:16 PM
Charles--

QuoteYou could create an overlay structure to access the color bytes directly, rather then bit shifting the RGB.

Could you ellaborate on that, what kind of overlay structure?

...

Just using typedefs and pointers. I think this will give you good speed, doing all the pixels in one function helps.

#include <stdlib.h>
#include <stdio.h>

typedef struct _RGB
{
char red,green,blue;
} tRGB, *pRGB;

typedef unsigned long tGRAY,*pGRAY;

int main()
{
int width=640, height=480;
int e=width*height;
pRGB  ColorImage = malloc(e*sizeof(tRGB));
pGRAY GrayImage  = malloc(e*sizeof(tGRAY));
//...
int  i;
pRGB  color = ColorImage;
pGRAY gray  = GrayImage;
//
for (i=0;i<e;i++)
{
  //RGB to grayscale as (0.299 * R + 0.587 * G + 0.114 * B)
  *gray=(0.299*color->red)+
        (0.587*color->green)+
        (0.114*color->blue);
  color++;
  gray++;
}
//...
free(ColorImage);
free(GrayImage);
}

Charles
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Mike Stefanik on April 10, 2013, 01:42:50 AM
I'm by no means a graphics guy, and don't know about the context in which that function is being used, but if the end-goal is the conversion of an image from color to grayscale, wouldn't the use of a ColorMatrix in GDI+ be the simplest (and fastest) approach? I'd have to presume that all of the low-level optimization, etc. that would need to be done has already been done there. Just a thought.
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Charles Pegge on April 10, 2013, 07:09:12 AM
Much of this is an exercise in C comprehension for Patrice and myself. We both need to understand C from the ground level.

Mike, do you recall we had a conversation about first-class functions and closures, on the thinBasic forum. I am still a little mystified by closures, so perhaps we could start a new topic on functional programming.
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Patrice Terrier on April 10, 2013, 09:21:58 AM
Mike--

It does not serve the same purpose, in GDImage it is used to create an image with variable opacity where the 256 level of gray are being used to assign a specific alpha channel to each pixel of an image, something totaly different that converting a whole image to gray. Indeed it works more like what OpenGL does when using GL_BLEND.

                   pBits = bm.bmBits
                   FOR y = 0 TO bm.bmHeight - 1
                       FOR x = 0 TO (bm.bmWidth - 1)
                           @pBits[3] = Rgb2Gray(RGB(@pBits[2],@pBits[1],@pBits[0]))
                           pBits = pBits + 4
                       NEXT
                   NEXT


As you can see from the above code only the alpha channel is changed, the other RGB components are left unchanged.
And you can understand now, why the Rgb2Gray must be as fast as possible.

This is something totaly different than this:

LONG_PTR UseGrayMatrix(IN LONG_PTR imgAttr) {
    ColorMatrix c, g;
    // Create the ImageAttributes object
    if (imgAttr == 0) { GdipCreateImageAttributes(imgAttr); }
    // Fill the color matrix
    // Red              Green               Blue                Alpha              W
    c.m[0][0] = 0.3f  ; c.m[1][0] = 0.3f  ; c.m[2][0] = 0.3f  ; c.m[3][0] = 0.0f ; c.m[4][0] = 0.0f; // Red
    c.m[0][1] = 0.59f ; c.m[1][1] = 0.59f ; c.m[2][1] = 0.59f ; c.m[3][1] = 0.0f ; c.m[4][1] = 0.0f; // Green
    c.m[0][2] = 0.11f ; c.m[1][2] = 0.11f ; c.m[2][2] = 0.11f ; c.m[3][2] = 0.0f ; c.m[4][2] = 0.0f; // Blue
    c.m[0][3] = 0.0f  ; c.m[1][3] = 0.0f  ; c.m[2][3] = 0.0f  ; c.m[3][3] = 1.0f ; c.m[4][3] = 0.0f; // Alpha
    c.m[0][4] = 0.0f  ; c.m[1][4] = 0.0f  ; c.m[2][4] = 0.0f  ; c.m[3][4] = 0.0f ; c.m[4][4] = 1.0f; // W
    // And set its color matrix
    GdipSetImageAttributesColorMatrix(imgAttr, ColorAdjustTypeDefault, TRUE, c, g, ColorMatrixFlagsDefault);
    return imgAttr;
}


Charles--
QuoteMuch of this is an exercise in C comprehension for Patrice and myself. We both need to understand C from the ground level.
So true, thank you :)
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: Mike Stefanik on April 10, 2013, 05:53:59 PM
Quote from: Charles Pegge on April 10, 2013, 07:09:12 AM
Mike, do you recall we had a conversation about first-class functions and closures, on the thinBasic forum. I am still a little mystified by closures, so perhaps we could start a new topic on functional programming.

Sure, but in the context of C++ though you kind of end out far into the weeds. C++11 introduced lambdas (anonymous functions) and closures that look like this:


int foo = 1;
for_each(v.begin(); v.end(); [&foo] (int bar) -> int
{
    return bar * foo++;
});
;

It does make things more convenient (for example, creating class delegates) but, to me, this just looks ugly. Other languages have a much cleaner implementation (such as C# and JavaScript). But perhaps it's just because I'm an old C programmer from days gone by and these are the new kids partying on my front lawn.

Edit: I'm just typing this off the top of my head, so hopefully I got the syntax right there (and it's somewhat complicated by the fact that not all of the current C++ compilers out there completely support the standard). Your mileage may vary, as they say.
Title: Re: Translating PB's CALL DWORD @@pthis[2] to C/C++, how?
Post by: James C. Fuller on April 10, 2013, 06:47:09 PM
I hear you Mike.
MinGW 4.8 has all of it I think.
This is one of the distro's I am using: http://nuwen.net/mingw.html
An MS employee's personal site.
Even though I am still early on in my c++ education I really like some of the new c11 stuff.
some of my favorites:
direct vector assigment, reference based loops and of course "auto"

With the nuwen distro this will compile with just this simple command line:
g++ v4.cpp -ov4.exe


James



#include <iostream>
#include <vector>
using namespace std;


int     main (void);


int main ()
{
    vector<string> s = {"one","two","three","four","five"};

    cout << "s contains" << endl;
    for(auto it = s.begin(); it != s.end(); ++it)
    {
        cout << " " << *it;
    }
    cout << endl;

    cout << "in reverse" << endl;
    for(auto rit = s.rbegin(); rit != s.rend(); ++rit)
    {
      cout <<" " << *rit;
    }

    cout << endl;
    cout << "range-based for loop" << endl;
    for ( auto it : s)
    {
      cout << " " << it;
    }
    cout << endl;
    return 0;
}