InvalidateRect / Program to show EMF files

Started by C.M.Obrecht, August 26, 2008, 09:30:17 PM

Previous topic - Next topic

C.M.Obrecht

Hello,

i wrote this program to view emf files (for Windows 2000, 98 etc in which the prewiew comes but the picture can't be shown in big). It works, but I made it today rapidly in C++ with MFC and remarked something.

The View will not be updated like it should. The function to resize the picture (radio button on the right side) sometimes works only one time and often it's needed to minimize and maximize the window. But I made the "InvalidateRect" call for this. What is wrong with this? Is the position of the call not good?
I've seen that with MFC there's a member named "invalidate" with which it isn't any problem (i think this is a member from the view).

The second problem, i don't know why the program doesn't open files with the command line argument (the media player uses the same procedure, or have I gorgotten something)?

Thanks :)

.Const

.Data?
handle DD ?
devicec DD ?

left DD ?
right DD ?
top DD ?
bottom DD ?
.Data
ofn OPENFILENAME <0>
szFileName DB 255 Dup(?), 0
szShortFileName DB 255 Dup(?), 0
wrect RECT <0>
newrect RECT <0>
metarec ENHMETAHEADER <0>
filterstr DB "*.emf Enhanced Windows Meta File Vector Graphics", 0, "*.emf", 0

divisor DD 2

infotitel DB "Info über EMF Betrachter ", 0
infotext DB "© 2008, C. M. Obrecht, Reben Studio, Aufnahmemedien & Informatik C.M.Obrecht", 10, 13, 10, 13, "Betrachter für EMF (Enhanced Windows Metafile) Vektorgrafiken. ", 10, 13, 10, 13, "Geschrieben in Assembler, mit MASM32/EasyCode", 0
.Code

Window1Procedure Proc Private hWnd:HWND, uMsg:ULONG, wParam:WPARAM, lParam:LPARAM
.If uMsg == WM_CREATE
Invoke GetShortPathName, App.CommandLine, Addr szShortFileName, 255
Invoke SetWindowText, hWnd, TextAddr("EMF-Betrachter")
Invoke GetEnhMetaFile, Addr szShortFileName

        Mov handle, Eax
        Invoke GetEnhMetaFileHeader, handle, SizeOf ENHMETAHEADER, Addr metarec
        Invoke GetClientRect, hWnd, Addr wrect


Invoke InvalidateRect, hWnd, Addr wrect, 0


Return TRUE
.ElseIf uMsg == WM_CLOSE
Invoke IsModal, hWnd
.If Eax
Invoke EndModal, hWnd, IDCANCEL
Return TRUE
.EndIf


.ElseIf uMsg == WM_COMMAND
Mov Eax, wParam
.If Ax == IDC_WINDOW1_RADIO1
Invoke GetClientRect, hWnd, Addr wrect
Invoke InvalidateRect, hWnd, Addr wrect, 0
.EndIf
.If Ax == IDC_WINDOW1_RADIO2
Invoke GetClientRect, hWnd, Addr wrect
Invoke InvalidateRect, hWnd, Addr wrect, 0
.EndIf
.If Ax == IDC_WINDOW1_RADIO3
Invoke GetClientRect, hWnd, Addr wrect
Invoke InvalidateRect, hWnd, Addr wrect, 0
;Invoke MessageBox, 0, TextAddr("Diese Funktion funktioniert noch nicht ganz fehlerfrei; wird das Bild nicht richtig anzezeigt, das Programm nochmals schliessen und VOR dem Öffnen der Datei das Fenster in etwa auf die benötigte Grösse ziehen!"), TextAddr("Achtung, bitte lesen"), MB_ICONEXCLAMATION
.EndIf


.If Ax == IDM_WINDOW1_IDEND
Invoke PostQuitMessage, NULL
.EndIf
.If Ax == IDM_WINDOW1_IDINFO
Invoke MessageBox, hWnd, Addr infotext, Addr infotitel, MB_ICONINFORMATION
.EndIf

          .If Ax == IDM_WINDOW1_IDOPEN


Invoke DeleteEnhMetaFile, handle
                  Invoke ReleaseDC, hWnd, devicec

          Mov ofn.lStructSize, SizeOf OPENFILENAME
          Push Offset filterstr
          Pop ofn.lpstrFilter
;Push hParent
     ;Pop ofn.hWndOwner
    ;Push hInstance
    ;Pop ofn.hInstance
    ;Push lpFilter
    ;Pop ofn.lpstrFilter
    Push Offset szFileName
    Pop ofn.lpstrFile
    Mov ofn.nMaxFile, SizeOf szFileName
   ; Push lpTitle
   ; Pop ofn.lpstrTitle
    Mov ofn.Flags,              OFN_EXPLORER or OFN_FILEMUSTEXIST or \
                                OFN_LONGNAMES


        Invoke GetOpenFileName, Addr ofn
        Invoke GetShortPathName, Addr szFileName, Addr szShortFileName, 255
oeffnen: Invoke GetEnhMetaFile, Addr szShortFileName

        Mov handle, Eax
        Invoke GetEnhMetaFileHeader, handle, SizeOf ENHMETAHEADER, Addr metarec
        Invoke GetClientRect, hWnd, Addr wrect

Invoke InvalidateRect, hWnd, Addr wrect, NULL




          .EndIf
          .ElseIf uMsg == WM_PAINT
newpaint: Invoke GetClientRect, hWnd, Addr wrect

                  Invoke GetDC, hWnd
                  Mov devicec, Eax

Invoke GetWindowItem, hWnd, IDC_WINDOW1_RADIO2
Invoke SendMessage, Eax, BM_GETCHECK, NULL, NULL
Cmp Eax, 1
Je origgr

Invoke GetWindowItem, hWnd, IDC_WINDOW1_RADIO3
Invoke SendMessage, Eax, BM_GETCHECK, NULL, NULL
Cmp Eax, 1
Je origgrhalb


Invoke PlayEnhMetaFile, devicec, handle, Addr wrect  ;Addr metarec.rclBounds
Jmp weiter
origgr: Invoke PlayEnhMetaFile, devicec, handle, Addr metarec.rclBounds
    Jmp weiter
origgrhalb: Call halbiererect

            Invoke PlayEnhMetaFile, devicec, handle, Addr newrect
weiter:


.ElseIf uMsg == WM_DESTROY

Invoke DeleteEnhMetaFile, handle
                  Invoke ReleaseDC, hWnd, devicec
          .EndIf
Return FALSE


Window1Procedure EndP

Window1ToolBar1 Proc Private hWnd:HWND, uMsg:ULONG, wParam:WPARAM, lParam:LPARAM
Return FALSE
Window1ToolBar1 EndP

Window1Radio1 Proc Private hWnd:HWND, uMsg:ULONG, wParam:WPARAM, lParam:LPARAM
Return FALSE
Window1Radio1 EndP

Window1Radio2 Proc Private hWnd:HWND, uMsg:ULONG, wParam:WPARAM, lParam:LPARAM
Return FALSE
Window1Radio2 EndP

Window1Radio3 Proc Private hWnd:HWND, uMsg:ULONG, wParam:WPARAM, lParam:LPARAM
Return FALSE
Window1Radio3 EndP
halbiererect Proc Private

Fild metarec.rclBounds.left
Fidiv divisor
Fist newrect.left

Fild metarec.rclBounds.right
Fidiv divisor
Fist newrect.right

Fild metarec.rclBounds.top
Fidiv divisor
Fist newrect.top

Fild metarec.rclBounds.bottom
Fidiv divisor
Fist newrect.bottom
Ret
halbiererect EndP

Ramon Sala

Hi C.M.Obrecht,

Would you mind to post the whole project so that I could see what is happening?

Thanks,

Ramon
Greetings from Catalonia

C.M.Obrecht

Here is it, the exe file (the project was too large). Thanks! I think it's a little thing, maybe the place of the invalidate calls.

[attachment deleted by admin]

Ramon Sala

Hi,

I cannot do anything with the exe file, but I have looking in the code you posted and I found the problem:

In the WM_PAINT message you should not get a DC. Instead you should call the BeginPaint function which fills a PAINTSTRUCT structure. The hdc member of PAINTSTRUCT is the valid DC for the window. Besides, the returned DC is only valid during the WM_PAINT message execution. At the end of this message you have to call the EndPaint function.

On the other hand, in the Radio buttons clicks, you should call the InvalidateRect function with the last parameter set to TRUE for the background to be redrawn. Here is the code working fine and please read the Winodws documentation in order to avoid such kind of problems:


.Const

.Data?
handle DD ?
devicec DD ?

left DD ?
right DD ?
top DD ?
bottom DD ?
.Data
ofn OPENFILENAME <0>
szFileName DB 255 Dup(?), 0
szShortFileName DB 255 Dup(?), 0
wrect RECT <0>
newrect RECT <0>
metarec ENHMETAHEADER <0>
filterstr DB "*.emf Enhanced Windows Meta File Vector Graphics", 0, "*.emf", 0

divisor DD 2

infotitel DB "Info über EMF Betrachter ", 0
infotext DB "© 2008, C. M. Obrecht, Reben Studio, Aufnahmemedien & Informatik C.M.Obrecht", 10, 13, 10, 13, "Betrachter für EMF (Enhanced Windows Metafile) Vektorgrafiken. ", 10, 13, 10, 13, "Geschrieben in Assembler, mit MASM32/EasyCode", 0
.Code

Window1Procedure Proc Private hWnd:HWND, uMsg:ULONG, wParam:WPARAM, lParam:LPARAM
   Local ps:PAINTSTRUCT

   .If uMsg == WM_CREATE
      Invoke GetShortPathName, App.CommandLine, Addr szShortFileName, 255
      Invoke SetWindowText, hWnd, TextAddr("EMF-Betrachter")
      Invoke GetEnhMetaFile, Addr szShortFileName

        Mov handle, Eax
        Invoke GetEnhMetaFileHeader, handle, SizeOf ENHMETAHEADER, Addr metarec
        Invoke GetClientRect, hWnd, Addr wrect

      Invoke InvalidateRect, hWnd, Addr wrect, 0

      Return TRUE
   .ElseIf uMsg == WM_COMMAND
      Mov Eax, wParam
      .If Ax == IDC_WINDOW1_RADIO1
         Invoke GetClientRect, hWnd, Addr wrect
         Invoke InvalidateRect, hWnd, Addr wrect, TRUE
         Return TRUE
      .EndIf
      .If Ax == IDC_WINDOW1_RADIO2
         Invoke GetClientRect, hWnd, Addr wrect
         Invoke InvalidateRect, hWnd, Addr wrect, TRUE
         Return TRUE
      .EndIf
      .If Ax == IDC_WINDOW1_RADIO3
         Invoke GetClientRect, hWnd, Addr wrect
         Invoke InvalidateRect, hWnd, Addr wrect, TRUE
         ;Invoke MessageBox, 0, TextAddr("Diese Funktion funktioniert noch nicht ganz fehlerfrei; wird das Bild nicht richtig anzezeigt, das Programm nochmals schliessen und VOR dem Öffnen der Datei das Fenster in etwa auf die benötigte Grösse ziehen!"), TextAddr("Achtung, bitte lesen"), MB_ICONEXCLAMATION
         Return TRUE
      .EndIf
         .If Ax == IDM_WINDOW1_IDOPEN
         Invoke DeleteEnhMetaFile, handle
         Invoke ReleaseDC, hWnd, devicec

         Mov ofn.lStructSize, SizeOf OPENFILENAME
         Push Offset filterstr
         Pop ofn.lpstrFilter
         ;Push hParent
          ;Pop ofn.hWndOwner
          ;Push hInstance
          ;Pop ofn.hInstance
          ;Push lpFilter
          ;Pop ofn.lpstrFilter
          Push Offset szFileName
          Pop ofn.lpstrFile
          Mov ofn.nMaxFile, SizeOf szFileName
         ; Push lpTitle
         ; Pop ofn.lpstrTitle
          Mov ofn.Flags,              OFN_EXPLORER or OFN_FILEMUSTEXIST or \
                                        OFN_LONGNAMES


         Invoke GetOpenFileName, Addr ofn
         Invoke GetShortPathName, Addr szFileName, Addr szShortFileName, 255
oeffnen:   Invoke GetEnhMetaFile, Addr szShortFileName

         Mov handle, Eax
         Invoke GetEnhMetaFileHeader, handle, SizeOf ENHMETAHEADER, Addr metarec
         Invoke GetClientRect, hWnd, Addr wrect

         Invoke InvalidateRect, hWnd, Addr wrect, NULL


         .EndIf
      .If Ax == IDM_WINDOW1_IDEND
         Invoke SendMessage, hWnd, WM_CLOSE, 0, 0
         Return TRUE
      .EndIf
      .If Ax == IDM_WINDOW1_IDINFO
         Invoke MessageBox, hWnd, Addr infotext, Addr infotitel, MB_ICONINFORMATION
      .EndIf
   .ElseIf uMsg == WM_PAINT
      Invoke GetClientRect, hWnd, Addr wrect

      Invoke BeginPaint, hWnd, Addr ps
      Move devicec, ps.hdc
;      Invoke GetDC, hWnd
;      Mov devicec, Eax

      Invoke GetWindowItem, hWnd, IDC_WINDOW1_RADIO2
      Invoke SendMessage, Eax, BM_GETCHECK, NULL, NULL
      Cmp Eax, 1
      Je origgr

      Invoke GetWindowItem, hWnd, IDC_WINDOW1_RADIO3
      Invoke SendMessage, Eax, BM_GETCHECK, NULL, NULL
      Cmp Eax, 1
      Je origgrhalb


      Invoke PlayEnhMetaFile, devicec, handle, Addr wrect  ;Addr metarec.rclBounds
      Jmp weiter
      origgr: Invoke PlayEnhMetaFile, devicec, handle, Addr metarec.rclBounds
          Jmp weiter
origgrhalb: Call halbiererect

         Invoke PlayEnhMetaFile, devicec, handle, Addr newrect
      weiter:

      Invoke EndPaint, hWnd, Addr ps ;Invoke ReleaseDC, hWnd, devicec

   .ElseIf uMsg == WM_SIZE
      Invoke InvalidateRect, hWnd, NULL, TRUE
   .ElseIf uMsg == WM_DESTROY
      Invoke DeleteEnhMetaFile, handle
   .ElseIf uMsg == WM_CLOSE
      Invoke IsModal, hWnd
      .If Eax
         Invoke EndModal, hWnd, IDCANCEL
         Return TRUE
      .EndIf
   .EndIf
   Return FALSE


Window1Procedure EndP

Window1ToolBar1 Proc Private hWnd:HWND, uMsg:ULONG, wParam:WPARAM, lParam:LPARAM
Return FALSE
Window1ToolBar1 EndP

Window1Radio1 Proc Private hWnd:HWND, uMsg:ULONG, wParam:WPARAM, lParam:LPARAM
Return FALSE
Window1Radio1 EndP

Window1Radio2 Proc Private hWnd:HWND, uMsg:ULONG, wParam:WPARAM, lParam:LPARAM
Return FALSE
Window1Radio2 EndP

Window1Radio3 Proc Private hWnd:HWND, uMsg:ULONG, wParam:WPARAM, lParam:LPARAM
Return FALSE
Window1Radio3 EndP
halbiererect Proc Private

Fild metarec.rclBounds.left
Fidiv divisor
Fist newrect.left

Fild metarec.rclBounds.right
Fidiv divisor
Fist newrect.right

Fild metarec.rclBounds.top
Fidiv divisor
Fist newrect.top

Fild metarec.rclBounds.bottom
Fidiv divisor
Fist newrect.bottom
Ret
halbiererect EndP
Greetings from Catalonia

C.M.Obrecht

#4
Oh yes, thank you!
In C++ with MFC the DC 'll  come as argument for the paint function, and then I don't knew anymore how I can get this DC without to create a new; but once i made this in C and have seen the MASM32 wizard makes this. :)
What I wonder is why the App. doesn't work with commandline arguments; I used "App.CommandLine" and because it doesn't work I made a messageBox for viewing the szShortFilename and the App.CommandLine and they are empty!

I think you don't have a EMF-file to try the program? Not every windows installation has some, only .wmf-files are installed with word for the cliparts.


Thanks!

Ramon Sala

Yes of course! For the command line not to be empty you have to pass some command line to the application. For example, when you create a shortcut you can pass the command line in the shortcut properties (just after the program path and separated by a blank).

Ramon
Greetings from Catalonia

C.M.Obrecht

Yes, of course it's empty by opening the program over a shortcut (without giving arguments). I used the way with the right mouse-button on a file and then choose "open with..." and then i selected the program. And then it's empty. Must I "say" the program that I'll use cmd args, like the window should accept drop files? I don't think so?
The media player works with this (only makes a exception while closing after listening, but it opens).

Ramon Sala

When you use the option "Open with...", Windows is responsible to pass the correspondings arguments, not the application, and as far as I know it works fine. To check whether it works properly in your applications, do the following test:

At the end of the WM_CREATE message write the following sentence:

    Invoke SetWindowText, hWnd, App.CommandLine

That will make the command line to be set as the window title (in the title bar or caption) and you will be able to see how it works.

Greetings from Catalonia

C.M.Obrecht

Ooh I'm a fool  :green I gave the address to the MessageBox, how I've seen the SetWindowText-call! The Commandline is OK, but the picture will not open. I made this WM_CREATE: .If uMsg == WM_CREATE
      Invoke GetShortPathName, App.CommandLine, Addr szShortFileName, 255
Invoke GetEnhMetaFile, Addr szShortFileName

         Mov handle, Eax
         Invoke GetEnhMetaFileHeader, handle, SizeOf ENHMETAHEADER, Addr metarec
         Invoke GetClientRect, hWnd, Addr wrect

         Invoke InvalidateRect, hWnd, Addr wrect, NULL


Invoke SetWindowText, hWnd, App.CommandLine
      Return TRUE

Ramon Sala

I can't see the problem without the project, but do you mean with "the picture will not open"?
Greetings from Catalonia

C.M.Obrecht

I sent you the project in a mail, with a .emf-file to try it. The picture will not open, i mean the picture'll not appear on the screen after starting the program with the filename as commandline-arg.

Ramon Sala

Well, the problem with the command line is that the name is given in double quotes when it is a long name. That makes the GetShortPathName function not to work. So, to avoid this issue make the following in the WM_CREATE message:

.If uMsg == WM_CREATE
    Invoke lstrcpy, Addr szShortFileName, App.CommandLine
    Lea Esi, szShortFileName
    .If Byte Ptr [Esi] == 34
        Mov Eax, Esi
        Inc Eax
        Invoke lstrcpy, Esi, Eax
    .EndIf
    Invoke lstrlen, Esi
    Dec Eax
    Add Eax, Esi
    .If Byte Ptr [Esi] == 34
        Mov Byte Ptr [Eax], 0
    .EndIf
    Invoke GetShortPathName, Addr szShortFileName, Addr szShortFileName, 255

This will remove the double quotes characters (ASCII 34). Now it opens with the command line.

Regards,
Greetings from Catalonia

C.M.Obrecht

#12
Oh i'll try it later! Thank you very much. Funny that the Media Player works, it makes the same :bg

It must have a little error; the 2nd double quote will not be removed (at the end of the string). I tried to find it, but i don't understand the 2nd "if": Invoke lstrlen, Esi
    Dec Eax

    Add Eax, Esi
    .If Byte Ptr [Esi] == 34
        Mov Byte Ptr [Eax], 0

This decrements the value in EAX which is the string length (EAX points to the double quotes which has to be removed then) and then adds to this the starting address of the string or am I wrong?

EDIT: No while I'm writing this post, i came to the idea then that it MUST be .If Byte Ptr [EAX] == 34 and now it works!! Very good, thanks a lot! :) Because of the error with the register I came to the insight that I learnd a little bit more in string operations with assembler, since I made a payment-order printing program for DOS in assembler  :green

Ramon Sala

That's it! The second .If must be: .If Byte Ptr [Eax] == 34.

I'm glad it works now.
Greetings from Catalonia

C.M.Obrecht

Yes it works really fine :) Thanks!
In the Media Player I must check something when the command line is used, then it makes an exception by closing, and while playing the hourglass will be visible. Except this, it works fine too.