Recent

Author Topic: GetConsoleTitle with pchar as argument ?  (Read 5116 times)

Nitorami

  • Sr. Member
  • ****
  • Posts: 491
GetConsoleTitle with pchar as argument ?
« on: March 10, 2023, 09:29:00 am »
GetConsoleTitle works with a shortstring as parameter but not with a pchar. Why ?

Code: Pascal  [Select][+][-]
  1. {$H-}
  2. uses windows;
  3.  
  4. var s: shortstring;
  5.     p: pchar;
  6. begin
  7.   writeln;
  8.   s :=  '##########################################################################';
  9.   writeln ('GetTitle returns ',GetConsoleTitle (@s[1],50));  //works
  10.   writeln (s+LineEnding);
  11.  
  12.   p :=  '##########################################################################';
  13.   writeln ('GetTitle returns ',GetConsoleTitle (p,50));      //doesn't work
  14.   writeln (p+LineEnding);
  15.   writeln ('GetTitle returns ',GetConsoleTitle (@p[0],50));  //doesn't either
  16.   writeln (p+LineEnding);
  17. end.
  18.  
  19.  

Output:
Running "c:\temp\getconsoletitle.exe "

GetTitle returns 24
Eingabeaufforderung - fp #################################################

GetTitle returns 0
##########################################################################

GetTitle returns 0
##########################################################################



Red_prig

  • Full Member
  • ***
  • Posts: 143
Re: GetConsoleTitle with pchar as argument ?
« Reply #1 on: March 10, 2023, 10:08:28 am »
Because pchar is a reference to data, first allocate the memory and put the reference in p, then when the data is no longer needed, free it accordingly

Nitorami

  • Sr. Member
  • ****
  • Posts: 491
Re: GetConsoleTitle with pchar as argument ?
« Reply #2 on: March 10, 2023, 10:10:20 am »
Understood, but I initialised p with p := '####....', so it must have been allocated at a speciifc address ?

Red_prig

  • Full Member
  • ***
  • Posts: 143
Re: GetConsoleTitle with pchar as argument ?
« Reply #3 on: March 10, 2023, 10:11:36 am »
'####....' is a constant and is write-protected

Nitorami

  • Sr. Member
  • ****
  • Posts: 491
Re: GetConsoleTitle with pchar as argument ?
« Reply #4 on: March 10, 2023, 10:31:23 am »
You mean the content of pchar is stored in a specific write-protected area of memory which the API function cannot write to ?

Red_prig

  • Full Member
  • ***
  • Posts: 143
Re: GetConsoleTitle with pchar as argument ?
« Reply #5 on: March 10, 2023, 10:46:24 am »
correct

JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4467
  • I like bugs.
Re: GetConsoleTitle with pchar as argument ?
« Reply #6 on: March 10, 2023, 01:44:53 pm »
Yes, memory must be allocated for PChar with StrAlloc(). Later it should be freed with StrDispose().
ShortString is a good type if the Title does not exceed 255 characters.
AnsiString can be used, but you must set its length first. After that it is freed automatically.
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux 64-bit.

Nitorami

  • Sr. Member
  • ****
  • Posts: 491
Re: GetConsoleTitle with pchar as argument ?
« Reply #7 on: March 10, 2023, 02:57:21 pm »
Thank you, that enlightens me. Maybe you can help me a bit further. I try to copy text to the windows clipboard from within a Console. I got it working in principle:

  • First, get a window handle to the Console via GetConsoleTitle and FindWindow().
  • Using this handle, I can now OpenClipBoard() and EmptyClipBoard().
  • Then, use GlobalAlloc to reserve a memory region; it returns a handle, not a pointer. I can pass this handle to SetClipboardData() to copy the associated memory to the clipboard.
  • But to get something into this memory first, I need its address. I can get a pointer via GlobalLock (handle), and can now move() my own memory content (e.g. the string) to this memory.

This seems to work, but I wonder if I could avoid the extra memory allocation via Global Alloc. I would need a memory handle for my own Pascal structure but cannot see a way how to do this.[/list]

JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4467
  • I like bugs.
Re: GetConsoleTitle with pchar as argument ?
« Reply #8 on: March 10, 2023, 03:44:13 pm »
I can only recommend the LCL unit Clipbrd and class TClipboard.
I don't use Windows myself and don't know much about WinAPI programming.
LCL pulls in a lot of code, thus in your console program you may want to avoid it.
If one GlobalAlloc is all you need for the task, it sounds like a reasonable addition.
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux 64-bit.

Nitorami

  • Sr. Member
  • ****
  • Posts: 491
Re: GetConsoleTitle with pchar as argument ?
« Reply #9 on: March 10, 2023, 03:56:47 pm »
Agreed it would be easier via Lazarus and the LCL. But I still use the textmode IDE because compliation speed is unsurpassed (unless the windows virusscanner intervenes). I often write small throw-away programs during my work, and the Strg-F9 button starts to wear out...

Can I use the LCL from within a Console program ? Rather not, I guess ?

JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4467
  • I like bugs.
Re: GetConsoleTitle with pchar as argument ?
« Reply #10 on: March 11, 2023, 08:54:59 am »
Can I use the LCL from within a Console program ? Rather not, I guess ?
You can but it may be difficult without the Lazarus IDE.
LCL has a "NoGUI" widgetset which does not call any real widgetset. For example the LazBuild console program uses it.
The same LazBuild can compile and build projects made with Lazarus. You could modify such a project with a textmode IDE and then run LazBuild. Compilation would not be super-fast any more because LCL pulls in lots of code.
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux 64-bit.

Raskaton

  • New Member
  • *
  • Posts: 12
Re: GetConsoleTitle with pchar as argument ?
« Reply #11 on: July 03, 2023, 08:16:05 pm »
Last time I use this:
Code: Pascal  [Select][+][-]
  1. uses
  2.   SysUtils;
  3. var
  4.   s: ShortString;
  5.   buf, p: PChar;
  6.   len: integer;
  7. begin
  8.   buf := StrAlloc(250); //temp buffer
  9.   len := GetConsoleTitle(buf,250);
  10.   //if len=0 then {Alloc to 'buf' more and repeat Get}
  11.  
  12.   p := StrAlloc(len);  //alloc real size
  13.   p := StrLCopy(p, buf, len); //get real data
  14.   StrDispose(buf);  //free buffer
  15.  
  16.   s := StrPas(p);
  17.  
  18.   WriteLn('Title = ', p); //automatic typecast will be done Alloc, StrPas and Dispose by ref
  19.   WriteLn('Len = ', StrLen(p));  //#0 not included
  20.   StrDispose(p);
  21.  
  22.   WriteLn('Title = ', s);
  23.   WriteLn('Len = ', Length(s));
  24. end;
  25.  
PS not tested
« Last Edit: July 03, 2023, 08:24:01 pm by Raskaton »

ASerge

  • Hero Member
  • *****
  • Posts: 2240
Re: GetConsoleTitle with pchar as argument ?
« Reply #12 on: July 03, 2023, 09:55:23 pm »
PS not tested
Code: Pascal  [Select][+][-]
  1. {$MODE OBJFPC}
  2. {$APPTYPE CONSOLE}
  3.  
  4. uses Windows;
  5.  
  6. var
  7.   Dummy: UnicodeChar;
  8.   Count: DWORD;
  9.   U: UnicodeString;
  10. begin
  11.   // GetConsoleTitleW expects the size in bytes, not in chars, but returns in chars
  12.   // The documentation is incorrect about this
  13.   // The size cannot be zero
  14.   Count := GetConsoleTitleW(@Dummy, SizeOf(Dummy));
  15.   SetString(U, nil, Count);
  16.   GetConsoleTitleW(Pointer(U), (Count + 1) * SizeOf(UnicodeChar)); // + #0
  17.   Writeln(U);
  18.   Readln;
  19. end.
Tested.

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2050
  • Fifty shades of code.
    • Delphi & FreePascal
Re: GetConsoleTitle with pchar as argument ?
« Reply #13 on: July 04, 2023, 09:23:32 am »
Code: Pascal  [Select][+][-]
  1. var
  2.   Count: DWORD;
  3.   W: array[0..MAX_PATH -1] of WideChar;
  4. begin
  5.   Count := GetConsoleTitleW(@W, SizeOf(W));
  6.   W[Count] := #0;
  7.   Writeln(string(W));
  8.   Readln;
  9. end.
or
Code: Pascal  [Select][+][-]
  1. var
  2.   W: array[0..MAX_PATH -1] of WideChar;
  3. begin
  4.   FillChar(W, SizeOf(W), #0);
  5.   GetConsoleTitleW(@W, SizeOf(W));
  6.   Writeln(string(W));
  7.   Readln;
  8. end.
or
Code: Pascal  [Select][+][-]
  1. {$IF Defined(FPC) and Declared(FPC_VERSION) and (FPC_VERSION >= 3)}
  2.   {$DEFINE UniCode} { FreePascal UniCode support }
  3. {$IFEND}
  4.  
  5. function GetConsoleOriginalTitleA(lpConsoleTitle: LPTSTR; nSize: DWORD): DWORD;
  6.   external 'kernel32.dll' name 'GetConsoleOriginalTitleA';
  7.  
  8. function GetConsoleOriginalTitleW(lpConsoleTitle: LPWSTR; nSize: DWORD): DWORD;
  9.   external 'kernel32.dll' name 'GetConsoleOriginalTitleW';
  10.  
  11. function GetConsoleOriginalTitle(lpConsoleTitle: {$IF Defined(UniCode)}LPWSTR{$ELSE}LPTSTR{$ENDIF}; nSize: DWORD): DWORD;
  12.   external 'kernel32.dll' name 'GetConsoleOriginalTitle' + {$IF Defined(UniCode)}'W'{$ELSE}'A'{$ENDIF};
  13.  
  14. var
  15.   W: array[0..MAX_PATH -1] of {$IF Defined(UniCode)}WideChar{$ELSE}AnsiChar{$ENDIF};
  16. begin
  17.   FillChar(W, Length(W) * SizeOf({$IF Defined(UniCode)}WideChar{$ELSE}AnsiChar{$ENDIF}), #0);
  18.   GetConsoleOriginalTitle(@W, SizeOf(W));
  19.   Writeln({$IF Defined(UniCode)}PWideChar{$ELSE}PAnsiChar{$ENDIF}(W));
  20.   Readln;
  21. end.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2050
  • Fifty shades of code.
    • Delphi & FreePascal
Re: GetConsoleTitle with pchar as argument ?
« Reply #14 on: July 04, 2023, 12:40:39 pm »
    Thank you, that enlightens me. Maybe you can help me a bit further. I try to copy text to the windows clipboard from within a Console. I got it working in principle:

    • First, get a window handle to the Console via GetConsoleTitle and FindWindow().
    • Using this handle, I can now OpenClipBoard() and EmptyClipBoard().
    • Then, use GlobalAlloc to reserve a memory region; it returns a handle, not a pointer. I can pass this handle to SetClipboardData() to copy the associated memory to the clipboard.
    • But to get something into this memory first, I need its address. I can get a pointer via GlobalLock (handle), and can now move() my own memory content (e.g. the string) to this memory.

    This seems to work, but I wonder if I could avoid the extra memory allocation via Global Alloc. I would need a memory handle for my own Pascal structure but cannot see a way how to do this.[/list]
    This is how I would do.
    Code: Pascal  [Select][+][-]
    1. program Project1;
    2.  
    3. {$APPTYPE CONSOLE}
    4.  
    5. uses
    6.   Windows, SysUtils;
    7.  
    8. function GetTitle(Wnd: HWND): String;
    9. var
    10.  lpch: String;
    11.  len: DWORD;
    12. begin
    13.  len := GetWindowTextLength(Wnd);
    14.  SetLength(lpch, len);
    15.  GetWindowText(Wnd, PChar(lpch), Length(lpch) + 1);
    16.  Result := lpch;
    17. end;
    18.  
    19. function GetClipboardText(Wnd: HWND; var Str: string): Boolean;
    20. var
    21.  hData: HGlobal;
    22. begin
    23.  Result:=True;
    24.  if OpenClipboard(Wnd) then begin
    25.   try
    26.    hData:=GetClipboardData(CF_TEXT);
    27.    if hData<>0 then begin
    28.     try
    29.      SetString(Str, PChar(GlobalLock(hData)), GlobalSize(hData));
    30.     finally
    31.      GlobalUnlock(hData);
    32.     end;
    33.    end else Result:=False;
    34.    Str:=PChar(@Str[1]);
    35.   finally
    36.    CloseClipboard;
    37.   end;
    38.  end else Result:=False;
    39. end;
    40.  
    41. function SetClipboardText(Wnd: HWND; Value: string): Boolean;
    42. var
    43.  hData: HGlobal;
    44.  pData: pointer;
    45.  Len: integer;
    46. begin
    47.  Result:=True;
    48.  if OpenClipboard(Wnd) then begin
    49.   try
    50.    Len:=Length(Value)+1;
    51.    hData:=GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, Len);
    52.    try
    53.     pData:=GlobalLock(hData);
    54.     try
    55.      Move(PChar(Value)^, pData^, Len);
    56.      EmptyClipboard;
    57.      SetClipboardData(CF_Text, hData);
    58.     finally
    59.      GlobalUnlock(hData);
    60.     end;
    61.    except
    62.     GlobalFree(hData);
    63.     raise
    64.    end;
    65.   finally
    66.    CloseClipboard;
    67.   end;
    68.  end else Result:=False;
    69. end;
    70.  
    71. var
    72.   s, ss: string;
    73.   wnd: HWND;
    74. begin
    75.   wnd := GetForegroundWindow;
    76.   ss := GetTitle(wnd);
    77.   WriteLn('Window Caption: ', ss);
    78.   s := '';
    79.   if SetClipboardText(wnd, ss) then
    80.     begin
    81.       WriteLn('Copy to clipboard success.');
    82.       if GetClipboardText(wnd, s) then
    83.         begin
    84.           WriteLn('Text from clipboard: ', s);
    85.         end
    86.         else
    87.           WriteLn('Unabled to get text from clipboard.');
    88.     end
    89.     else
    90.       WriteLn('Copy to clipboard failed.');
    91.   ReadLn;
    92. end.
    I've missed a lot of pre-checkings, just a prototype to demonstrate.
    « Last Edit: July 04, 2023, 01:12:02 pm by KodeZwerg »
    « Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

     

    TinyPortal © 2005-2018