NO

Author Topic: Dynamic array of structures or pointers  (Read 7829 times)

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Dynamic array of structures or pointers
« on: January 30, 2024, 01:11:45 PM »
In many applications we would like to have same functionalities of C++ vectors with all their rich set of methods to handle dynamic arrays of data structures or pointers.
It would be very nice to have possibility to add, remove and insert items at random positions, expand and squeeze your array as needed  ::)
If you don't want to spend time to write your personal library for that you can use the DPA (Dynamic Pointers Array) and DSA (Dynamic Structure Array) already coded and, presumably  >:(, tested for you in the ComCtl32.dll library.
Below an example of the possibilities:
Code: [Select]
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
HDSA hDsa = DSA_Create(sizeof(char[32]), 2);

printf("------ Writing the array ------\n");
for (int i=0; i<20; i++)
{
char str[32];
sprintf(str, "Test%2d", i+1);
printf ("  - Appending string \"%s\".\n", str);
//DSA_GetSize present in COMCTL32.DLL V.6.00.00
//printf ("  - Appending string \"%s\". Actual array size = %llu\n", str, DSA_GetSize(hDsa));
DSA_AppendItem(hDsa, str);
}
printf("------ Reading the array ------\n");
int cItems = DSA_GetItemCount(hDsa);
for (int i=0; i<cItems; i++)
{
char str[32];
DSA_GetItem(hDsa, i, str);
printf ("  - Read string \"%s\".\n", str);
}
printf("------ Invert the array ------\n");
//DSA_Sort(hDsa, fn_compare, 0); //DSA_Sort present in COMCTL32.DLL V.6.00.00
cItems = DSA_GetItemCount(hDsa);
for (int i=0; i<cItems/2; i++)
{
char str[32];
memcpy(str, DSA_GetItemPtr(hDsa, i), sizeof(str));
memcpy(DSA_GetItemPtr(hDsa, i), DSA_GetItemPtr(hDsa, cItems - i - 1), sizeof(str));
memcpy(DSA_GetItemPtr(hDsa, cItems - i - 1), str, sizeof(str));
}
printf("------ Reading the array ------\n");
cItems = DSA_GetItemCount(hDsa);
for (int i=0; i<cItems; i++)
{
char *str = DSA_GetItemPtr(hDsa, i);
printf ("  - Read string \"%s\".\n", str);
}
printf("------ Invert again the array ------\n");
cItems = DSA_GetItemCount(hDsa);
for (int i=0; i<cItems/2; i++)
{
char str[32];
memcpy(str, DSA_GetItemPtr(hDsa, i), sizeof(str));
memcpy(DSA_GetItemPtr(hDsa, i), DSA_GetItemPtr(hDsa, cItems - i - 1), sizeof(str));
memcpy(DSA_GetItemPtr(hDsa, cItems - i - 1), str, sizeof(str));
}
printf("------ Remove odd items from the array ------\n");
cItems = DSA_GetItemCount(hDsa);
for (int i=0; i<cItems/2; i++)
DSA_DeleteItem(hDsa, i);
printf("------ Reading the array ------\n");
cItems = DSA_GetItemCount(hDsa);
for (int i=0; i<cItems; i++)
{
char *str = DSA_GetItemPtr(hDsa, i);
printf ("  - Read string \"%s\".\n", str);
}
printf("------ Add odd items after even items in the array ------\n");
cItems = DSA_GetItemCount(hDsa);
for (int i=0; i<cItems*2; i+=2)
{
char str[32];
sprintf(str, "Test%2d", i+1);
printf ("  - Adding string \"%s\".\n", str);
DSA_InsertItem(hDsa, i+1, str);
}
printf("------ Reading the array ------\n");
cItems = DSA_GetItemCount(hDsa);
for (int i=0; i<cItems; i++)
{
char *str = DSA_GetItemPtr(hDsa, i);
printf ("  - Read string \"%s\".\n", str);
}
printf("------ Reading directly the array ------\n");
cItems = DSA_GetItemCount(hDsa);
char (*first)[32] = DSA_GetItemPtr(hDsa, 0);
for (int i=0; i<cItems; i++)
{
printf ("  - Read string \"%s\".\n", first[i]);
}
printf("------ Destroy the array ------\n");
DSA_Destroy(hDsa);

return 0;
}

EDIT: I forget to say that the array can be accessed as a standard array using the pointer to the first element as array address. See last part of the example above updated with the feature.
« Last Edit: January 31, 2024, 02:50:43 PM by frankie »
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: Dynamic array of structures or pointers
« Reply #1 on: January 30, 2024, 02:53:46 PM »
Hi Frankie,

That's a nice one, thanks :)

I checked with Masm32 and found out that the declarations are all there, but we never used DSA_*, except for one post by Donkey 12 years ago. Astonishing 8)

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2122
Re: Dynamic array of structures or pointers
« Reply #2 on: January 30, 2024, 04:08:18 PM »
Nice  :)

This usually helps these examples
Code: [Select]
#define WIN32_LEAN_AND_MEAN
...
#pragma comment(lib, "comctl32.lib")
...
May the source be with you

Online Vortex

  • Member
  • *
  • Posts: 870
    • http://www.vortex.masmcode.com
Re: Dynamic array of structures or pointers
« Reply #3 on: January 30, 2024, 05:53:53 PM »
Hi Frankie,

Thanks. Here is my report of Windows 7 SP1 64-bit, the list of exported functions with the leading symbol DSA_ :

Code: [Select]
E:\PellesC\Bin>podump.exe /EXPORTS C:\Windows\System32\comctl32.dll | findstr "DSA_"
            140    1E  000007FF75870770  DSA_Create
            147    1F  000007FF75870B58  DSA_DeleteAllItems
            146    20  000007FF75870AA0  DSA_DeleteItem
            141    21  000007FF758707B8  DSA_Destroy
            184    22  000007FF75870878  DSA_DestroyCallback
            183    23  000007FF7587080C  DSA_EnumCallback
            142    24  000007FF7587089C  DSA_GetItem
            143    25  000007FF758708D8  DSA_GetItemPtr
            144    26  000007FF758709C8  DSA_InsertItem
            145    27  000007FF758708F4  DSA_SetItem
« Last Edit: January 30, 2024, 07:01:28 PM by Vortex »
Code it... That's all...

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: Dynamic array of structures or pointers
« Reply #4 on: January 30, 2024, 06:55:01 PM »
There should be some more, e.g. DSA_Sort

Code: [Select]
DSA_AppendItem macro
DSA_Clone function
DSA_Create function
DSA_DeleteAllItems function
DSA_DeleteItem function
DSA_Destroy function
DSA_DestroyCallback function
DSA_EnumCallback function
DSA_GetItem function
DSA_GetItemCount macro
DSA_GetItemPtr function
DSA_GetSize function
DSA_InsertItem function
DSA_SetItem function
DSA_Sort function

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2122
Re: Dynamic array of structures or pointers
« Reply #5 on: January 30, 2024, 09:39:41 PM »
COMCTL32 Functions
Quote
DSA_Sort   6.10 and higher   documented
In my Windows 7 it is 5.82.7601.18837

But in C:\Windows\winsxs 6.10.7601
so have to use manifest for that
perhaps:
Code: [Select]
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
« Last Edit: January 30, 2024, 09:53:09 PM by TimoVJL »
May the source be with you

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: Dynamic array of structures or pointers
« Reply #6 on: January 31, 2024, 09:31:28 AM »
MS documentation says:
Quote
DSA_GetItem is not exported by name. To use it, you must use GetProcAddress and request ordinal 322 from ComCtl32.dll to obtain a function pointer.
Quote
DSA_SetItem is not exported by name. To use it, you must use GetProcAddress and request ordinal 325 from ComCtl32.dll to obtain a function pointer.
Quote
DSA_DeleteItem is not exported by name. To use it, you must use GetProcAddress and request ordinal 326 from ComCtl32.dll to obtain a function pointer.
But in WIN10 all the three are available and exported by name.
The functions DSA_GetSize() and DSA_Sort() instead have been completely removed, they are no more available by name not by ordinal.
This means that in different OS versions there are different functions available.

In the case as documented you can workaround changing only a the DSA_Create() functions defining a new function DSA_New() as in the following snippet:
Code: [Select]
#include <windows.h>
#define DSA_DeleteItem DSA_DeleteItem_org
#define DSA_GetItem DSA_GetItem_org
#define DSA_SetItem DSA_SetItem_org
#include <commctrl.h>
#undef DSA_DeleteItem
#undef DSA_GetItem
#undef DSA_SetItem
#include <stdio.h>

#define DSA_GETITEM_ORDINAL 322
#define DSA_SETITEM_ORDINAL 325
#define DSA_DELETEITEM_ORDINAL 326

extern BOOL WINAPI (*DSA_GetItem)(HDSA hdsa, int  i, void *pitem)      = NULL;
extern BOOL WINAPI (*DSA_SetItem)(HDSA hdsa, int i, const void *pitem) = NULL;
extern BOOL WINAPI (*DSA_DeleteItem)(HDSA hdsa, int i)                 = NULL;

HDSA DSA_New(int cbItem, int cItemGrow)
{
if (!DSA_GetItem)
{
/*
* Initialize function addresses for unexported functions
*/
DSA_GetItem    = GetProcAddress(GetModuleHandle("ComCtl32.dll"), MAKEINTRESOURCE(DSA_GETITEM_ORDINAL));
DSA_SetItem    = GetProcAddress(GetModuleHandle("ComCtl32.dll"), MAKEINTRESOURCE(DSA_SETITEM_ORDINAL));
DSA_DeleteItem = GetProcAddress(GetModuleHandle("ComCtl32.dll"), MAKEINTRESOURCE(DSA_DELETEITEM_ORDINAL));
}

/*
* Create the Dynamic structure array.
*/
return DSA_Create(cbItem, cItemGrow);
}
The missing functions DSA_GetSize() and DSA_Sort() are not a problem, the first have no practical use, the second could be easily implemented.
« Last Edit: February 01, 2024, 02:06:17 PM by frankie »
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: Dynamic array of structures or pointers
« Reply #7 on: January 31, 2024, 10:49:50 AM »
Quote
The functions DSA_GetSize() and DSA_Sort() instead have been completely removed, they are no more available by name not by ordinal.

It seems not all of Microsoft have realised that change 8)

https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/UI/Controls/fn.DSA_Sort.html
Quote
Function windows::Win32::UI::Controls::DSA_Sort

pub unsafe fn DSA_Sort<P0, P1>(
    pdsa: P0,
    pfncompare: PFNDACOMPARE,
    lparam: P1
) -> BOOL

Are you sure it's no longer there?
DSA_Sort
Sorts the items in a dynamic structure array (DSA).
Minimum supported client   Windows 10 Build 20348
« Last Edit: January 31, 2024, 10:53:37 AM by jj2007 »

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: Dynamic array of structures or pointers
« Reply #8 on: January 31, 2024, 11:37:14 AM »
Are you sure it's no longer there?
DSA_Sort
Sorts the items in a dynamic structure array (DSA).
Minimum supported client   Windows 10 Build 20348
In my win10 system are missing. See picture.
The function DSA_GetSize() has ordinal 348, and the function DSA_Sort() has ordinal 346, they are missing from DLL exports with name and ordinal.
I will test agains win10SDK libraries to see if the ordinal change....  :o not very likely anyway  ::)
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2122
Re: Dynamic array of structures or pointers
« Reply #9 on: January 31, 2024, 11:55:22 AM »
Code: [Select]
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
int __cdecl main(void)
{
char szFile[MAX_PATH];
HMODULE hMod = LoadLibrary("comctl32.dll");
GetModuleFileName(hMod, szFile, sizeof(szFile));
printf("%s\n", szFile);
FARPROC pFunc = GetProcAddress(hMod, MAKEINTRESOURCE(346));
printf("%ph\n", pFunc);
return 0;
}
Code: [Select]
C:\WINDOWS\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.3636_none_a863d714867441db\comctl32.dll
742dbe90h
Code: [Select]
C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.3636_none_60b6a03d71f818d5\comctl32.dll
00007ffe45ed7c40h
« Last Edit: January 31, 2024, 12:01:02 PM by TimoVJL »
May the source be with you

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: Dynamic array of structures or pointers
« Reply #10 on: January 31, 2024, 12:07:16 PM »
Thanks Timo, I just made the same test adding a manifest.
The functions exists indeed in ComCtl32.dll V6.00
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide