Jump to content

Steven Kamradt

Members
  • Content Count

    23
  • Joined

  • Last visited

Everything posted by Steven Kamradt

  1. Are you doing full builds or just compiles? I personally wouldn't trust a compile as it could pick up a stray dcu elsewhere in the search path (possibly with opposing debug info than a full build would generate) rather than the one you would build. I would expect two builds done back to back to have the same byte signature if there are no other changes. Don't get me started on .dfm changes when saving a unit that includes one. The streaming system likes to recompress images (I believe its the color palette) which throws off binary equality, even if no changes were actually made, and there is the possibility that if you touch an inherited component on the form that it will bring in an inherited version in the inherited .dfm as well that serves no purpose. I also use https://github.com/ahausladen/DDevExtensions and "Remove Explicit properties" from the DFM which also generates quite a bit of useless noise each save, at least when working in a group.
  2. Steven Kamradt

    A Question of Style

    My personal preference is to decouple the database field logic completely. Use a mapping object to map property name to field name and just deal with an object model and its properties. If I have to pick from only your examples, I would pick pattern 2. I dislike pattern 3 the most from a future maintenance point of view. It hides the context of the assignment and could make some logic bugs difficult to locate. Pattern 1 doesn't give you the ability to add additional attributes to the column. Pattern 2 allows you to extend the concept of a column record/class to have additional methods which might be useful that could be used in a loop. if not Stmt.Column[x].isNull then .... if Stmt.Column[x].valueType = vtString then ... ColumnHeading[x] := Stmt.Column[x].fieldname; Yes, you can do the same with pattern 3, but that pattern of using implicits will make it harder to read intent later, especially if you are mixing types in the same block with the same syntax.
  3. Steven Kamradt

    wuppdi Welcome Page for Delphi 11 Alexandria?

    It offers a different way to manage your projects over what Embarcadero has. For example, I have over a dozen versions of the same few projects, all are the same project names stored in separate version specific directories. With this plugin I can create branches in the favorites for each version and group like projects for the same version together. This makes opening a specific version very simple, unlike the default favorite "hearts" which are only sorted by most recently opened, so separate versions of the projects get shuffled and to find a specific one is time consuming.
  4. Steven Kamradt

    wuppdi Welcome Page for Delphi 11 Alexandria?

    The source for example welcome page plugins is available at https://github.com/Embarcadero/RADStudio12Demos/tree/main/Object Pascal/VCL/VCL WelcomePage or if you checked the samples checkbox in the installer.
  5. Steven Kamradt

    Strange behaviour Windows VCL app on specific laptop

    The mouse cursor being different might be a clue. Is there any other software installed that is different on this machine than others? Are any of the Accessibility options enabled? Are you using themes? I recall that there was a screen to speech service (designed for blind usage) somewhere that really created havoc many years ago in a app that I developed as it was intercepting low level windows calls and caused the application to not render properly. If you are using themes, try to rebuild and deploy a version without them and see if it works.
  6. Maybe the soundex algorithm might be a way to start? I have used it before to check for misspellings of names as two words which sound the same will generate the same value. Unfortunately there are false positives, and you might want to not use the first character, just the numeric value, but it might get fairly close. (see https://en.wikipedia.org/wiki/Soundex). I wouldn't truncate at 3 digits, let it go all the way to maxint if necessary. As for database layout, you could just store the word with the soundex value (integer portion). When you need sounds like words, just return all records with the same soundex integer from your database.
  7. I would use a simple record with an int for 5 seconds, minute, hour and day, an expires time for seconds, minute, hour, day. At each request, see if it has gone past the expiration time (set on the first request for that period) and if so then subtract the amount from the next fields, reset the expiration time for the and log the 5 second interval to the db. If you have hit a limit at any point across the steps then you can deny the request. On startup, initialize your record from the 5 second db intervals for the previous day, hour, minute and 5 second interval. This gives you the ability to reporting against the 5 second intervals, and keeps what is in memory to a minimum. Of course there are some issues that you may need to consider. What happens if you load balance multiple servers to handle increasing growth? How does it handle hundreds of thousands of single requests from unique users rather than hundreds of thousands of multiple requests from a few users?
  8. Steven Kamradt

    wuppdi Welcome Page for Delphi 11 Alexandria?

    There is one in development right now which was listed earlier in this thread (https://dwp.gksoft.ch/) and I believe that the experimental version of gExperts (or it was a patch you have to apply yourself) has an importer for its "favorite files". There is a sample for creating your own welcome page plugin that gets installed if you click the checkbox for samples (see https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Samples_Repositories, specifically the https://github.com/Embarcadero/RADStudio11Demos/tree/main/Object Pascal/VCL/VCL WelcomePage projects). I believe Daniel (the original author of Wuppdi) stated that he is no longer going to maintain that project moving forward.
  9. Steven Kamradt

    11.2 Pre-Upgrade Checklist / back out plan

    You will still have to remove 1.1, but you can run the migration tool to save your settings. The "get it" packages for me didn't all install properly, so I had to grab those separately after.
  10. Steven Kamradt

    Ignore exception type from code

    You asked how to ignore the exception type in that block of code. If you were using a compiler directive for a block of code you would also be making changes. I would actually suggest that your rule should be more of a guideline than a rule. If your maintaining production code, you really want your external components to also be in version control under the project they are being used in. Otherwise, how can you possibly make sure that you are rebuilding a specific version if you have to roll back to diagnose an issue in the field? How do you insure that anyone new to the team has the exact components installed? Often I have had the need to modify a 3rd party component or source to do what I needed and it was unique enough that the vendor wasn't willing to add support for my necessary changes. In the case where its a "bypass" for debugging, you can always revert your changes once your confident that its working properly unless its something you deal with every time you debug. Either way, if its in version control you have a diff with the changes and its not difficult to merge some minor changes in with the next component update.
  11. Steven Kamradt

    Project manager feature

    While I see what your getting at, this feature kind of already exists if you right click on the project, not the folder. When you add a new unit, it creates a dirty buffer that has not yet been saved. Saving it prompts you for the name, which defaults to unit1.pas (or next available number) in the project directory. In the save dialog its trivial to click on a folder (or create a new one) and save it there instead. The first thing I generally do when I create a new unit is save the file and give it a proper name and location. The folders don't show up until you add a file that is in a folder other than the dproj project folder location. As far as adding multiple existing units from a directory, I just drag and drop from explorer to the project and it "automagically" puts them in the appropriate folder (based on the existing location of course). Much simpler than clicking the button or right clicking to add to the project, unless its a one off.
  12. Steven Kamradt

    Ignore exception type from code

    You could just rewrite the CheckOSError line to: if TSynDWrite.GDIInterop.CreateFontFromLOGFONT(LogFont, DWFont) <> ERROR_SUCCESS then exit(False); and then the exception will not be raised by the CheckOSError function wrapper.
  13. Steven Kamradt

    Parnassus Bookmarks for Delphi 11 Alexandria?

    Really, all that is missing from this GExperts expert is mapping the CTRL-B to add a new bookmark (or if your on a bookmark already just remove it), and the concept of a bookmark stack (the ctrl-shift-b to drop a temporary bookmark, and escape to pop the bookmark stack, shift-escape would swap the current position for the last position). There was some custom drawing of the bookmark stack into the editor, which is possibly why we haven't seen it updated to Delphi 11.1 yet?
  14. I see nothing wrong with using absolute in this case, however you could make it a tiny bit stronger by placing it all in a class and hiding the storage. Maybe use TList as a starting point, but add accessor methods to fetch/append/insert/delete for each type. Keep a state variable so you know what mode its in and only have to switch modes when you change. Also, keep counts for each supported type so you can set the length appropriately. The list would always be an array of integers behind the scenes, but it then could contain an odd number of bytes or words. A ForEachByte or ForEachWord routine could be coded to use a stack to set and reset the state variable if necessary. I have done something similar with absolute when I needed to compare large blocks of data. An integer compares or moves at just short of 4x as fast as looping through 4 bytes. Disclaimer: This doesn't mean you should use this technique because you can. Its good practice to always measure to find the real bottlenecks and not add complexity to optimize when the net result is still nearly identical.
  15. Steven Kamradt

    Trial RAD 11 expired Delphi CE is 10.x

    I believe they are talking about the most recent version of the Community Edition, not the current paid version. The current community edition (as far as I can tell) is based on 10.4, not 11.x. See question 9 where it clearly states that the community edition is NOT the same as a trial of the latest release. In your quoted question the actual answer states that the community edition license is valid (ONLY) for the most recent community version not previous versions of Delphi regardless of community or not. Also keep in mind that a benefit of being on at least a professional sku is that you get access to the latest releases, which would include 11.1 and that a community edition license is only valid for a single year, at which time you must request a new license, and that license will be valid for the "most recent version" of the Community Edition.
  16. Well, since you opened this up for comments. 🙂 I think it would be useful to have some sort of indicator in the available units to show which ones are ALREADY in the interface/implementation. Maybe use italics or dark grey for any match? Or grey circle icons where either the top half or bottom half are a specific color if its used in the interface or implementation respectfully?
  17. Steven Kamradt

    INI problem

    Another trick is to use ExtractFilePath(paramstr(0)) to get the executable location. It really depends on your use case and how the executable is deployed. using your example above, this would be: TIFFileini:= TIniFile.Create(ExtractFilePath(paramstr(0))+'ComPortServer.ini');
  18. In your case, I would put the variables you are working with in a class or even a record and set the scope to what you selected as private to the thread. Keep it simple, its all about preventing access from multiple threads. If you have a global variable that needs to be accessed by multiple threads, protect the access using some sort of semaphore, such as a critical section or spin lock.
  19. Maybe a state variable and a work queue? You would add to the work queue the item that needs to be processed and its current state. Somewhere in your application (maybe a separate thread or on idle) loop through the queue and investigate each state to see if its eligible to move to the next state or be removed from the queue. If you persist this queue (database or file) you can then on program crash and reload determine if there is a state which would need to be restarted or not.
  20. First, lets agree to disagree. Yes, there is no problem with that pattern as long as it is used consistently for those forms. However, if you start to mix patterns with those forms, where sometimes you use the method you pointed out, and other times use the try/finally block with a variable you will likely run into AV when the destructor gets called twice in the later pattern (once on form close, then again on the explicit free). This is not something that is not always easy to find the cause of. Sure, if you have a small team or project it won't be that large of a deal, but if your project becomes more complex or has a larger team working on it the deviation from the norm can have an unexpected cost.
  21. The problem with above is that you will be scratching your head as to why you have AV's everywhere when you mix patterns, not to mention the fact that it will not be disposed of if there is an AV in the modal form. But we never have those do we. 🙂 The simplest solution is what Lajos Juhász suggests above. You could easily make this a standardized procedure or class method. I just wouldn't be afraid of the standard pattern, its simple and easy to maintain.
  22. A hash of the list would only tell you if the list was identical across all items. Keep in mind that any positive matches would have to be checked as it is mathematically possible to create the same hash value from different source values, more so if you are just using the DigestAsInteger function to grab a simple integer. Also, it is entirely possible to generate a hash value ANYWHERE in the integer range, so don't rely on any special values (for example, 0 is a possible result). If the lists have partial matches you need to report on, you could build a list of lists for each list. The idea is that each level would contain more information. So first list would be a single year and contain a list of months, which contains a list of days, which contains lists of hours, and the next level minutes. Each list can be a static array so there is no walking through the list, just checking against nil to see if that array position has a list (and potential values) or not. It has the disadvantage of using more memory, and requires time to build/destroy the list, but should be very quick to access. You just need to do a decodeDateTime to break a datetime into its parts, then use that to see if there is a value in the other list(s) that matches. The idea is to create something manageable and eliminate a need to loop and compare more than necessary. If you need to support multiple years, I would add another level to the start that would be a dynamic array of years and compute the array position as selected year - lowest year supported and grow your array as needed. if the year in the comparison list is outside of the bounds of that array, then it doesn't match anything that year.
  23. Steven Kamradt

    Parnassus Bookmarks for Delphi 11 Alexandria?

    And to twist the knife even deeper... I received a marketing email from Embarcadero today focusing on the Parnassus Navigator, saying how its available via getit, but in reality, no.... still nothing for Delphi 11... just 10.4.
×