• Welcome to Theos PowerBasic Museum 2017.

News:

Attachments are only available to registered users.
Please register using your full, real name.

Main Menu

Translating PB's CALL DWORD @@pthis[2] to C/C++, how?

Started by Patrice Terrier, April 06, 2013, 03:50:37 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Mike Stefanik

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.
Mike Stefanik
sockettools.com

Patrice Terrier

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++

???
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

James C. Fuller

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

Mike Stefanik

#18
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.
Mike Stefanik
sockettools.com

Patrice Terrier

#19
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
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Mike Stefanik

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.
Mike Stefanik
sockettools.com

Patrice Terrier

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?)
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Charles Pegge

#22
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;

Mike Stefanik

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.
Mike Stefanik
sockettools.com

Charles Pegge

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)

Mike Stefanik

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.
Mike Stefanik
sockettools.com

Patrice Terrier

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?

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

James C. Fuller

Patrice,
  I have very little 64bit assembler knowledge but maybe this link might help you:

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

James

Charles Pegge

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

Mike Stefanik

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.
Mike Stefanik
sockettools.com