• Welcome to Powerbasic Museum 2020-B.
 

News:

Forum in repository mode. No new members allowed.

Main Menu

Get prepared to move on.

Started by Patrice Terrier, January 11, 2013, 02:44:59 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Patrice Terrier

I have started to work on the translation of my GDImage.dll to plain C 64-bit by hand, because BCX is absolutly not reliable, what a slow process !!!

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

James C. Fuller

Patrice,
What compiler are you using for your plain c? I ask because VC++ is only c(89) for "c" code.

James


Frederick J. Harris

Are you planning to use C or C++ compilation Patrice?  Just my opinion, but I prefer greatly using the *.cpp file extension, and using therefore C++ compilation.  In that way, without going into all the nastiness of C++ (STL being the biggies), one gets some significant advantages. 

I never fully embraced everything in C++; but prefer compiling as C++, even though my coding style is mostly C centric (whatever that means).

Patrice Terrier

#33
I am using Microsoft Visual Studio 2010 Professional.

Here is my config type:
- Create Dynamic library (.dll)
- Use Windows standard library
- Do not use ATL
- Use Unicode
- Do not use the Common Language Runtime

Command line:
/Zi /nologo /W3 /WX- /O2 /Oi /GL /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "GDIMAGE_EXPORTS" /D "_WINDLL" /D "_UNICODE" /D "UNICODE" /Gm- /EHsc /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Yu"StdAfx.h" /Fp"x64\Release\GDImage.pch" /Fa"x64\Release\" /Fo"x64\Release\" /Fd"x64\Release\vc100.pdb" /Gz /errorReport:queue

Note: I am using /Gz (__stdcall)
source code has the .cpp extension.

Here is an example of the header i am using (work in progress)//#define       METADATA_SIZE    2048
const int       METADATA_SIZE       = 2048;
//const char    *GDImageClassName   = "ZIMAGECTRL";
const wchar_t   *GDImageClassName   = L"ZIMAGECTRL";
const wchar_t   *GLImageClassName   = L"ZOPENGLCTRL";

// See below the list of GDImage properties:
// Note: Constants prefixed with %ZI_ are for IMAGE control
const int ZI_DC                 = 1;    // Internal DC
const int ZI_Bitmap             = 2;    // Memory Bitmap
const int ZI_Horizontal         = 3;    // Horizontal scrolling position
const int ZI_Vertical           = 4;    // Vertical scrolling position
const int ZI_GradientTop        = 5;    // Top gradiant color backgroud
const int ZI_GradientBottom     = 6;    // Bottom gradiant color backgroud

const int ZI_FitToWindow        = 7;    // Resize the image to fit the view port
const int    ZI_QualityDefault  = -1;   // And use any of this constant as Parameter
const int    ZI_QualityGood     = 1;    // Best performance
const int    ZI_QualityHigh     = 2;    // Best rendering quality
// DO NOT use or alter these properties!
const int ZI_PaintDC            = 8;    // Internal DC
const int ZI_PaintBitmap        = 9;    // Memory Bitmap
const int ZI_Reserved           = 10;   // Animated frame parameters : LOWRD = FrameWidth, HIWRD = FrameCount

const int ZI_ZoomWindow         = 11;   // Version 1.41
const int ZI_ZoomFactor         = 12;   // Version 1.41
const int ZI_Orientation        = 13;   // Version 1.41

const int ZI_FlagByte           = 14;   // Version 2.00 4 bytes reserved for flag
const int    TOOL_CROP          = 1;    // Stored in the first byte
const int    TOOL_CUTTER        = 2;    // Stored in the first byte
const int    TOOL_PENCIL        = 4;    // Stored in the first byte
const int    TOOL_FLOOD         = 8;    // Stored in the first byte
const int    TOOL_AIRBRUSH      = 16;   // Stored in the first byte
const int    TOOL_PIPE          = 32;   // Stored in the first byte
const int    TOOL_MOUSE         = 64;   // Stored in the first byte
const int    TOOL_UNKNOWN       = 128;  // Stored in the first byte

const int Extend_cbWndExtra     = ZI_FlagByte;

const int ZI_GDIPLUSHANDLE      = 1;    // Load GDIPLUS Image handle

const int ZI_GLDC               = 8;    // OpenGL Device Context
const int ZI_GLRC               = 9;    // OpenGL Rendering Context

const int ZD_MAPCOLORFROM       = 0x807F80;   // Maping color for 32-bit alphablending
const int ZI_MAPCOLORFROM       = 0xFF807F80; // Maping color for 32-bit alphablending
const int ZI_MAPCOLORTO         = 0xFF808080; // Maping color for 32-bit alphablending
const int ZI_MAPCOLORNULL       = 0x00807F80; // Maping color for 32-bit alphablending
const int ZI_MAPTRANSCOLOR      = 0x807F80;   // Transparent maped color for 32-bit alphablending

extern "C" _declspec (dllexport) wchar_t* ZI_Version();
extern "C" _declspec (dllexport) long RegisterGLImageClass();
extern "C" _declspec (dllexport) HINSTANCE zInstance();
extern "C" _declspec (dllexport) void ZI_SetProperty (IN HWND hWnd, IN long nItem, IN long nValue);
extern "C" _declspec (dllexport) long ZI_GetProperty (IN HWND hWnd, IN long nItem);
extern "C" _declspec (dllexport) void ZI_GetBitmapSize (IN HANDLE hBmp, OUT long xWidth, OUT long yHeight);
extern "C" _declspec (dllexport) HANDLE ZI_GetBMP (IN HWND hWnd);
extern "C" _declspec (dllexport) void ZI_GetImageSizeFromControl (IN HWND hWnd, OUT long imgW, OUT long imgH);
extern "C" _declspec (dllexport) HBITMAP zCreateDIBSection (IN HDC hDC, IN long nWidth, IN long nHeight, IN long nBitCount);


And here is the begining of GDImage.cpp (work in progress)// GDImage.cpp : définit les fonctions exportées pour l'application DLL.
//
#include <windows.h>
#include <iostream>
#include <string.h>
#include <WinGDI.h>
#include <gl/GL.h>
#include <gl/GLU.h>

#include "stdafx.h"
#include "GDImage.h"

typedef struct {
    HWND    hWnd;
    LONG    anchor;
    RECT    rc;
    LONG    TiledBitmap;
    CHAR    order[METADATA_SIZE];
    LONG    ordersize;
    LONG    WMBit[25];
    DWORD   WMCodePtr[25 * 32];
    LONG    centerx;
    LONG    centery;
    LONG    Composited;
} ZIMAGEPROP;

typedef struct {
    HWND    hWnd;
    long    hTexture;
    BYTE    CharWidth[256];
    long    nFontSize;
    TCHAR   szFontName[64];
} CHARTFONT;

static wchar_t *Version = L"6.06";

// Global variables
CHARTFONT g_GLF[];

HBITMAP zCreateDIBSection (IN HDC hDC, IN long nWidth, IN long nHeight, IN long nBitCount) { // exportdll
    BITMAPINFO bi = { 0 };
    bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bi.bmiHeader.biWidth = nWidth;
    bi.bmiHeader.biHeight = nHeight;
    bi.bmiHeader.biPlanes = 1;
    bi.bmiHeader.biBitCount = nBitCount;
    bi.bmiHeader.biCompression = BI_RGB;
    return CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, 0, 0, 0);
}

long SetupPixelFormat(IN HDC hDC, IN long FlagStyle) {
    PIXELFORMATDESCRIPTOR pfd;
    long pixelformat;
    long lRet;

    lRet = TRUE;

    pfd.nSize              = sizeof(pfd);
    pfd.nVersion           = 1;
    pfd.dwFlags            = FlagStyle;
    pfd.iPixelType         = 0;
    pfd.cColorBits         = 32;
    pfd.cRedBits           = 0;
    pfd.cRedShift          = 0;
    pfd.cGreenBits         = 0;
    pfd.cGreenShift        = 0;
    pfd.cBlueBits          = 0;
    pfd.cBlueShift         = 0;
    pfd.cAlphaBits         = 1;
    pfd.cAlphaShift        = 0;
    pfd.cAccumBits         = 0;
    pfd.cAccumRedBits      = 0;
    pfd.cAccumGreenBits    = 0;
    pfd.cAccumBlueBits     = 0;
    pfd.cAccumAlphaBits    = 0;
    pfd.cDepthBits         = 16;
    pfd.cStencilBits       = 0;
    pfd.cAuxBuffers        = 0;
    pfd.iLayerType         = 0;
    pfd.bReserved          = 0;
    pfd.dwLayerMask        = 0;
    pfd.dwVisibleMask      = 0;
    pfd.dwDamageMask       = 0;

    pixelformat = ChoosePixelFormat(hDC, &pfd);
    if (pixelformat) {
        if (SetPixelFormat(hDC, pixelformat, &pfd) == 0) { lRet = FALSE; } }
    else {
       lRet = FALSE;
    }

    return lRet;
}

long zSetupPixelFormat(IN HDC hDC) {
    return SetupPixelFormat(hDC, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SUPPORT_GDI);
}

wchar_t* ZI_Version () { // dllexport
    return Version; // Version number of the form "#.#"
}

HINSTANCE zInstance () { // dllexport
    return GetModuleHandle(NULL);
}

void ZI_GetBitmapSize (IN HANDLE hBmp, OUT long xWidth, OUT long yHeight) { // dllexport
    BITMAP bm;
    if (hBmp) {
       GetObject(hBmp, sizeof(bm), &bm);
       xWidth = bm.bmWidth;
       yHeight = bm.bmHeight;
    }
}

HANDLE ZI_GetBMP (IN HWND hWnd) { // dllexport
    return HANDLE(ZI_GetProperty(hWnd, ZI_Bitmap));
}

void ZI_GetImageSizeFromControl (IN HWND hWnd, OUT long imgW, OUT long imgH) { // dllexport
    ZI_GetBitmapSize(ZI_GetBMP(hWnd), imgW, imgH);
}

long ZI_GetProperty (IN HWND hWnd, IN long nItem) { // dllexport
    long nRet = 0;
    if (nItem > 0 && nItem < Extend_cbWndExtra + 1 && IsWindow(hWnd)) {
        nRet = GetWindowLong(hWnd, (nItem - 1) * 4);
    }
    return nRet;
}

void ZI_SetProperty (IN HWND hWnd, IN long nItem, IN long nValue) { // dllexport
    if (nItem > 0 && nItem < Extend_cbWndExtra + 1 && IsWindow(hWnd)) {
        SetWindowLong(hWnd, (nItem - 1) * 4, nValue);
    }
}

LRESULT CALLBACK zGLWindowProc(IN HWND hWnd, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam) {
    PAINTSTRUCT ps;
    HDC glDC;
    HGLRC glRC;

    switch (uMsg) {
    case WM_CREATE:
         glDC = GetDC(hWnd);

         if (zSetupPixelFormat(glDC) == 0) {
            return 1;
         }
         glRC = wglCreateContext(glDC);
         wglMakeCurrent(glDC, glRC);

         ZI_SetProperty(hWnd, ZI_GLDC, long(glDC));
         ZI_SetProperty(hWnd, ZI_GLRC, long(glRC));
         return 0;

    case WM_PAINT:
         BeginPaint(hWnd, &ps);
         EndPaint(hWnd, &ps);
         return 0;

    case WM_DESTROY:
         glDC = HDC(ZI_GetProperty(hWnd, ZI_GLDC));
         glRC = HGLRC(ZI_GetProperty(hWnd, ZI_GLRC));
         if (glRC) {
            wglMakeCurrent(glDC, 0);
            wglDeleteContext(glRC); glRC = 0;
         }
         if (glDC) { ReleaseDC(hWnd, glDC); glDC = 0; }
//         GL_DeleteTextureFont(hWnd);
//         if GL_ChartProc(0,0) { SetWindowLong(GL_ChartWnd(0,0), GWL_WNDPROC, GL_ChartProc(0,0)); }
         break;
    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

long RegisterGLImageClass () { // dllexport
    WNDCLASSEX wcx;
    wcx.cbSize = sizeof(wcx);
    long IsInitialized = GetClassInfoEx(zInstance(), GLImageClassName, &wcx);
    if (IsInitialized) {
        wcx.style         = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
        wcx.lpfnWndProc   = zGLWindowProc;
        wcx.cbClsExtra    = 0;
        wcx.cbWndExtra    = Extend_cbWndExtra * 4;
        wcx.hInstance     = zInstance();
        wcx.hIcon         = NULL;
        wcx.hCursor       = LoadCursor(NULL, IDC_ARROW);
        wcx.hbrBackground = NULL; // Don't paint the class window background
        wcx.lpszMenuName  = NULL;
        wcx.lpszClassName = GLImageClassName;
        wcx.hIconSm       = NULL;
        if (RegisterClassEx(&wcx)) { IsInitialized = TRUE; }
    }
    return IsInitialized;
}

//BOOL WINAPI DllMain(IN DWORD hDllHandle, IN DWORD nReason, IN LPVOID Reserved) {
//  BOOLEAN bRet = TRUE;
//
//  //  Perform global initialization.
//  if (nReason == DLL_PROCESS_ATTACH) {
//      }
//  else if (nReason == DLL_PROCESS_DETACH) {
//  }
//
// }


BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Patrice Terrier

Here is a typical PowerBASIC syntax, that is hard to translate into C.

Using UBOUND on an array that has not been DIMed yet, and REDIM PRESERVE to change array size.

TYPE CHARTFONT
    hWnd            AS LONG
    hTexture        AS LONG
    CharWidth(255)  AS BYTE
    nFontSize       AS LONG
    szFontName      AS ASCIIZ * 64
END TYPE
       
GLOBAL g_GLF() AS CHARTFONT

FUNCTION GL_GetNewFontItem() AS LONG
    LOCAL nItem AS LONG
    IF UBOUND(g_GLF) > 0 THEN
       ARRAY SCAN g_GLF(LBOUND(g_GLF)), FROM 1 TO 4, = MKL$(0), TO nItem
    END IF
    IF nItem = 0 THEN
       nItem = MAX&(UBOUND(g_GLF) + 1, 1)
       REDIM PRESERVE g_GLF(1 TO nItem) AS CHARTFONT
    END IF
    FUNCTION = nItem
END FUNCTION


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

Stan Duraham

If you don't need to Insert or Delete items in the middle of the array, then it's easy to roll your own.

use: GlobalAlloc(ByVal %GPTR, ByVal Count) to allocate memory for an empty array.
use: GlobalReAlloc(ByVal h, ByVal Count, ByVal %GMEM_MOVEABLE Or %GMEM_ZEROINIT) to allocate a larger or smaller memory block.

Count = number of bytes

GlobalReAlloc(), with those flags, will preserve the data.
GlobalReAlloc() may return a different memory handle.

Patrice Terrier

#36
Stanley,

Your GMem solution is a good one, however it envolves a lot of changes to the original PB's syntax being used...
I mean using a global memory pointer, instead of a global array().

:-\

Stan's memory manager:
Function LibMemAlloc(ByVal Count As Long) As Long
    'allocate Count bytes of memory
    If Count Then
        Function = GlobalAlloc(ByVal %GPTR, ByVal Count)
    End If
End Function
Function LibMemFree(ByVal h As Long) As Long
    'free allocated memory - return null
    If h Then GlobalFree(ByVal h)
End Function
Function LibMemReAlloc(ByVal h As Long, ByVal Count As Long) As Long
    'change allocation block size
    'current contents saved
    'if Count > current allocation - additional memory will be null
    'USE: h = LibMemReAlloc(h, newSize)
    If Count = 0 Then
        If h Then GlobalFree(ByVal h)
    Else
        If h Then
            Function = GlobalReAlloc(ByVal h, ByVal Count, ByVal %GMEM_MOVEABLE Or %GMEM_ZEROINIT)
        Else
            Function = GlobalAlloc(ByVal %GPTR, ByVal Count)
        End If
    End If
End Function
Sub LibMemCopy(ByVal copyTo As Long, ByVal copyFrom As Long, ByVal Count As Long)
    'copy/move block of memory
    If Count Then MoveMemory(ByVal copyTo, ByVal copyFrom, ByVal Count)
End Sub
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com


Patrice Terrier

Stanley,

I am not moving to C on happy heart, but because i don't want to be an hostage anymore.

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

Patrice Terrier

Stanley--

In the case of a DLL, don't you think that HeapCreate could be a better choice, than using GlobalAlloc ?

...

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

Stan Duraham

#40
I don't know.
That's all I've tried because it works so well for arrays.
GlobalReAlloc, with those flags, is like REDIM PRESERVE with no extra work.
I had no problems with DLLs.

Charles Pegge

#41
One of the biggest challenges is to make a good string engine with concatenator and garbage collection. You can still use OLEstrings like PB. They are also good for dynamic arrays up to 2 gig of data.

Having been through all the logistics of dynamic string management (using Assembler), I would be very happy to share ideas on how this might be achieved in C.

Charles




Frederick J. Harris

I've always tended to use the GlobalAlloc() family of functions, rather than the HeapCreate()/HeapAlloc(), but its likely just inirtia with me. 

My question on C compilation as opposed to C++ compilation was simply based on the idea that C++ compilation, as you are apparently doing if you terminate your filenames with *.cpp instead of *.c, gives some ease of use type benifits that I believe are significant, without incurring any negatives.  To give just one example, in a lot of ways you can eliminate the typedef key word around structs if you do C++ compiulation.  The following will compile in C as Main.c ...


// C Way ...
#include <cstdio>

struct SomeStruct
{
int a;
int b;
};

int main(void)
{
struct SomeStruct ss;

ss.a=5, ss.b=6;
printf("ss.a = %d\n",ss.a);
printf("ss.b = %d\n",ss.b);
getchar();

return 0;
}



Note in main() I had to preface the SomeStruct declaration with the struct keyword.  However, one can get away from that to a more natural usage in straight C by using the typedef ...


#include <cstdio>

typedef struct
{
int a;
int b;
}SomeStruct;

int main(void)
{
SomeStruct ss;

ss.a=5, ss.b=6;
printf("ss.a = %d\n",ss.a);
printf("ss.b = %d\n",ss.b);
getchar();

return 0;
}


Note carefully the few changes above.  Using the typedef in the definition of SomeStruct, I was able to eliminate the use of the struct keyward before the declaration of the SomeStruct object in main().  So there you see where and why the typedef is on so many darned UDTs in the documentation;  its because folks want the stuff to compile with either a C or C++ compiler.   And that might be true in your case too.  But if you stick to straight C++ compilation, you can eliminate the dumb typedefs.  Here's same program using C++ compilation ...


//C++ way ...
#include <cstdio>

struct SomeStruct
{
int a;
int b;
};

int main(void)
{
SomeStruct ss;

ss.a=5, ss.b=6;
printf("ss.a = %d\n",ss.a);
printf("ss.b = %d\n",ss.b);
getchar();

return 0;
}


Of course, there are other benifits too, such as Byref parameter passing (like PowerBASIC), so that is the only point I was trying to make.

Since I work back and forth so frequently between C/C++ and PowerBASIC, I've always tended to use only that subset of PowerBASIC that has ready analogues in C.  For example, your use of Array Sort above pretty much 'threw me', as I tend not to use such constructs.  I tend to write pretty low level in both language families.  So I can see where it will be difficult translating your code Patrice.

I will say it is time consumming doing line by line translating between C and PB.  CreateWindowEx() calls are a real bear.  I mean, they look so similiar, but everyone takes like a whole minute to do.  One must ...

1) insert semicolon;
2) replace 'Or' with '|';
3) stick Byval 0 for lpCreateParams;
4) remove '%';
5) deal with wide character issue using TCHARs or whatever you do

etc.  In my example programs I've posted here where I'll provide C++ and exact PowerBASIC versions of the same program, it can easy take an hour or two to convert only a simple 200 line example program.     

Frederick J. Harris

Quote
One of the biggest challenges is to make a good string engine with concatenator and garbage collection. You can still use OLEstrings like PB. They are also good for dynamic arrays up to 2 gig of data.

How right you are Charles!  That, in my mind, is where the fatal flaw in C++ lies.  The language has no built in 'String' type.  Its rather part of the C++ Standard Library.  In my opinion, even though the String Class in the C++ Standard Library is extremely good, its usage for the coder doesn't match what is available in various good versions of BaSIC, such as PowerBASIC.  What Bob Zale must have know about writting String code!!!!!

Frederick J. Harris

Quote
Having been through all the logistics of dynamic string management (using Assembler), I would be very happy to share ideas on how this might be achieved in C.

For the next little while I'll be busy on some things at work that I have to get done, but at some point in the future I'd love to work on that Charles.  As you know, I made my own String class I use in my C++ coding.  However, its only based on null terminated string buffers, i.e., allocate buffer, terminate with NULL - you know the drill.  I'd like to try to make another based on OLE String Engine as you mentioned.