MASM32, porting win32 specfic from C++. (GetOpen/SaveDialog).

Started by Chesso, May 28, 2007, 12:24:35 AM

Previous topic - Next topic

Chesso

This is a bet hefty to ask, but any pointers in the right direction would be great (this is going to be an addition to the first basic DLL I made in MASM32 which is basically a function that performs a MessageBox based on byte parameter (0-11)).


// OFNHookProc for centering Open/Save Dialogs.
static UINT CALLBACK OFNHookProc(HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
switch (uiMsg)
{
  case WM_INITDIALOG:
  {   
     RECT rcP,rc;
     HWND hWnd = GetParent(hDlg);
       
     GetWindowRect(GetDesktopWindow(), &rcP);
     GetWindowRect(hWnd, &rc);
     rcP.right -= rcP.left;
     rcP.bottom -= rcP.top;
     rc.right -= rc.left;
     rc.bottom -= rc.top;
     SetWindowPos(hWnd, NULL, (rcP.right/2)-(rc.right/2), (rcP.bottom/2)-(rc.bottom/2), 0, 0, SWP_NOSIZE);
     return FALSE;   
  }
}
return 0;                                 
}   

char* OpenSaveDialog(int Open, char* InitDir)
{
// Setup OPENFILENAME struct parts that are common for Open and Save.
OPENFILENAME ofn;
char szFileName[65000];

//char* FData("");
char* FData;

// BUG_FIX
// Fixes the open/save not working after either have been called
// at some points because it wasn't zero initialised. Also helps
// with size.
ZeroMemory(&szFileName, sizeof(szFileName));
   
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = NULL;
ofn.lpstrFile = szFileName;
ofn.nMaxFile = 65000;
ofn.lpfnHook = &OFNHookProc;

switch(Open)
{
  case 0: break;
  case 1:
    // Now setup specific OPENFILENAME structs for this open.
    ofn.lpstrFilter = "All Supported Files\0*.mp3;*.mp2;*.wav;*.wma;*.mid;*.ogg\0";
    ofn.lpstrInitialDir = InitDir;
    ofn.Flags = OFN_EXPLORER | OFN_ENABLEHOOK | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT;
   
    if (GetOpenFileName(&ofn))
    {
     int len = strlen(ofn.lpstrFile);
     
     if( ofn.lpstrFile[len + 1] == 0) { return ofn.lpstrFile; } // If single file was selected.
     else {
     // This is the directory.
      FData = ofn.lpstrFile;

      ofn.lpstrFile += len + 1;
      while(ofn.lpstrFile[0]) {
     
     // This will contain the current file name from multiple selection.
     
      //FData = FData + "|" + ofn.lpstrFile;
      sprintf(FData,"%s|%s",FData,ofn.lpstrFile);     
     
      // Find next name
      len = strlen(ofn.lpstrFile);
      ofn.lpstrFile += len + 1;
      }
       return FData;                       
     }
    }
    else { return "CANC"; }
  break;
  case 2:
    ofn.lpstrFilter = "All Supported Files\0*.sm3l;*.sm3;*.m3u;*.pls\0";
    ofn.lpstrInitialDir = InitDir;
    ofn.Flags = OFN_EXPLORER | OFN_ENABLEHOOK | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
    ofn.lpstrDefExt = "sm3l";
   
    if (GetOpenFileName(&ofn)) { return ofn.lpstrFile; }
    else { return "CANC"; }
  break; 
  case 3:
    // Now setup specific OPENFILENAME structs for this save.
    ofn.lpstrFilter = "SM3 format\0*.sm3\0M3U Format\0*.m3u\0PLS Format\0*.pls\0";
    ofn.Flags = OFN_EXPLORER | OFN_ENABLEHOOK | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
    ofn.lpstrDefExt = "sm3l";
   
    if (GetSaveFileName(&ofn)) { return ofn.lpstrFile; }
    else { return "CANC"; }
  break;                                 
}
}


This is probably a bit much for me to tackle outright in MASM32, but I suppose it's mostly a matter of knowing how to do the exact same thing in MASM32 as opposed to C++.

I am mostly worried about how to handle some of the strings, and windows specific types in MASM32, I might check out that uhh Lizon or some such's Win32 tutorials and see if he mentions how to use these (or other useful information to build this up).

I can't wait to compare the different between the C++/MASM32 version  :dance:

Probably won't be a whole lot, but it's still fun.

hutch--

If you can make the shift from C lbraries to Windows API functions you will find them both flexible and powerful in most instances. For the odd bit you absolutely MUST do you can still use MSVCRT.DLL as MASM32 supports this standard DLL. Comparing the two you will probably find the ASM version comes in a fair bit smaller but you will find the precision and compact nature of MASM very seductive over time.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Chesso

And that's exactly why I started playing in any assembler at all.

It's damn fun, and making things as compact, fast and hopefully memory efficient as I can is just something I can't help but give it what I can :P, whether it's necessary or not :D.

I almost forgot I made this topic lol, what do you mean by C libraries? (like strings and such?, ZeroMemory and GetOpenSaveDialog is WinAPI I think? (been awhile since I made this DLL and used these specific functions/api's)).

Timbo

The ZeroMemory macro maps to RtlZeroMemory (which is also a macro under MSVC) which ultimately maps to memset() in msvcrt.

You can slim down your dependencies by using #pragma comment (linker, "/NODEFAULTLIB:libc) and by using your own crt for the dll.

I am pasting one that I use in a current project:

.386
.model flat, stdcall
option casemap:none



DllMain PROTO :DWORD,:DWORD, :DWORD

.code

_DllMainCRTStartup proc hInstance:DWORD, dwReason:DWORD, lpReserved:DWORD
invoke DllMain, hInstance, dwReason, lpReserved
ret
_DllMainCRTStartup endp
end


Hope this helps.

Chesso

I thought ZeroMemory was the actual API? (I use it in that case with Dev-CPP and mingW compiler).

So setmem is the actual API? (which I could call directly instead eh).

Perhaps ZeroMemory is just an encapsulation over the real one? As I use it in Delphi also.

I already have the base dll with detecting messages (DETATCH_THREAD) and such, with 1 function, I just plan on adding this one in the future (the function and the callback so I can center the dialog(s)).

I'll have a crack probably tomorrow and just basically write the whole thing the best I can and try and get it working myself and post here if I can't get something to go :).

hutch--

Chesso,

By C libraries I mean the normal C runtime libraries wich you can pretty well deliver using the MSVCRT DLL to get if you need the functionality. With an API like ZeroMemory() you can generally do better with an assembler version as they are simple enough to write and this is the case with many basic string and similar API calls.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Timbo

Chesso,

The actual API is RtlZeroMemory (in kernel32.dll) but it is defined as a macro in MSVC to prevent a direct call to it, for whatever reason...perhaps MS plans to remove it in the future.  I have the feeling Delphi does the same with their win32 library, since they can remap it if/when RtlZeroMemory is removed.

The C memory functions are easily duplicated with assembly as Hutch pointed out.

Regards,

Tim

Chesso

so it'd be a case of doing the same thing as they did? (re-mapping it).

But I wonder is it necessary to do so lol.

hutch--

Chesso,

You would be better off to have a look at the C runtime functions as they are time tested and reliable if not always the fastest way to do things. If you can get an API to do what you are after instead of an MSVCRT function fine but its no big deal either way.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Timbo

Chesso,

The following is just an example of assembly and c/c++ interacting.  Pasted below is an unoptimized version of lstrlen with a c++ test piece.

strlenx86 proc lpstring:dword
; edx = pointer to string
; ecx = char counter
push ecx
push edx
mov edx, lpstring
xor ecx, ecx

scan4terminator:
mov byte ptr al, [edx]
cmp al, 0
je terminator_found
add ecx, 1
add edx, 1
jmp scan4terminator

terminator_found:
mov eax, ecx
pop edx
pop ecx
ret
strlenx86 endp


char test_string [] = "hello! this is a test string for strlenx86";
extern "C" int _stdcall strlenx86(char *buffer);
int main()
{
printf("the length of the test string returned from strlenx86 is: %d \n", strlenx86(test_string) );
printf("the length returned from lstrlen: %d", lstrlen(test_string));
Sleep(10000);
return 0;
}

This mimics lstrlen in that the value returned in eax is the length of the buffer not counting the terminator.  I haven't calculated the size of the procedure and compared it to that of lstrlen, but it's a pretty sure bet that if you use assembly to implement the few C functions you need that you will come up with a smaller executable after foregoing the linkage with libc.  On the other hand, using msvcrt only costs you import header space and a little runtime memory to load the library.

Have a look in the laboratory for speed tests and different ways of implementing memory functions in assembly.

Hope this helps,

Tim

edit: changed msvc to msvcrt. oops.