

PeterBelow
Members-
Content Count
567 -
Joined
-
Last visited
-
Days Won
13
Everything posted by PeterBelow
-
Questions about Application and Package .dproj files.
PeterBelow replied to Pat Foley's topic in Delphi IDE and APIs
Design-time packes are only 32 bit, they are only used by the IDE and this is 32 bit programm. Run-time packages (that is what youre compiled programs use) can be 32 or 64 bit. Put the component class into a run-time package and add that to the requires clause of the design-time package. The only thing that package does is registering the component, i. e. it contains the Register procedure the IDE looks for to add the component to the palette. See https://docwiki.embarcadero.com/RADStudio/Alexandria/en/64-bit_Windows_Application_Development#Making_Your_Components_Available_at_Design_Time_and_Run_Time in the online help. It also tells you how you can specify which platforms your component is compatible with (ComponentPlatformsAttribute) if the default is not to yor taste. -
In theory you can create a VCL control (not forms or datamodules since they add themselves to the global Screen object's collection) in a background thread but you cannot do anything with it that causes its window handle to be created, since that would bind it to the background thread. Things like TBitmap or TGraphicControl descendents (the latter only as long as they have no Parent assigned) should work, and I have worked with TBitmap in background threads successfully. To show them you have to pass them to the main thread, though.
-
The VCL is not thread-safe and has been documented to not be thread-safe since Delphi 1. If you need to create Windows controls in a secondary thread you have to do it on the naked API level, and the thread probably needs a message loop (API style, not ProcessMessages) as well for the control to work properly.
-
You are assuming Sizeof(Char) = 1, which is no longer true since Delphi 2007. Use ballpointer:=GetMemory(3000000*Sizeof(char)); Incrementing a pointer to Char (PChar) will correctly take the size of Char into account, so your statement ballpointer:=ballpointer+1; will increment the address held in ballpointer by 2. Since GetMemory takes the size in bytes your code allocates only half the memory needed for 3,000,000 UTF16 characters, so the loop runs over the end of the buffer when it is halfway through.
-
They are of type String already. The limitation seems to be in the parser which cannot deal with lines longer than 255 characters in the source. But there is an easy workaround, which your third-party tool should use for long string literals: split it into several shorter literals concatenated by '+' plus linebreaks. Much easier to read for you as well if you need to manually correct stuff later.
-
The compiler accepts this without problems: const CTest = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'+ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'+ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'+ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'+ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'+ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'+ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'+ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'+ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'+ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' ;
-
How to remove metadata from Word document (using OLE)
PeterBelow replied to Kevin Smith's topic in General Help
Isn't the Last Author set when the file is saved? That would simply undo your change... -
Is it possible that an exception does not inherits from Exception class?
PeterBelow replied to Wagner Landgraf's topic in RTL and Delphi Object Pascal
There is a case, though: if the code inside the try block calls something in a DLL and that DLL function does not trap any exceptions raised inside the DLL code these would bubble up the exception handler stack into your try except block, be trapped there but not recognized as deriving from the Exception class. This would even be the case if the DLL is written in Delphi, unless DLL and EXE are build with the same Delphi version and with run-time packages enabled for both projects. -
Which OS/CPU are we talking about here? What you show has not been a problem since 16-bit (DOS, Win 2.x, 3.x) programs have gone the way of the dinosaurs. 32 and 64 bit CPUs use a different memory architecture. 32 bit CPUs (Intel) do in fact still have segment registers but their content is constant during normal program runs, and the offset (address) registers are 32 bit wide, so a memory block can be up to 4GB large in theory. Due to OS requirement (Windows) 32 bit application programs can only use 2GByte of this theoretical address space though (3GByte with a special executable flag).
-
In Delphi you very rarely need to go as far down to the metal as GetMem. If you need arrays of some element type and don't know the size needed at coding time use a dynamic array type. Once your code has figured out the size needed use SetLength on the array to allocate the needed memory for it, then access members of the array with the classical array syntax ([index]). For array of characters use the String type in the same manner. This way you never have to deal with raw memory allocation or pointer manipulation (where you better know what you are doing if you value your sanity). You can use pointer stuff in Delphi if you really need to, but there is rarely any need. If you need a pointer to pass to some low-level API the @ operator is your friend, you can allocate memory using a dynamic array and then pass @A[0] (the address of the first array element) as the pointer. Just be aware that this only works for one-dimensional arrays. Multidimensional dynamic arrays do not occupy one single memory block. Refer to the Delphi Language Guide to learn about such pesky details, it is part of the main online help. Oh, to get a value a pointer points at you best use a specific pointer type that defines the type of data the pointer points at, e.g you use a PInteger (defined as type PInteger = ^Integer; in the run-time library units, System.Types I think) in preference to the raw Pointer type if you know the pointer points at an integer (or an array of integers). You can then just dereference the pointer to get the pointed-at value into an integer variable: var N: Integer; P: PInteger; begin ...assign an address to P N:= P^; If you only have a raw pointer you can typecast it to the specific pointer type for the assignment. var N: integer; P: Pointer begin ...asign an address to P N:= PInteger(P)^;
-
Very sensible policy, it saves you from serious headaches.
-
Is there a way to use a platform specific win32/win64 DEF file?
PeterBelow replied to alank2's topic in General Help
DEF files are a C/C++ thing, no? Delphi definitely does not need them. -
unit compile with a different versio of idTCPConnection
PeterBelow replied to Zazhir's topic in Algorithms, Data Structures and Class Design
I hope you have the source code of this library. You need to recompile its units to use the Indy version you just installed. And make sure you only have one instance of the Indy dcus on the pathes the compiler searches for files (IDE library path, project search path). -
Bad unit format for IdSMTP.dcu
PeterBelow replied to Zazhir's topic in Algorithms, Data Structures and Class Design
This looks like the Indy folders listed in the IDE library path for 32 bit projects are actually for the 64 bit version of the Indy components. Correct the path entries to point at the 32 bit version of the dcus. -
There are two ways to declare variables inside a method or standalone procedure or function. Sherlock's reply shows the traditional way of declaring all variables in a single var section before the begin keyword that starts the body of the method. That has been part of the Pascal language since the time of its inception by Wirth; variables you declare this way are accessible in every place inside the body of the method. What you showed in your post is a fairly new way to declare variables inline, near the place of first use. In my opinion this should only be used if you need to reduce the scope of a variable to a specific block (e.g. a begin ... end block for an if statement or for loop). In fact in my real opinion it should not be used at all ; for one it is alien to the general structure of the language, and some IDE features do not work correctly (in the current version) when they are used, e.g. refactorings and things depending on the LSP server, like code completion. If you need a lot of variables in a method this is actually a "code smell", it indicates your method is too large and tries to do too many things. Refactor it to call several smaller methods that each do a single task. If that gets complex (i.e. you find you actually need a lot of methods to partition the code correctly) the solution may be to create a new class that does the required work internally and isolates it from the calling code. The array issue you mentioned probably has a different cause. If you declare a variable with a syntax like x: array [1..9] of variant; you are using what is called an anonymous type for the variable. This is allowed for classical variables declared at the top of the method but may not be allowed for inline variables. If in doubt declare a proper type and use that for the variable: procedure.... type T9Variants = array [1..9] of variant; var x: T9Variants;
-
Using SetLength(Self) inside a record helper for TBytes
PeterBelow replied to MarkShark's topic in RTL and Delphi Object Pascal
It's OK, a record or helper is just way to add methods for a type, they always work on the instance of the type you call the added method on. -
Is there a Delphi equivalent of WriteStr ?
PeterBelow replied to Martin Liddle's topic in RTL and Delphi Object Pascal
It used to be possible to kind of redirect the output of Write/WriteLn using something called a "text-file device driver". I found some ancient unit of mine in the newsgroup archives, see https://codenewsfast.com/cnf/article/0/permalink.art-ng1618q5913 . If the link does not work search for "Unit StreamIO". It contains a AssignStream procedure you can use to attach a stream (in this case a TStringstream would be appropriate) to a Textfile variable. Output to this variable would then end up in the stream, from which you can get the content as a string. As I said this is old code, I have no idea how it behaves under Unicode-enabled versions of Delphi. -
It is expected to act the same since SendInput is just the recommended alternative to the old keybd_event API, which is basically legacy from 16-bit Windows; still supported by current Windows versions but it may be removed sometime in the future, though that seems unlikely based on past experience with other "legacy" APIs. Windows carries a loads of old APIs along, since dropping them will cause old applications still in use at many customers to fail, and the resulting uproar would be bad for business .
-
Why should it? The Shift parameter is not a Var parameter so you just change the local value of it, not the one the caller passed. Even changing that (if you could) would not do what you think it should since it would not change the Windows-internal state of the modifier keys. And the WM_CHAR message for the tab key is already in the message queue anyway. Using keybd_event (in fact thats deprecated, you should use SendInput instead) puts a completely new Shift-Tab combination into the message queue, so you better set Key := 0 to abort processing of the 37 key. You should use virtual key codes instead of numeric values however, those make it clear which key you are processing here. VK_LEFT is much more readable than 37.
-
Nowhere in fact. Components are installed via design-time packages and those register their components when the package has been loaded, through calls to the Register procedure a unit in the package defines in its interface section (in fact several units can have such a procedure, though that is not recommended). The procedure contains calls to RegisterComponents that tells the IDE how the component class is named and on which page of the palette to display the associated icon. The installed design-time packages are listed in the registry.
-
Use the OnKeyPress event of the edit control. Like this: procedure TForm2.Edit1KeyPress(Sender: TObject; var Key: Char); begin if (Key = '+') and (GetKeyState(VK_ADD) < 0) then begin Key := #0; label1.Caption := 'VK_ADD'; end else label1.Caption := string.Empty; end; The GetKeyState API function allows you to check which key is currently down. The code above will let the '+' key of the normal keyboard add the character to the edit but block the numpad plus key input.
-
Have you tried running the code under an admin account? This may be a rights issue, since you are changing a setting that effects all users.
-
Calculation of the illumination of a point for PNG image, taking into account transparency
PeterBelow replied to lisichkin_alexander's topic in Algorithms, Data Structures and Class Design
You cannot, since the pixel color in question depends on the background the image is rendered on. Just replace transparent pixels with a default color for the comparison, e.g. black. -
Making sure I add unique records to text file
PeterBelow replied to karl Jonson's topic in Algorithms, Data Structures and Class Design
The best way is to not have duplicate records in your query result in the first place. If you are using a SQL-supporting database just do not access the table directly (via TDBTable or analog), instead use a query component and give it a SELECT DISTINCT <columnlist> FROM <tablename> statement, optionally with more restrictions on the records to return (WHERE clause) and ordering. This way the result set will not contain duplicates in the first place. If the database you use does not support this kind of statement your best bet is to keep track of what you have already written to the file in an in-memory structure that supports quick lookup. You could concatenate all field values of a record into a string (basically the line you write to the text file) and store them into a TDictionary<string,byte>, using the byte part to keep a count of the duplicates you find. Depending on the number of records you have to process this may use too much memory, though. You could cut down on that by calculating a hash value from the string and storing the hash instead of the string. That is not completely failsafe, though, since different strings can result in the same hash value. You can deal with that by writing any such duplicate detected to separate file, which will end up with only few such records. When done with the task load that file into a stringlist, sort the list, and then do a final run over the record file and compare the lines read with the content of the stringlist, marking each match found there. If you end up with any unmarked items in the stringlist those are false duplicates and need to be added to the record file. -
That is an old problem you also have at design-time: using ssPercent each change of a column width recalculates all column widths, including the one you just changed, so you end up with a value different from what you just entered. The algorithm used is faulty, but at design-time it is fairly easy to work around by changing the width in the DFM file directly. If you need to change the width at run-time it is easier to work with absolute column widths and do the calculations yourself, at least it is better for your mental health.