Oxygen Basic

Programming => Example Code => General => Topic started by: Charles Pegge on March 04, 2018, 05:58:31 PM

Title: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: Charles Pegge on March 04, 2018, 05:58:31 PM
There are many ways to declare a procedure. Here are some of the combinations for late binding:

In these examples we are using '!' instead of 'declare function'.

Code: [Select]
'2018-03-05 T 01:42:51
'
'LATE BINDING TO DLL
====================
'
'BASIC WITH PROTOTYPE
'! ptr MessageBox (sys hwnd,char*msg,*title,int mode) as int
'C STYLE
'int (*MessageBox) (sys hwnd,char*text,char*title,int mode)
'BASIC UNPROTOTYPED
!* MessageBox
'
sys u32=LoadLibrary "user32.dll"
@MessageBox=GetProcAddress  u32, "MessageBoxA"
'
'USE LIKE ANY OTHER FUNCTION CALL
MessageBox 0,"helo","greet",0
'EXPLICIT CALL
call MessageBox 0,"helo","greet",1
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: Raymond Leech on March 05, 2018, 07:16:49 AM
Thanks Charles, I see the similarities now.
Title: Re: Late binding to DLL / Call DWORD equiv / (for Charles)
Post by: Mike Lobanovsky on March 05, 2018, 05:21:54 PM
Hi Charles,

"Late binding to DLL" declares, header files, prototyping and similar stuff are retrograde, ridiculous, and redundant.

Luckily, you are still king and god in your alpha world of Oxygen Basic.

O2 in all the three of its hypostases (IDE, Oxygen.dll, and end user executables via the O2 runtime library they are linked against) is always linked against at least four system DLLs: kernel32.dll, user32.dll, oleaut32.dll, and msvcrt.dll. Add gdi32.dll into the bargain (BASIC without graphics primitives like LINE, CIRCLE, PSET, etc. is not a BASIC, is it?) and be merciful to O2 users.

Since the 5 DLLs are already in the process memory regardless of the user code, spare them this monkey business messing with the Windows includes and late bindings.

1. Run the WINDOWS_LEAN_AND_MEAN set of include files once through a utility that would convert them to the O2 IDE's table of intellisense entries.

2. Map the vtables of these DLLs in their entirety at app load time dynamically into the O2 namespace and make their APIs part of the O2 user's extra default arsenal.

Looping through the DLL export API name table is trivial. Call GetProcAddress() for each name found. This system function is more robust and reliable than manual hopping from thunk to thunk in the DLL vtable.

3. Add an #import MM.DLL meta (DLL name is exemplary here) to the O2 vocabulary. If the user would like to see a Windows multimedia API call in their code, they either:or
or both. Make this O2 meta do exactly the same as what's described in Item 2 above for each DLL the user would care to import. Loading a DLL for just one API call isand let late bindings be done with once and for all.

FBSL has been doing that for decades in its BASIC interpreter and DynAsm JIT compiler, and for years, additionally in separate DynC code blocks. The DynC JIT compiler uses an ELF executable object format but I'm too old and respectful to end my days roaming through the debris of an inferior OS finding out how to set up shared memory for dozens of DynC blocks I'm using in almost every FBSL app I write. And still FBSL is practically twice faster than OxygenBasic to launch a script of comparable size and complexity in the JIT compilation mode (remember oxyscheme/tinyscheme olympics? :) ).

(I've just had a look into my O2 folder to see what Oxygen.dll imports are, and noticed the InMemoriam.o2bas script in the root there. You are very kind, Charles, and you always have been. Thank you.)
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: Charles Pegge on March 05, 2018, 06:45:38 PM
Hi Mike,

Yes, I would be delighted to dump the 'bloody' headers. That will work for the most part  of those Windows DLLs. But how do you handle the A and W calls in FBSL?

As for Opengl, we have mixed floats and ints, so we would have to rely on users being rigorous in making that distinction when passing parameters.
Title: Re: Late binding to DLL / Call DWORD equiv / (for Charles)
Post by: Mike Lobanovsky on March 05, 2018, 08:13:44 PM
MS has a default convention that every system API whose name ends in a capital A stands for ASCII if there is also a matching W version found, that would then stand for WCHAR. Same API without an A or W is not a DLL name table entry but a PP header #define sensible to what platform bitness the compiler is currently dealing with.

You need no PP to do that for you in real time. Regardless of bitness, O2 would always find and map the MessageBoxA and MessageBoxW names in the name table of respective 32- or 64-bit user32.dll. But then it would also create one more "synthetic" O2 name MessageBox and would point it to either MessageboxA or MessageBoxW depending on which bitness version of an O2 executable is currently in the process of launching.

Re. "rigorous in making that distinction"

Exactly. That's what intellisense, MSDN and help files are for. And if they are still passing an int instead of a float despite all these three aids open on their desktops, let their apps crash and rot in hell. Hopefully they will still be able to find peace and happiness someplace else, milking cows or breeding pigs.

Tip: like any other respectful BASIC, FBSL supports type identifiers to its vars and literals:

% = int/long/bool
%% = long-long/quad
! = float/single
!! = double

and whenever I see a * qualifier in the MSDN or help file, I'm supposed to pass my var reference as an explicit @varname parameter in my FBSL statement. When the time comes and I won't be able to do just that little, I'll go hang my poor self quietly in the khazi.

Re. "bloody"

BASIC headers and declares have been invented by the evil dudes from the VB and PB sites to shake out yet more money from our pockets. Let's not let them do it any more to us, Charles. :D

But if it ever comes to cloning PB in x64 O2, let's let them have those headers in 64 bits as a matter of their culture and tradition. FBSL does allow line numbers in its BASIC scripts for the sake of Darthmouth busyworkers from retro-BASIC sites, but trashes them silently while parsing. ;)
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: Charles Pegge on March 06, 2018, 08:55:56 PM
Thanks, Mike,

We can extract all the names and call address RVAs in one go. To get the call address for each function, its RVA is simply added as an offset to the library handle.

But what do we do about all those wretched equates that take up the bulk of header files?
Title: Re: Late binding to DLL / Call DWORD equiv / (for Charles)
Post by: Mike Lobanovsky on March 06, 2018, 11:35:44 PM
... its RVA is simply added as an offset to the library handle.

Charles, beware! This attitude is naive, or Microcoft wouldn't be who they effectively are and there wouldn't be such a thing as GetProcAddress! Take my advice or as I said you're going to find yourself grasshopping all over the DLL's PE header pretty soon chasing the real entry point rather than another thunk! :D

Did you know MS VB6's original DoEvents takes perhaps a thousand lines of C code to re-implement? Yes, my middle initials stand for Ida Pro ... :D

(Seriously, I'm under an NDA with my former FBSL coworkers, and I'll always be, so I can't provide ready-made solutions. But I can still give hints and tips and applaud to bingos. :) )

But what do we do about all those wretched equates that take up the bulk of header files?

Let them stay, Charles. They aren't that bad and they are all pretty logical and helpful to keep human readability of any programming language pretty high. FBSL sports an approx. 200KB large (LF only rather than CRLF line endings) equate-only Windows.inc header. My personal statistics runs as follows:
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: Charles Pegge on March 07, 2018, 12:20:16 AM
A modest tweak in the standard dll sectional info, and the whole world would be spared the curse of headers, completely.

I'll do some research on the Kernel and his fellow officers. It is very easy to check all the call addresses against GetProcAddress values and list any anomalies.
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: Charles Pegge on March 07, 2018, 04:49:31 AM
Well, here are my findings on a selection of DLLs.

The Kernel is the worst offender with 174 GetProcAddress mismatches, followed by GDI with 54.

As you can see from the lists, most of the calls are obscure. And it's only a small percentage of the thousands of API calls in the system.

Title: Re: Late binding to DLL / Call DWORD equiv / (for Charles)
Post by: Mike Lobanovsky on March 07, 2018, 09:15:37 AM
Thank you, Charles.

You may call me anything you want but don't call me late for supper. 8)

(One can also utilize this MS "feature" as sorta protection against fiddling with custom PE loaders used to avoid AV alarms.)
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: Charles Pegge on March 09, 2018, 07:17:33 AM
Since most programs will only use a tiny fraction of the Windows API, on reflection, I think we should use this facility for generating unprototyped 'omni' headers, and store them unprocessed, somewhere low priority, until called forth.

Then the overhead of using GetProcAddress is minimal anyway.
Title: Re: Late binding to DLL / Call DWORD equiv / (for Charles)
Post by: Mike Lobanovsky on March 09, 2018, 07:49:16 AM
Quote
... we should use this facility for generating unprototyped 'omni' headers ... low priority, until called forth

There is nothing more permanent than something temporary, postponed as a TODO till better times.

Now think about name mangling as in "@n" appended at the end of API names to denote their call stack size, or C-style "_" DLL API prefixes.

Dumping function declarations altogether IS very handy, I assure you. Try your "unprototyped" declares with explicit pointer and type identifiers in your API calls as per MSDN and DLL documentation, and you'll see how obviously logical and natural this scheme appears to be.

Try loading and mapping the 5 DLLs at app launch time and enjoy 2,500+ most usable Win32 SDK APIs at your immediate disposal on default without stirring a finger. ;)
Title: Re: Late binding to DLL / Unprototyped Windows Headers
Post by: Charles Pegge on March 11, 2018, 05:33:36 AM
Well, this is what I have come up with:

It works well without any further compiler optimisation. The extra compilation time is barely perceptible.

Code: [Select]
'2018-03-10 T 15:53:37

------------
'CoreWin.inc
============


'equates,types,macros
=====================

uses WinData


'dll declarations
=================

uses Kernel  '1595
uses User    '985
uses Gdi     '945
uses Comctl  '118
uses Comdlg  '28
uses Oleaut  '409
uses Shell   '484

'4564 declarations

The 'A' procedures use an alias, but the 'W' procedures are left intact, to call explicitly.

Comdlg.inc, for example:
Code: [Select]
extern lib "Comdlg32.dll"
! ChooseColor "ChooseColorA"
! ChooseColorW
! ChooseFont "ChooseFontA"
! ChooseFontW
! CommDlgExtendedError
! DllCanUnloadNow
! DllGetClassObject
! FindText "FindTextA"
! FindTextW
! GetFileTitle "GetFileTitleA"
! GetFileTitleW
! GetOpenFileName "GetOpenFileNameA"
! GetOpenFileNameW
! GetSaveFileName "GetSaveFileNameA"
! GetSaveFileNameW
! LoadAlterBitmap
! PageSetupDlg "PageSetupDlgA"
! PageSetupDlgW
! PrintDlg "PrintDlgA"
! PrintDlgEx "PrintDlgExA"
! PrintDlgExW
! PrintDlgW
! ReplaceText "ReplaceTextA"
! ReplaceTextW
! Ssync_ANSI_UNICODE_Struct_For_WOW
! WantArrows
! dwLBSubclass
! dwOKSubclass
end extern

Title: Re: Late binding to DLL / Attaching protptypes
Post by: Charles Pegge on March 11, 2018, 07:06:10 AM
A minor tweak to o2 allows prototypes to be 'attached' to unprototyped declarations.

In this messagebox example, default values are also specified:

Code: [Select]
'2018-03-11 T 10:13:29
'prototype overlay
uses corewin
'Create protype with default values for MessageBox
! messagebox(
  sys hwnd=0,
  char*text="",
  char*title="OxygenBasic",
  int mode=0
) at @messagebox
'
'TEST
messagebox
messagebox text="helo"

https://github.com/Charles-Pegge/OxygenBasic/blob/master/OxygenBasicProgress.zip


Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: José Roca on March 11, 2018, 07:20:46 AM
And what about the return type?
Title: Re: Late binding to DLL / Attaching prototypes
Post by: Charles Pegge on March 11, 2018, 07:58:00 AM
Sure,

) as int, at @messagebox

Even without a return type specified it will return an integer (in eax/rax)
Code: [Select]
'/*
'2018-03-11 T 15:55:30
'prototype overlay
uses corewin
'Create protype with default values for MessageBox
! messagebox(
  sys hwnd=0,
  char*text="",
  char*title="OxygenBasic",
  int mode=0
) as int, at @messagebox
'
'TEST
messagebox
a=messagebox text="helo", mode=1
print a
Title: Re: Late binding to DLL / Attaching prototypes
Post by: Charles Pegge on March 11, 2018, 09:59:02 AM
The return type may also be placed at the start, C-style. In this case, declare/! is omitted.

int messagebox( ...

Code: [Select]
'2018-03-11 T 17:55:05
'c-style prototype overlay
uses corewin
'Create protype with default values for MessageBox
int messagebox(
  sys hwnd=0,
  char*text="",
  char*title="OxygenBasic",
  int mode=0
) at @messagebox
'
'TEST
messagebox
a=messagebox text="helo", mode=2
print a
Title: Re: Late binding to DLL / Unprototyped Windows Headers
Post by: Mike Lobanovsky on March 11, 2018, 08:59:34 PM
I beg your pardon?

Do you mean to say we're in for yet another set of incompatible headers to worry about before we're able to yell our first hello into the world of computer programming?!

As with all similarly half-hearted design decisions, a few questions immediately spring to mind:(and most sarcastically)

I've submitted my reasons, and practical solutions, for doing away with declares altogether in my earlier messages in this thread.

Do not you deign to explain yourself, esteemed sir, as to why you preferred to dismiss them? I smell conspiracy in the air... ;)
Title: Re: Late binding to DLL / Unprototyped Windows Headers
Post by: Charles Pegge on March 11, 2018, 10:30:43 PM
Hi Mike,

MessageBox without the 'A': a modest compromise for the sake of common usage. At least we still have access to MessageBoxW in the same program. What's not to like? :)

Interesting that you raise the subject of name mangling. I have just been finessing o2's means of handling it:

! "_fname@4"

This will import the mangled '_fname@4' within the quotes, and extract 'fname' as the internal reference for it.
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: José Roca on March 11, 2018, 11:00:50 PM
IMO the default should be unicode. I don't understand why many people are still using the "A" functions with an OS like Windows, that is fully unicode. The "A" functions are wrappers that convert strings to unicode and then call the "W" functions. In my framework for FreeBasic I only use unicode.
Title: Re: Late binding to DLL / Unprototyped Windows
Post by: Mike Lobanovsky on March 12, 2018, 04:24:12 AM
Hi Charles,

Thank you for picking up the glove! :)

MessageBox without the 'A': a modest compromise for the sake of common usage.

This doesn't explain what I should do with my MessageBoxA!  ???

Interesting that you raise the subject of name mangling.

Actually I was raising it for the second time in this thread!  ::)

This will import the mangled '_fname@4' within the quotes, and extract 'fname' as the internal reference for it.

I agree that can handle the underscore prefixes and mangled postfixes. But you still won't be able to avoid aliases that would map ??3@YAXPAX@Z horrors into a limited subset of characters allowable in an intelligent language's function name. (that mumbo-jumbo is actually a real export from msvcrt.dll) :P

Now my question is, if you still need a pling, function name and alias to describe a single entry point among the 2,500+ first-aid APIs that you could have automated the entire process of importing, then why bother at all? Let us all fall prone before José and plead him to write a set of rock solid classic BASIC headers for us that we'll keep overlooking to supply, as is only natural for human beings, when deploying or exchanging our code? :)

I don't understand why many people are still using the "A" functions ...

Hi José,

I will tell you why.
Code: [Select]
//#AppType Console
#Option Strict

#DllDeclare Kernel32(GetModuleHandleW, LoadLibraryW)
#DllDeclare User32(RegisterClassExW, CreateWindowExW, LoadIconW, LoadCursorW, _
MessageBoxW, IsDialogMessageW, PeekMessageW, DispatchMessageW, DefWindowProcW, _
SendMessageW, PostMessageW, TranslateMessage, GetSystemMenu)
#DllDeclare Gdi32(CreateFontW)

// Window style constants
#Define ES_MULTILINE 4
#Define WS_OVERLAPPEDWINDOW &HCF0000
#Define WS_CLIPCHILDREN &H2000000
#Define WS_CLIPSIBLINGS &H4000000
#Define WS_HSCROLL &H100000
#Define WS_VSCROLL &H200000
#Define WS_VISIBLE &H10000000
#Define WS_CHILD &H40000000

// Window extended style constants
#Define WS_EX_NOPARENTNOTIFY 4
#Define WS_EX_WINDOWEDGE 256
#Define WS_EX_APPWINDOW &H40000

// Child control ID constants
#Define IDC_RICHEDIT &H1000
#Define IDC_BUTTON &H1001

// Global variables
Dim hindi = "{\rtf1\ansi\ansicpg1251\deff0\deflang1049{\fonttbl{\f0\fswiss\fcharset1 Mangal;}{\f1\fswiss Mangal;}}" & _
"{\colortbl ;\red192\green0\blue0;}\viewkind4\uc1\pard\qc\cf1\b\f0\fs20\u2330?\u2368?\u2344?\u2368? \u2360?\u2366?" & _
"\u2341?\u2367?\u2351?\u2379?\u2306? \u2325?\u2375? \u2346?\u2381?\u2352?\u2348?\u2354? \u2348?\u2343?\u2366?\u2312?\f1 !" & _
"\par\f0\u2346?\u2381?\u2352?\u2327?\u2340?\u2368? \u2310? \u2352?\u2361?\u2368? \u2361?\u2376?\f1 !\par}"
Dim malayalam = "{\rtf1\ansi\ansicpg1251\deff0\deflang1049{\fonttbl{\f0\fnil\fprq2\fcharset1 Akshar Unicode;}{\f1\fnil\fprq2 Akshar Unicode;}" & _
"{\f2\fnil\fprq2\fcharset0 Akshar Unicode;}}{\colortbl ;\red0\green35\blue255;}\viewkind4\uc1\pard\qc\cf1\f0\fs28\u3335?\u3368?\u3405?\u3364?" & _
"\u3405?\u3375?\u3451? \u3384?\u3350?\u3390?\u3349?\u3405?\u3349?\u3454? \u3378?\u3399?\u3349?\u3405?\u3349?\u3393?\u3379?\u3405?\u3379? \u3338?\" & _
"u3383?\u3405?\u3374?\u3379?\u3374?\u3390?\u3375? \u3334?\u3382?\u3330?\u3384?\u3349?\u3454?\f1 !\par\f0\u3370?\u3393?\u3376?\u3399?\u3390?" & _
"\u3351?\u3364?\u3391? \u3381?\u3376?\u3393?\u3368?\u3405?\u3368?\u3393?\f1 !\lang1033\f2\par}"
Dim font = CreateFontW(18, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 0, AnsiToWide("Akshar Unicode"))
Dim library = LoadLibraryW(AnsiToWide("riched20.dll"))
Dim window = Unicode_Form("Vinod's Unicode Special")
Dim button = Unicode_Control("Button", window, "Click me...", IDC_BUTTON, 670, 710, 90, 30, WS_CHILD BOr WS_VISIBLE)
Dim edit = Unicode_Control("RichEdit20W", window, "", IDC_RICHEDIT, _
212, 370, 370, 125, WS_CHILD BOr WS_VISIBLE BOr WS_VSCROLL BOr WS_HSCROLL BOr ES_MULTILINE)


// ================== EXECUTION STARTS HERE ====================
Sub Main()
  MakeNonResizable(window) // for artistic reasons
  If STANDALONE Then
    Fbsl_Tile(window, Fbsl_LoadImage(APPEXEPATH & "\Smile.jpg"))
  Else
    Fbsl_Tile(window, Fbsl_LoadImage(Left(Command(1), InStrRev(Command, "\")) & "Smile.jpg"))
  End If
  Resize(window, 0, 0, 800, 800)
  Center(window): Show(window)
 
  Unicode_Main()
End Sub
// =================== EXECUTION ENDS HERE =====================


// - Equivalent to FBSL built-in ASCII Begin Events/End Events -
Function Unicode_Events(ByVal hwnd As Integer, ByVal msg As Integer, ByVal wparam As Integer, ByVal lparam As Integer) As Integer
  #Define IDCANCEL 2
  #Define WM_CLOSE 16
  #Define WM_COMMAND 273
 
  Select Case msg
    Case WM_COMMAND
      If wparam = IDCANCEL Then
        PostMessageW(window, WM_CLOSE, 0, 0)
      ElseIf wparam = IDC_BUTTON Then
        OnClick()
        Return 0
      End If
    Case WM_CLOSE
      ExitProgram(0)
  End Select
  Return DefWindowProcW(hwnd, msg, wparam, lparam)
End Function

Sub Unicode_Main()
  #Define CS_DBLCLKS 8
  #Define WM_QUIT 18
  #Define PM_REMOVE 1
 
  Type MESSAGE
    hWnd As Integer
    message As Integer
    wParam As Integer
    lParam As Integer
    dwTime As Integer
    ptX As Integer
    ptY As Integer
  End Type
 
  Dim msg As MESSAGE
 
  While 1
    PeekMessageW(@msg, 0, 0, 0, PM_REMOVE)
    If msg.message = WM_QUIT Then Exit While
    If Not IsDialogMessageW(window, @msg) Then
      TranslateMessage(@msg)
      DispatchMessageW(@msg)
    End If
  WEnd
End Sub
// -------------------------------------------------------------

// ---------------------- Event handlers -----------------------
Sub OnClick()
  #Define WM_SETTEXT 12
 
  SendMessageW(button, WM_SETTEXT, 0, AnsiToWide("Clicked!"))
  Edit_Append(edit, hindi)
  Edit_Append(edit, malayalam)
End Sub

// ---------------------- Window creation ----------------------
Function Unicode_Form(FormTitle As String, _
  X As Integer = 0, Y As Integer = 0, Width As Integer = 320, Height As Integer = 200, _
  hWndOwner As Integer = NULL) As Integer
 
  #Define IDI_APPLICATION 32512
  #Define IDC_ARROW 32512
  #Define COLOR_BTNFACE 15
 
  Type WNDCLASSEXW
    cbSize As Integer
    style As Integer
    lpfnWndProc As Integer
    cbClsExtra As Integer
    cbWndExtra As Integer
    hInstance As Integer
    hIcon As Integer
    hCursor As Integer
    hbrBackground As Integer
    lpszMenuName As Integer
    lpszClassName As Integer
    hIconSm As Integer
  End Type
 
  Dim wcx As WNDCLASSEXW, szClassName = AnsiToWide("_FBSL_UNICODE_")
 
  wcx.cbSize = LenB(wcx)
  wcx.style = CS_DBLCLKS
  wcx.lpfnWndProc = AddressOf Unicode_Events
  wcx.hInstance = GetModuleHandleW(NULL)
  wcx.hIcon = LoadIconW(GetModuleHandleW, 101)
  wcx.hCursor = LoadCursorW(NULL, IDC_ARROW)
  wcx.hbrBackground = COLOR_BTNFACE + 1
  wcx.lpszClassName = @szClassName
  If Not RegisterClassExW(@wcx) Then
    MessageBoxW(NULL, $AnsiToWide("Unable to register Unicode window class"), $AnsiToWide("Error" & Chr(0)), 0)
    ExitProgram(-1)
  End If
 
  Dim hwin = CreateWindowExW( _
    WS_EX_APPWINDOW BOr WS_EX_WINDOWEDGE, _
    szClassName, AnsiToWide(FormTitle & Chr(0)), _
    WS_OVERLAPPEDWINDOW BOr WS_CLIPSIBLINGS BOr WS_CLIPCHILDREN, _
    X, Y, Width, Height, _
    NULL, NULL, GetModuleHandleW, NULL)
  If Not hwin Then
    MessageBoxW(NULL, $AnsiToWide("Unable to create Unicode window"), $AnsiToWide("Error" & Chr(0)), 0)
    ExitProgram(-1)
  End If
 
  Return hwin
End Function

Function Unicode_Control(ClassName As String, hWndParent As Integer, Caption As String, hCtlID As Integer = 0, _
  X As Integer = 0, Y As Integer = 0, Width As Integer = 0, Height As Integer = 0, _
  Style As Integer = WS_CHILD BOr WS_VISIBLE, XStyle As Integer = 0) As Integer
 
  #Define WM_SETFONT 48
 
  Dim hctl = CreateWindowExW( _
    XStyle, _
    $AnsiToWide(ClassName & Chr(0)), $AnsiToWide(Caption & Chr(0)), _
    Style, _
    X, Y, Width, Height, _
    hWndParent, hCtlID, GetModuleHandleW(NULL), NULL)
  If Not hctl Then
    MessageBoxW(NULL, $AnsiToWide("Unable to create Unicode control"), $AnsiToWide("Error" & Chr(0)), 0)
    ExitProgram(-1)
  End If
  SendMessageW(hctl, WM_SETFONT, font, TRUE)
 
  Return hctl
End Function

// ------------------------- Utilities -------------------------
Sub MakeNonResizable(hwnd As Integer)
  #Define WS_MAXIMIZEBOX &H10000
  #Define WS_MINIMIZEBOX &H20000
  #Define SC_SIZE &HF000
  #Define SC_MINIMIZE &HF020
  #Define SC_MAXIMIZE &HF030
  #Define SC_RESTORE &HF120
  #Define MF_BYCOMMAND 0
 
  Style_Remove(hwnd, WS_MINIMIZEBOX BOr WS_MAXIMIZEBOX)
  DeleteMenu(GetSystemMenu(hwnd, FALSE), SC_SIZE, MF_BYCOMMAND)
  DeleteMenu(GetSystemMenu, SC_MINIMIZE, MF_BYCOMMAND)
  DeleteMenu(GetSystemMenu, SC_MAXIMIZE, MF_BYCOMMAND)
  DeleteMenu(GetSystemMenu, SC_RESTORE, MF_BYCOMMAND)
End Sub

Sub Edit_Append(who As Integer, what As String)
  #Define ST_SELECTION 2
  #Define EM_SETTEXTEX 1121
 
  Type SETTEXTEX
    flags As Integer
    codepage As Integer
  End Type
 
  Dim ste As SETTEXTEX: ste.flags = ST_SELECTION
 
  SendMessageW(who, EM_SETTEXTEX, @ste, what)
End Sub


(BTW José, I find it extremely difficult to handle diacritics on my standard primary US English/secondary Cyrillic keyboard. Every time I type your name, I have to walk an extra mile to your site and use copy-paste to spell it "politically" correctly. Can I have your kind permission to spell it henceforth as Jose rather than José in my, er, simplified Anglo-Saxon? :) )
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: Charles Pegge on March 12, 2018, 05:57:12 AM
Hi Mike,

I quite like the plings! At least they are an improvement on declare function, and pass through the compiler pronto.I might even be able to shorten the route further.

And yes, I have encountered those dreadfully mangled names in MSVCRT, they are clearly not intended for public use, so I am deftly applying /* ... */ to all 58 of them.

Updated CoreWin list:
Code: [Select]
uses Kernel  '1595
uses User    '985
uses Gdi     '945
uses Comctl  '118
uses Comdlg  '28
uses Oleaut  '409
uses Shell   '484
uses Msvcrt  '1429 -58

'5935 declarations



PS Does Alt (keypad)130 é work for you?
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: jcfuller on March 12, 2018, 06:02:53 AM
Mike,
  I find it extremely easy to do ansi/unicode with the same bc9 source thanks to a coulple of bcx'ers who wrote a utility to do ansi->unicode. I do not do unicode file IO though.

Charles,
  that's what I use for é
 
James


Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: José Roca on March 12, 2018, 06:16:50 AM
> Can I have your kind permission to spell it henceforth as Jose rather than José in my, er, simplified Anglo-Saxon? :) )

Of course. You can also use Josep, which is my name in Valencian, my mother language, or Pepe or Pep, that are popular familiar abbreviations.
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: Mike Lobanovsky on March 12, 2018, 06:26:43 AM
Quote
PS Does Alt (keypad)130 é work for you?

Psst! I also have a bunch of French friends, and they have a ton of accents in their names, and they agreed to my omissions, and they'll all be after my head if they ever see me still using the numpad in someone else's name! :D

I know POTs by heart and I can read binary numbers but I'm finding it progressively more and more difficult to recollect my wife's phone number. Do you want me to learn by heart the entire Alt code table for at least courier.ttf? Then Aurel will also demand I use literal ć in his last name...  ::)

What about calling me Михаил for a change, guys? Hope you have the Cyrillic pack installed to be able to see what it looks like in reality? ;D


@Jose:

Thank you very much! Jose will do just fine for me, and let's leave Pep for your buddies and relatives. :)


[EDIT] As an afterthought, BTW are y'all aware there are a lot of compact cheap throw-away keyboards around without the numpad extension targeted for people to whom size matters or every buck counts? Also, typical QWERTY WASD PC game control is impractical on AZERTY layouts used in France, Germany, etc?
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: José Roca on March 12, 2018, 07:06:11 AM
Quote
How many businesses that are still dependent on PB would ever need anything but ASCII in their programs, do you think?

In fact, PB DDTers's are using unicode without realizing it. Since PB 10+, DDT dialogs are unicode aware.

Quote
How many Indians, Chinese or Japanese followers do you think Charles is ever going to have?

None, if you insist in using ascii instead of unicode. There are a couple of Chinese guys translating the documentation of my framework for FreeBasic to his language. There is also an Indian guy that has started to use it.

Using it with Paul Squire's WinFBE editor and my CWSTR class you can do something like:

Code: [Select]
#include once "Afx/CWStr.inc"

DIM cws AS CWSTR = "Дмитрий Дмитриевич Шостакович"

DIM f AS LONG = FREEFILE
OPEN "test.txt" FOR OUTPUT ENCODING "utf16" AS #f
PRINT #f, cws
CLOSE #f

That is WYSIWYG unicode programming as easy as using ascii.
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: Mike Lobanovsky on March 12, 2018, 07:32:43 AM
Since PB 10+, DDT dialogs are unicode aware.

(10+) - 1 = (9+) versions seems like a long way indeed before adding "final touches", doesn't it?

But frankly, I do acknowledge the importance of Unicode, and that's why I suggested Charles make his A/W-less aliases bitness-dependent while OxygenBasic is still in a relatively early phase of development. This will help automate, to a significant extent, platform independent code development and smoother transition from ANSI to Unicode practices.

Yet I'd rather O2 fully supports both A and W API name versions alongside their respective "unisex" aliases in both 32-bit and 64-bit environments. Let's leave the final choice of names in all its variety to the end user.
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: Arnold on March 12, 2018, 08:35:38 AM
I am afraid but it seems I cannot use unicode with OxygenBasic. I tried this little code:

Code: [Select]
use corewin

wstring russian = "Привет, Михаил"
wstring caption = "Nice to meet you"

MessageBoxW null, russian, caption ,0

If I save this as Ansi and run the code I will get this output in a MessageBox:

Nice to meet you
(6 question marks, 6 question marks)

If I save the code as UTF-16 LE, I cannot even run the code (ASM ERR Line 1)

Is there a special trick to run unicode with OxygenBasic? The only example I found is examples\WideStrings\ReadUnicode.o2bas

Roland
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: Charles Pegge on March 12, 2018, 10:07:43 AM
Hi Roland,

Are you using unicode source code? I have not designed for that yet. But you should be able to getfile a unicode text, and do things with it using wstrings.
Title: Re: Late binding to DLL / Call DWORD equiv / (for Arnold)
Post by: Mike Lobanovsky on March 12, 2018, 05:27:37 PM
Is there a special trick to run unicode with OxygenBasic?

You could probably use a hidden RichEdit20W and BOM-less UTF-8 to do the conversion for you but that would not be a "trick" but rather a "hack".

But thanks for trying to impress me anyway Roland, and howdy yourself! :)
Title: Re: Late binding to DLL / Call DWORD equiv / (for Charles)
Post by: Mike Lobanovsky on March 12, 2018, 07:19:36 PM
... dreadfully mangled names in MSVCRT, they are clearly not intended for public use ...

Actually those are the C++ public exports I was referring to in my earlier messages here. :D

Quote
... they are an improvement on declare function, and pass through the compiler pronto ...

That's it!

Should you also agree to use type identifier prefixes rather than classic BASIC postfixes, OxygenBasic's parser may become the prontoest parser around. (after FBSL of course) :D
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: Aurel on March 12, 2018, 10:07:06 PM
I don't know for you but I know what work for me and work fine
it is as I said VB way of declares .Also there are plenty of them on net.
Another thing ..i don't need unicode because o2 is ansi..
..all this talks reminds me that i must remove instruction bind from my include.
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: Arnold on March 13, 2018, 10:54:36 AM
After searching in Internet for unicode I found a lot of explanations, definitions, tables and discussions, but no real working sample with exception of MASM32. Here I found the only examples which made sense to me. I took one of them and ported it to OxygenBasic.

To use unicode text I can use stringtables in a resource file, compile the .rc file with GoRC and link the .res file with LinkRes2Exe.exe to the executable. The resource file must be created as a unicode text file, which can be edited e.g. with WordPad.

And yes, to display the unicode text of the application I must use the "W" functions. I now know it is possible to use unicode with Oxygenbasic, but as I am not able to speak any of these languages, or can use the necessary keyboards, I will stay with Ansi and be happy.

I attached the necessary files to build the application. If the path of OxygenBasic is different, then in BuildMulti.bat o2dir must be adjusted, and in multi.rc (using at least Wordpad) the path for oxicon.ico must be corrected too.

Roland

Code: OxygenBasic
  1. '====================================================================
  2. ' Multi-lingual example, simple modal dialog as main.
  3. '====================================================================
  4. ' ported from MASM32 example to OxygenBasic
  5.  
  6. $ filename "Multi_lingual.exe"
  7.  
  8. 'use rtl32
  9. use rtl64
  10.  
  11. '% review
  12.  
  13. use corewin
  14.  
  15. uses dialogs
  16. 'namespace
  17.  
  18. % DS_CENTER=0x0800
  19. % WM_SETICON=128
  20.  
  21. ==============================================
  22.  
  23. 'MAIN CODE
  24. =============================================
  25.  
  26. 'dim nCmdline as asciiz ptr, hInstance as sys
  27. '&nCmdline = GetCommandLine
  28. hInstance = GetModuleHandle(NULL)
  29.  
  30. Init_common_controls()
  31.  
  32. function DialogProc( sys hDlg, uint uMsg, sys wParam, lParam ) as int callback
  33.  
  34.   wstring pbuf = space 260
  35.  
  36.   select case uMsg
  37.  
  38.     case WM_INITDIALOG
  39.        hStat0 = GetDlgItem(hDlg,1250)
  40.        hStat1 = GetDlgItem(hDlg,1251)
  41.        hStat2 = GetDlgItem(hDlg,1252)
  42.        hStat3 = GetDlgItem(hDlg,1253)
  43.        hStat4 = GetDlgItem(hDlg,1254)
  44.        hStat5 = GetDlgItem(hDlg,1255)
  45.        hStat6 = GetDlgItem(hDlg,1256)
  46.        hStat7 = GetDlgItem(hDlg,1257)
  47.        hStat8 = GetDlgItem(hDlg,1258)
  48.        hStat9 = GetDlgItem(hDlg,1259)
  49.        hStat10 =GetDlgItem(hDlg,1260)      
  50.  
  51.        SendMessage (hDlg, WM_SETICON,1, LoadIcon(hInstance,500))
  52.        
  53.        LoadStringW (hInstance,250,pbuf,260)
  54.        SetWindowTextW (hStat0,pbuf)
  55.  
  56.        LoadStringW (hInstance,251,pbuf,260)
  57.        SetWindowTextW (hStat1,pbuf)
  58.  
  59.        LoadStringW (hInstance,252,pbuf,260)
  60.        SetWindowTextW (hStat2,pbuf)
  61.  
  62.        LoadStringW (hInstance,253,pbuf,260)
  63.        SetWindowTextW (hStat3,pbuf)
  64.  
  65.        LoadStringW (hInstance,254,pbuf,260)
  66.        SetWindowTextW (hStat4,pbuf)
  67.  
  68.        LoadStringW (hInstance,255,pbuf,260)
  69.        SetWindowTextW (hStat5,pbuf)
  70.  
  71.        LoadStringW (hInstance,256,pbuf,260)
  72.        SetWindowTextW (hStat6,pbuf)
  73.  
  74.        LoadStringW (hInstance,257,pbuf,260)
  75.        SetWindowTextW (hStat7,pbuf)
  76.  
  77.        LoadStringW (hInstance,258,pbuf,260)
  78.        SetWindowTextW (hStat8,pbuf)
  79.  
  80.        LoadStringW (hInstance,259,pbuf,260)
  81.        SetWindowTextW (hStat9,pbuf)
  82.  
  83.        LoadStringW (hInstance,260,pbuf,260)
  84.        SetWindowTextW (hStat10,pbuf)
  85.        
  86.  
  87.     case WM_COMMAND
  88.       select case loword(wParam)
  89.         case IDCANCEL, IDOK
  90.            EndDialog( hDlg, null )
  91.       end select
  92.      
  93.     case WM_CLOSE
  94.       EndDialog( hDlg, null )
  95.                
  96.   end select
  97.  
  98.   return 0
  99. end function
  100.  
  101. sub winmain()
  102.  
  103.   sys lpdt
  104.  
  105.   'provide memory for DLGTEMPLATE structure etc    
  106. '  dyn::init(lpdt,nBytes)
  107.  dyn::init(lpdt,5000) '1024
  108.  
  109.   Dialog( 23,  10,10,360,183, "Multi-Lingual Support", lpdt,
  110.           WS_VISIBLE|WS_CAPTION|WS_SYSMENU|DS_CENTER or DS_SETFONT,
  111.           8,"MS Sans Serif" )
  112.   CONTROL "Chinese : ",1000,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_RIGHT,18,14,56,10
  113.   CONTROL "Japanese : ",1001,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_RIGHT,18,26,56,10
  114.   CONTROL "Russian : ",1002,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_RIGHT,18,38,56,10
  115.   CONTROL "Greek : ",1003,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_RIGHT,18,50,56,10
  116.   CONTROL "Hindi : ",1004,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_RIGHT,18,62,56,10
  117.   CONTROL "Vietnamese : ",1005,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_RIGHT,18,74,56,10
  118.   CONTROL "Georgian : ",1006,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_RIGHT,18,86,56,10
  119.   CONTROL "Serbian : ",1007,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_RIGHT,18,98,56,10
  120.   CONTROL "Armenian : ",1008,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_RIGHT,18,110,56,10
  121.   CONTROL "Korean : ",1009,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_RIGHT,21,123,56,10
  122.   CONTROL "English:",1010,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_RIGHT,18,136,56,10
  123.   CONTROL "Chinese",1250,"Static",WS_CHILDWINDOW|WS_VISIBLE,76,14,268,10
  124.   CONTROL "Japanese",1251,"Static",WS_CHILDWINDOW|WS_VISIBLE,76,26,268,10
  125.   CONTROL "Russian",1252,"Static",WS_CHILDWINDOW|WS_VISIBLE,76,38,268,10
  126.   CONTROL "Greek",1253,"Static",WS_CHILDWINDOW|WS_VISIBLE,76,50,268,10
  127.   CONTROL "Hindi",1254,"Static",WS_CHILDWINDOW|WS_VISIBLE,76,62,268,10
  128.   CONTROL "Vietnamese",1255,"Static",WS_CHILDWINDOW|WS_VISIBLE,76,74,268,10
  129.   CONTROL "Georgian",1256,"Static",WS_CHILDWINDOW|WS_VISIBLE,76,86,268,10
  130.   CONTROL "Serbian",1257,"Static",WS_CHILDWINDOW|WS_VISIBLE,76,98,268,10
  131.   CONTROL "Armenian",1258,"Static",WS_CHILDWINDOW|WS_VISIBLE,76,110,268,10
  132.   CONTROL "Korean",1259,"Static",WS_CHILDWINDOW|WS_VISIBLE,78,123,268,10
  133.   CONTROL "English",1260,"Static",WS_CHILDWINDOW|WS_VISIBLE,78,136,268,10
  134.   CONTROL "OK",IDOK,"Button",WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,288,156,56,14
  135.  
  136.   CreateModalDialog( null, @DialogProc, 0, lpdt )
  137. end sub
  138.  
  139. winmain()
  140.  
Title: Re: Late binding to DLL / Call DWORD equiv / (for Arnold)
Post by: Mike Lobanovsky on March 13, 2018, 12:04:30 PM
Roland,

Your Russian translation reads literally "The programmer is best in the morning" but I got the idea. Good morning to you too, colleague! :D

Thanks for sharing this working example and walking an extra mile to prove once again OxygenBasic is alive and kicking! :)
Title: Re: Late binding to DLL / Unicode min demo
Post by: Charles Pegge on March 13, 2018, 09:04:39 PM
Many thanks, Roland. I would like to include your demo in WinDynDialogs.

Here is a minimal demo:

note the casting on Getfile. It is only byte-aware.

Code: [Select]
'2018-03-14 T 04:10:15
'UNICODE LOADING AND DISPLAY
% filename "t.exe"
'use rtl64
use corewin
wstring ws
ws=(wstring) getfile "t.txt"
messageboxW 0,ws,"",0
'
'EXAMINE UNICODING
word ww at strptr ws
string t
for i=1 to 512
  t+=hex(ww[i],4)+"  "
next
print t
Title: Re: Late binding to DLL / Unicode min demo
Post by: Mike Lobanovsky on March 14, 2018, 01:25:04 AM
I would like to include your demo in WinDynDialogs.

Good morning, computer programmers!

If you decide to add the demo to the distro, please use the following Russian demo string:

Доброе утро, программист!  (and note the punctuation)

It says exactly what its English equivalent does.
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: Arnold on March 14, 2018, 02:03:46 AM
Hi Mike,

I only copied the text to Google translator and checked if the characters looked similar and I have no idea if the translation was correct in each case. I always was jealous of the people in my neighborhood who grew up multilingual. For me it is already difficult to learn only the alphabet of these languages. Maybe I will try Esperanto.

Roland
Title: Re: Late binding to DLL / Call DWORD equiv / (for Arnold and Jose)
Post by: Mike Lobanovsky on March 14, 2018, 03:55:39 AM
Hi Roland,

I wasn't trolling. I was rather encouraging you to continue your explorations. I like to watch, and I appreciate, your unfailing perseverance in attaining your goals. :)

Be forewarned however that, despite Jose's reasoning, there are two inarguable facts (sorta natural phenomena) that should be taken into account:
Title: Re: Late binding to DLL / Unicode source code
Post by: Charles Pegge on March 14, 2018, 09:43:13 AM
I'll investigate the feasability of using unicode source code in o2. You could have variable names in greek, or even  Cyrillic :).  It opens up new possibilities
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: JRS on March 14, 2018, 11:23:43 AM
Languages of the internet

English  (27.3%)
Chinese (22.6%)
Spanish (7.8%)
Japanese (5.3%)
Portuguese (4.3%)
German (4.0%)
Arabic   (3.3%)
French  (3.2%)
Russian (2.5%)
Korean (2.1%)

Title: Re: Late binding to DLL / Call DWORD equiv / (for John and Charles)
Post by: Mike Lobanovsky on March 14, 2018, 12:40:42 PM
John,

If we however re-evaluate this list from the business perspective of a commercial project and customer solvency, we may as well forget anything that comes below Item #1. So no wonder PB Inc. couldn't care less for Unicode. ;)

You could have variable names in ... Cyrillic :).  It opens up new possibilities

Oh no, not again! There's the so called 1C:Enterprise business management software package on the Russian market that's in fact their own "strategic" alternative to such US packages as SAP or Sage. Its client side scripting is implemented as a Russian-only "visual basic". I used to do a lot of that stuff in my greener years, and frankly, I've never seen more weird and cryptic code ever since.

Matter is, a non-native English programmer (including me) never perceives an ordinary programming language's vocab as anything humanly meaningful. That's just a set of conventional cryptic symbols or tokens one has to learn by heart to denote certain actions the computer is supposed to perform. The same regards var names, equates, common abbreviations, metadata etc.

But when I see code written totally in Russian, first I'd shake my head to drive away the delusion, then I'd wipe my glasses, and then I'd burst with laughter at Russian imperative Do/Loop's, While/Wend's, IIf's and End If's. ;D

My deepest condolences and sympathy to my English speaking friends being forced to do this every single day of their lives. ;D
Title: Re: Late binding to DLL / Unicode source code
Post by: Charles Pegge on March 14, 2018, 02:30:36 PM
Perhaps extending the repertoire of symbols available for use. After all, Physicists and Mathematicians, like to use their own special symbols. Another advantage would be to express unicode string literals directly in the source code.

Creating a few mockups would help to explore the idea.
Title: Re: Late binding to DLL / Call DWORD equiv / (for Ray)
Post by: Arnold on March 15, 2018, 02:31:28 AM
Hi Charles,

I agree with Mike. There should be no special need for coding in unicode. I always used ascii or ansi but was never aware of this. With my code editor (PSPad) I can save the code in several formats and I tried this with a small c program:
Compiling using gcc 4.8.1 / tcc 0.9.27 worked with ansi, oem, iso 8859-2, utf-8, it failed with utf-16 LE, utf-16 BE. I get the same results when running .o2bas files. Therefore I think Oxygen is compliant with other programming languages. And your Unicode min demo and examples\WideStrings\ReadUnicode.o2bas is already very helpful to see the principles of using unicode. And I noticed there are several libraries available if there would be full unicode support required. (I suppose I will never need them)

Roland
Title: Re: Late binding to DLL / Unicode source code
Post by: Charles Pegge on March 15, 2018, 04:38:47 AM
Thank you both.

From my insider point of view, converting to direct unicode source compiling would be quite disruptive. The best way of dealing with unicode source would be to create a front-end counterpart of co2, a uco2.

This would be the most efficient way to implement other dialects of Basic, and other experimental languages.