Results 1 to 27 of 27

Thread: printscreen

  1. #1

    Thread Starter
    Member
    Join Date
    Feb 2014
    Location
    Houston, TX
    Posts
    38

    printscreen

    Help! I got this code from this forum. (VB6 on Windows 10). I want a bitmap of frmText, but no matter whether I code:
    keybd_event vbKeySnapshot, 0&, 0&, 0&
    or
    keybd_event vbKeySnapshot, 1&, 0&, 0&,
    I get a bitmap of form1. As you can see, I've tried to make form1 not the active screen, but no luck. Any ideas?

    Code in frmText:

    Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, _
    ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)

    Private Sub cmdLabel_Click()
    Form1.Hide
    Form1.Visible = False
    Form1.Enabled = False
    frmText.Show
    frmText.Enabled = True
    frmText.Visible = True
    labText.Caption = Form1.LabelCap
    'Use the keybd_event API to do a screen shot.
    'If you only want the active screen, set the second parameter to 1
    keybd_event vbKeySnapshot, 1&, 0&, 0&
    'Yield the processing while the image is copied to clipboard
    DoEvents
    'Save the image on clipboard
    frmText.Picture = Clipboard.GetData(vbCFBitmap)
    ...

  2. #2
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    13,821

    Re: printscreen

    What is visible on the screen when you the code runs and after the code runs?

  3. #3

    Thread Starter
    Member
    Join Date
    Feb 2014
    Location
    Houston, TX
    Posts
    38

    Re: printscreen

    DataMiser, frmText shows the bitmap of form1. I need it to show the bitmap of frmText. Once I set labText.visible=false, then I would be left with nothing but the pixels in the frmText top banner and the pixels of the label. Then I can access them using frmText.Point. My goal is to eventually rotate them and display them using Pset. Thanks for your interest.

  4. #4
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    13,821

    Re: printscreen

    You did not actually answer my question.

    What do you see on the screen before the code executes, when the code executes, after the code executes.

    Print screen should capture what you see at the time it is executed.

  5. #5
    Lively Member vbLewis's Avatar
    Join Date
    Feb 2009
    Location
    USA
    Posts
    71

    Re: printscreen

    might try a DoEvents before the screenshot

  6. #6
    Frenzied Member
    Join Date
    Dec 2014
    Posts
    1,594

    Re: printscreen

    if u are trying to take a screenshot of a textbox, you can simply do:

    Code:
    Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
    Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
    
    With frmText
       BitBlt Picture1.hdc, 0, 0, ScaleX(.Width, vbTwips, vbPixels), ScaleY(.Height, vbTwips, vbPixels), GetDC(.hwnd), 0, 0, vbSrcCopy
       Picture1.Refresh
    End With
    if you instead want take the entire hwnd, you can do:

    Code:
    Private Declare Function PrintWindow Lib "user32.dll" (ByVal hWnd As Long, ByVal hdcBlt As Long, ByVal nFlags As Long) As Long
    
    PrintWindow frmText.hWnd, Picture1.hdc, 0
    Picture1.Refresh

  7. #7
    PowerPoster SamOscarBrown's Avatar
    Join Date
    Aug 2012
    Location
    NC, USA
    Posts
    8,073

    Re: printscreen

    I realize you are only a hobbyist, so, to be kind...let me offer some advice:

    use good naming conventions for your forms/controls/modules/etc. For example, it is hard to understand if you have a TEXTBOX on FORM1, or you have TWO forms (Form1 and frmText). Name labels with, (e.g.), lblNameOfLabel, and command buttons with cmdNameOfCommandButton...don't use, like you did, cmdLabel or labText...those are not descriptive of the FUNCTION of each one.

    If you can rename this stuff, and answer DM's question (which he repeated), we all might be able to better understand what you have, and what you want.

    @vblewis...what do you think DoEvents is going to do for him/her?
    Sam I am (as well as Confused at times).

  8. #8
    PowerPoster
    Join Date
    Feb 2006
    Posts
    22,956

    Re: printscreen

    Whenever possible avoid trashing the user's clipboard. The clipboard belongs to the user, not your program!

    You are also jumping through unneeded hoops. It sounds like you have even more hoops in store when you mention crazy stuff like PSet to accomplish rotation. Very, very slow and completely unnecessary:

    Code:
    Option Explicit
    
    Private Const WIN32_NULL As Long = 0
    
    Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
    
    Private Type POINT
        X As Long
        Y As Long
    End Type
    
    Private Declare Function PlgBlt Lib "gdi32" ( _
        ByVal hdcDest As Long, _
        ByRef DestPlg As POINT, _
        ByVal hDCSrc As Long, _
        ByVal nXSrc As Long, _
        ByVal nYSrc As Long, _
        ByVal nWidth As Long, _
        ByVal nHeight As Long, _
        Optional ByVal hbmMask As Long = WIN32_NULL, _
        Optional ByVal xMask As Long = 0, _
        Optional ByVal yMask As Long = 0) As Long
    
    Private Declare Function ReleaseDC Lib "user32" ( _
        ByVal hWnd As Long, _
        ByVal hDC As Long) As Long
    
    Private Sub Form_Load()
        Form2.Show vbModeless, Me
    End Sub
    
    Private Sub mnuCapture_Click()
        Dim DestPlg(0 To 2) As POINT
        Dim W As Long
        Dim H As Long
        Dim hDCSrc As Long
    
        With Form2
            W = .ScaleX(.ScaleWidth, .ScaleMode, vbPixels)
            H = .ScaleY(.ScaleHeight, .ScaleMode, vbPixels)
            'Resize to fit the rotated capture:
            Width = (Width - ScaleX(ScaleWidth, ScaleMode, vbTwips)) _
                  + .ScaleY(.ScaleHeight, .ScaleMode, vbTwips)
            Height = (Height - ScaleY(ScaleHeight, ScaleMode, vbTwips)) _
                  + .ScaleX(.ScaleWidth, .ScaleMode, vbTwips)
            'From MSDN:
            '
            'An array of three points in logical space that identify three corners of the
            'destination parallelogram. The upper-left corner of the source rectangle is
            'mapped to the first point in this array, the upper-right corner to the second
            'point in this array, and the lower-left corner to the third point. The
            'lower-right corner of the source rectangle is mapped to the implicit fourth
            'point in the parallelogram.
            '
            'So, to rotate counter-clockwise 90 degrees:
            DestPlg(0).Y = W
            DestPlg(2).X = H
            DestPlg(2).Y = W
            AutoRedraw = True
            Cls
            hDCSrc = GetDC(.hWnd)
            PlgBlt hDC, DestPlg(0), hDCSrc, 0, 0, W, H
            ReleaseDC .hWnd, hDCSrc
            AutoRedraw = False
        End With
        mnuCapture.Enabled = False
    End Sub
    The demo has two Forms, the first one for capturing a rotated screenshot of the client area of the second one.

    You would call GetWindowDC() instead of GetDC() if you want the entire window including the non-client area of the second Form as well. That returns "iffy" results these days because in recent versions of Windows DWM (Desktop Window Manager) plays a lot of reindeer games to create funky border effects.
    Attached Files Attached Files

  9. #9

    Thread Starter
    Member
    Join Date
    Feb 2014
    Location
    Houston, TX
    Posts
    38

    Re: printscreen

    SamOscarBrown, thank you for cutting me some slack, but in my defense, I thought frmText and labText, which only contain text were good names. :-(
    Okay, to all following this post, I found a workaround--I put the label, labText, on form1, so it is a part of the bitmap that I assign to frmText.Picture. All would work well (works partially) if the bitmap was not bigger than the form (due to the banner). When I scan the bitmap with frmText.Point, I only get about half of the pixels in the label. I'm going to try baka's suggestion, which will not have a banner that makes the bitmap bigger than the textbox. I'll be back with my results in a day or so. Thanks.

  10. #10

    Thread Starter
    Member
    Join Date
    Feb 2014
    Location
    Houston, TX
    Posts
    38

    Re: printscreen

    dilettante,
    unnecessary hoops, yeah, I'm sure. Nearly every line of code in your code window was not in the version of VB6 I learned. Likewise that of baka, but I'm happy to try yours and his suggestions. Regarding rotation, I only want 90 degrees, so Pset(x0+y,y0-x) does the job, where x0,y0 is the center of rotation, and x,y is the coordinates of the text's pixels. Thanks for the clipboard advice and code example.

  11. #11

    Thread Starter
    Member
    Join Date
    Feb 2014
    Location
    Houston, TX
    Posts
    38

    Re: printscreen

    baka,
    I'm confused, not to mention being unfamiliar with the code you shared. It looks like a version of VB beyond 6.0. Anyway, I can't use the entire hwnd, because it contains the banner of the form, making the bitmap bigger than the form. (The bits don't align with the pixels of the form.) I want to use your code to get the bitmap of the text assigned to the caption of my label, labText. Here's my code with improved (?) variable names and comments explaining my intentions. Will you show me how to adapt your code to do that?
    Thanks.

    'baka's code
    Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
    Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
    'end baka's code

    Public LabelCap As String 'user text from form1 to be captured by frmText.Point

    Private Sub cmdGetPixelsOfLabelCaption_Click()
    Dim nXcoord(5000) As Integer 'x coord. of black pixels in label caption
    Dim nYcoord(5000) As Integer 'y ditto
    Dim i, j As Integer 'indices of for loops scanning rectangle containing label caption
    Dim nBlackPix As Integer 'number of black pixels in label caption
    Dim xmin, xmax, ymin, ymax As Integer 'boundaries of rectangle containing label caption
    frmText.Show 'show the form containing the label to be bitmapped
    labText.BackColor = vbBlack 'to be sure the label's pixels can be identified based on color
    labText.Caption = Form1.LabelCap 'place user text from form1 in caption of label on frmtext form
    DoEvents

    ' baka's code
    '*****************************************
    'how do I modify baka's code to assign the bitmap of labText.Caption to frmText.Picture?
    '******************************************
    With frmText
    BitBlt picture1.hdc, 0, 0, ScaleX(.Width, vbTwips, vbPixels), ScaleY(.Height, vbTwips, vbPixels), GetDC(.hwnd), 0, 0, vbSrcCopy
    Refresh picture1
    End With
    'end baka's code

    xmin = 2000 'initial values of boundaries of label's caption
    xmax = -1
    ymax = -1
    ymin = 2000
    nBlackPix = 0
    For i = 0 To 100 'my labels are short in length
    For j = 0 To 20 'my labels' fontsize is small
    If frmText.Point(i, j) = vbBlack Then 'if pixel belongs to label caption
    nBlackPix = nBlackPix + 1
    nXcoord(nBlackPix) = i
    nYcoord(nBlackPix) = j
    If i > xmax Then xmax = i
    If j > ymax Then ymax = j
    If i < xmin Then xmin = i
    If j < ymin Then ymin = j
    End If
    Next j
    DoEvents
    Next i
    'I should now have all the black pixels that belong to the label caption.
    'Once I have them, I can manipulate them any way I desire (rotate, translate, invert)

  12. #12
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    13,821

    Re: printscreen

    All code posted is VB6 code. The part you seem confused by is the API. You'll find that most experienced coders use API calls in their VB6 programs especially if the are dealing with graphics.

  13. #13

    Thread Starter
    Member
    Join Date
    Feb 2014
    Location
    Houston, TX
    Posts
    38

    Re: printscreen

    DataMiser,
    I think you're right. API calls would not be something I would learn via self-teaching. On my old XP machine, I had online documentation that might have included API calls, although I don't remember them. I lost access to the documentation when Windows updated their op sys. I know I'm missing a lot of capability, but I don't know where to go to learn about API calls, plus I'm 81, so learning might be a problem. Thanks.

  14. #14
    Frenzied Member
    Join Date
    Dec 2014
    Posts
    1,594

    Re: printscreen

    labels don't have any DC on their own.
    u could create a textbox that "acts" like a label, that way its easier to copy.
    if u want to copy the label, it need to be the "parent", and I assume its the form itself?

    if u copy the form's client area, it will contain everything, and thats not what u desire.
    what u need to do is to copy a region of that.

    so, if u know the labels left/top position, u convert that into pixel
    and that u use BitBlt and instead of coping from 0,0 u copy from that left/top position
    and the width/height is the labels width and height in pixel. remember that VB6 IDE works in vbTwips,
    while BitBlt works with pixels (that is why I used ScaleX and ScaleY to convert it.

    so try that.

    more tips: labText.Caption can not be used here, use the parent .hdc.
    so replace GetDc(.hwnd) to Me.hdc and replace picture1.hdc with .hdc
    I wrote picture1.hdc as example, of course I assumed u would replace that with the desired destination picturebox.
    Last edited by baka; Oct 24th, 2021 at 03:09 PM.

  15. #15
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    13,821

    Re: printscreen

    Quote Originally Posted by VBH0bbyist View Post
    DataMiser,
    I think you're right. API calls would not be something I would learn via self-teaching. On my old XP machine, I had online documentation that might have included API calls, although I don't remember them. I lost access to the documentation when Windows updated their op sys. I know I'm missing a lot of capability, but I don't know where to go to learn about API calls, plus I'm 81, so learning might be a problem. Thanks.
    Under addins there is an API viewer. If you load that then from within it tell it to load text file you can load the win32 api. There you can see types, constants and definitions you can search online for more detailed info on any of these.

  16. #16

    Thread Starter
    Member
    Join Date
    Feb 2014
    Location
    Houston, TX
    Posts
    38

    Re: printscreen

    baka,
    this is the With block I have:

    With frmText
    BitBlt .hdc, 0, 0, ScaleX(labText.Width, vbTwips, vbPixels), ScaleY(labText.Height, vbTwips, vbPixels), Me.hdc, 0, 0, vbSrcCopy
    ' Picture1.Refresh
    End With

    What object's .Point method do I use in my For loops? Thanks.


    For i = 0 To 100
    For j = 0 To 20
    If frmText.Point(i, j) = vbBlack Then

  17. #17
    Frenzied Member
    Join Date
    Dec 2014
    Posts
    1,594

    Re: printscreen

    Im not that experienced with scanning a bitmap,
    but instead of Point u could use the API GetPixel and actually skip the entire copy bitmap first as u can scan the pixel directly.

    another method is to use CreateDIBSection.
    in this method u would first create a compatibledc, and create an "copy" of the .hdc in memory
    after that u access the memory using CopyMemory API, or create an array of the DIB section
    and scan the array. a bit of work but doable and not that complex.

    the easiest method is GetPixel:

    Private Declare Function GetPixel Lib "gdi32" Alias "GetPixel" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long

    as u can see: hdc, the me.hdc
    and u start from the label left and top position and do a for x = left to left + width and for y = top to top + height

  18. #18

    Thread Starter
    Member
    Join Date
    Feb 2014
    Location
    Houston, TX
    Posts
    38

    Re: printscreen

    baka,

    You're being very patient with me. Thanks. I hope it will last just a little bit longer. I coded:

    For x = 0 To labText.Width
    For y = 0 To labText.Height
    If GetPixel(ByVal Me.hdc, ByVal x, ByVal y) = vbBlack Then

    Sorry, I don't know what Me.hdc is or if it is the argument I should use in the GetPixel function. I want the function to point to the pixels in the labText.Caption. Thanks, again.

  19. #19
    PowerPoster
    Join Date
    Feb 2006
    Posts
    22,956

    Re: printscreen

    Hazardous code here:

    Code:
    With frmText
    BitBlt picture1.hdc, 0, 0, ScaleX(.Width, vbTwips, vbPixels), ScaleY(.Height, vbTwips, vbPixels), GetDC(.hwnd), 0, 0, vbSrcCopy
    Refresh picture1
    End With
    You never release the DC you obtained a handle to here. This may be cumulative depending on where you are doing it, and eventually lead to a process crash. While there are categories of DCs that don't have to be released it is always best practice to do so because you seldom know which you have. VB will manage hDC properties for the life of each event handler call but no longer. BE aware that changing AutoRedraw can also change hDC property values. VB cannot manage the ones you obtain behind its back at all.

    This part shouldn't even compile:

    Code:
    Refresh picture1
    Or was the Refresh method overloaded by a local Sub or something?


    This seems to actually be another thread about rotated text. I already got the willies from the previous one. You should not be using controls as graphic objects. Even if you bumble ahead and do this be aware that you will run afoul of things like antialiasing (whether ClearType or old-style). Prepare for some frustrating "color fringing" effects on text bit-rotated from upright horizontal escapement.

    Use a canvas container (Form, PictureBox, or UserControl) and draw everything within it. Do not rely on contained controls as graphic objects. Shape controls for example are only meant to be used for very, very simple things.


    Even when Microsoft VB6 classes were held there was only a brief introduction to making API calls. Most of that was just going over the VB reference manual chapter on calling conventions and parameter passing, how to look up calls in the documentation, and one "lab assignment." It was over in about an hour. Going deeper was left to the student.

    I'm not sure how far you will get with this if you don't have the MSDN Library CDs installed. The October 2001 edition is the best one for VB6 programming. Everything earlier has a lot of bugs and omissions, everything later omitted VB6 topics.
    Last edited by dilettante; Oct 24th, 2021 at 08:42 PM.

  20. #20
    PowerPoster
    Join Date
    Feb 2006
    Posts
    22,956

    Re: printscreen

    If you need to create graphics programs that go beyond the simple tools native to VB6 perhaps you'd be way ahead to find a 3rd party drawing library compatible with VB6?

    Doing a ton of raw GDI, GDI+, DirectDraw, Direct2D, etc. calls and getting it all correct is a lot of work.

  21. #21

    Thread Starter
    Member
    Join Date
    Feb 2014
    Location
    Houston, TX
    Posts
    38

    Re: printscreen

    Dilettante,

    I still have the original CDs, but they won't load on my Windows 10 laptop. I miss the quick reference capability desperately. I want to learn about APIs, but the learning curve would be weeks or months for me. I get excited when someone on the forum says "try this.", but they assume I will know how to adapt it to my needs. I don't. I also don't recognize poor or dangerous practices (using the clipboard, releasing DCs [whatever a DC is]).

    Bottom line, I want the user to enter a short string of text that I can place on a diagram (form) and allow the user to rotate (90 degree increments) or translate it into its final orientation and location. I can't access the pixels of a label with Point, so I need another way.

    Thanks for your continued interest.

  22. #22

    Thread Starter
    Member
    Join Date
    Feb 2014
    Location
    Houston, TX
    Posts
    38

    Re: printscreen

    dilettante,

    I don't mind the "lot of work". I give myself challenging projects to keep my mind active. I've been a programmer for 65 years, and Visual Basic (pre-.NET) is my favorite language. My current project is a drag'n'drop (or click'n'stick) app for creating electronic wiring diagrams, hence the need for short, rotated text that goes with the symbols placed on the diagram. Only a handful of people will use this program, so if I can't do the text rotation, it's no big deal. There are CAD programs that do the same thing, only better.

  23. #23

    Thread Starter
    Member
    Join Date
    Feb 2014
    Location
    Houston, TX
    Posts
    38

    Re: printscreen

    dilettante,
    "Use a canvas container (Form, PictureBox, or UserControl) and draw everything within it." If the "everything" includes user-entered text and user-selected font & size, how do I draw that on the container? That's what started both the "rotate text" and the "printscreen" posts. I need to convert text into pixels that I have access to using VB6's somewhat primitive tools.

  24. #24
    PowerPoster
    Join Date
    Feb 2006
    Posts
    22,956

    Re: printscreen

    Ok. Sometimes it is best to let people stumble and discover things. It isn't easy to be told "throw it away and start over."

    So you want to use PSet calls to copy some printed text from one control to another. That has a ton of issues, but settling those aside there just isn't very much to it:

    Code:
    Option Explicit
    
    'Form has two PictureBox controls with 3D borders.
    
    Private Sub Form_Load()
        Const MSG As String = "Text AND MORE text"
        Dim XPixel As Single
        Dim YPixel As Single
        Dim PB1X As Single
        Dim PB1Y As Single
        Dim PB1XMax As Single
    
        With Picture1
            XPixel = .ScaleX(1, vbPixels)
            YPixel = .ScaleY(1, vbPixels)
            .Move 0, _
                  0, _
                  .TextWidth(MSG) + XPixel * 4, _
                  .TextHeight(MSG) + YPixel * 4 'Add 3D border width & height.
            .AutoRedraw = True
            Picture1.Print MSG
            Set .Picture = .Image 'Commit our printed text.
            
            Picture2.Move .Left + .Width, 0, .Height, .Width
    
            PB1XMax = .ScaleWidth - XPixel
            Picture2.ScaleMode = .ScaleMode
            Picture2.AutoRedraw = True
            For PB1Y = 0 To .ScaleHeight - YPixel Step YPixel
                For PB1X = 0 To PB1XMax Step XPixel
                    Picture2.PSet (PB1Y, PB1XMax - PB1X), .Point(PB1X, PB1Y)
                Next
            Next
            Picture2.AutoRedraw = False 'Commit our drawing via PSet calls.
        
            .AutoRedraw = False 'We are done calling .Point() now.
        End With
    End Sub
    Seems to work just fine within its limitations.

  25. #25
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    13,821

    Re: printscreen

    Quote Originally Posted by VBH0bbyist View Post
    I want to learn about APIs, but the learning curve would be weeks or months for me.
    Actually that would be pretty quick, API is a pretty big topic. Just the Windows32 API is a pretty involved topic. I've been working with VB and using some of the Windows API functions for almost 30 years and I still don't know half of it not to mention the 100s, 1000s or more other APIs that are out there.

  26. #26
    Frenzied Member
    Join Date
    Dec 2014
    Posts
    1,594

    Re: printscreen

    this little example will help you understand a bit more
    so, you have:
    - 1 label called labText, that you place somewhere on the form, and write any text, like "test"
    - 1 picturebox, that you name picture1 (default)

    and add this code:
    Code:
    Private Declare Function GetPixel Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long
    Private Declare Function SetPixel Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal crColor As Long) As Long
    
    Private Sub Form_Load()
        Dim x&, y&, col&
    
        With Me
            .ScaleMode = vbPixels
            .Show
        End With
        Picture1.AutoRedraw = True
        DoEvents
        With labText
            For x = .left To .left + .width
            For y = .top To .top + .height
                col = GetPixel(Me.hdc, x, y)
                SetPixel Picture1.hdc, x - .left, y - .top, col
            Next y
            Next x
        End With
        Picture1.Refresh
    End Sub
    this will copy the text on the label and write it inside picture1
    its not a bitmap copy, but pixel by pixel,
    you can decide what color to draw or not, or if you want to write it in another direction.
    Last edited by baka; Oct 25th, 2021 at 02:42 AM.

  27. #27

    Thread Starter
    Member
    Join Date
    Feb 2014
    Location
    Houston, TX
    Posts
    38

    Re: printscreen

    DataMiser, baka, and dilettante,
    Thanks for all your help. I especially appreciate your patience, your explanations, and your code suggestions. You have inspired me to learn more of the capabilities of VB6 that was unaware of. We can close the printscreen and rotate text topics.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width