I'm testing a non visual ActiveX control based on a registered .ocx
which I import into Delphi using the provided wizard.
Then, I simply put the generated component on the main form of a new VCL application.
Under old Delphi versions (D5 and D2007), when i launch the application, this raise an AV
during the component initialization.
with Delphi 2009 : no problem, the application starts smoothly.
My questions are :
Are there known enhancements of ActiveX management in recent Delphi versions which
can explain this difference ?
Can I suspect a bug in the ActiveX control, or can I consider the origin of the
problem is from old Delphi versions ?
I need to use this component (if tests OK) in D2007.
Do you think that it is possible to correct the AV problem under D2007 by modifying the D2007 generated .tlb file (for example by trying to use the D2009 generated one)
PS: the ActiveX control is not named, because my question is a general question about Delphi and ActiveX, not about a specific ActiveX control.
Edit :
With D2007, the error (an Access Violation) appears during Application.CreateForm(TForm1, Form1);
and more specifically when the Olecontrol is created :
procedure TOleControl.CreateInstance;
var
ClassFactory2: IClassFactory2;
LicKeyStr: WideString;
procedure LicenseCheck(Status: HResult; const Ident: string);
begin
if Status = CLASS_E_NOTLICENSED then
raise EOleError.CreateFmt(Ident, [ClassName]);
OleCheck(Status);
end;
begin
if not (csDesigning in ComponentState) and
(FControlData^.LicenseKey <> nil) then
begin
// ON THE LINE BELOW : the call of CoGetClassObject raise an AV
OleCheck(CoGetClassObject(FControlData^.ClassID, CLSCTX_INPROC_SERVER or
CLSCTX_LOCAL_SERVER, nil, IClassFactory2, ClassFactory2));
LicKeyStr := PWideChar(FControlData^.LicenseKey);
LicenseCheck(ClassFactory2.CreateInstanceLic(nil, nil, IOleObject,
LicKeyStr, FOleObject), SInvalidLicense);
end else
LicenseCheck(CoCreateInstance(FControlData^.ClassID, nil,
CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IOleObject,
FOleObject), SNotLicensed);
end;
As far as I remember there were major enhancements to the ActiveX/TLB import in Delphi 2009 (related to Unicode support) - that might explain it.
In my personal experience Delphi 7 and Delphi 2007 repeatedly failed to import some Windows 7 type libraries (various new interfaces to work with new taskbar), but Delphi 2009 managed that without any problems at all.
As for using Delphi 2009 generated file in earlier versions - beware of Unicode issues. Plus it won't help if the defect is in RTL... Try to make a wrapper ActiveX in Delphi 2009 and use it in Delphi 2007 - that should work.
Sorry to barge in so late after the battle (5 years later as a matter of fact), but I wasted so much time on this precise issue that I thought I should share what I've seen and what I've done to solve it :
2 machines (win7 64 / win 8.1) same delphi 7 (same version same build), same activeX (MapX to name it) with identical .lic files containing the key made of 59 characters :
uQnZi2sFw22L0-MRa8pYX-1E2P8065-5N5M3459-3C934220-04969-6562
same import producing 2 slightly different TLB.
The one working : (on win 8.1) contains this in procedure TMap.InitControlData :
const
CLicenseKey: array[0..61] of Word = ( $0075, $0051, $006E, $005A, $0069, $0032, $0073, $0046, $0077, $0032, $0032
, $004C, $0030, $002D, $004D, $0052, $0061, $0038, $0070, $0059, $0058
, $002D, $0031, $0045, $0032, $0050, $0038, $0030, $0036, $0035, $002D
, $0035, $004E, $0035, $004D, $0033, $0034, $0035, $0039, $002D, $0033
, $0043, $0039, $0033, $0034, $0032, $0032, $0050, $0030, $002D, $004D
, $0030, $0034, $0039, $0036, $0039, $002D, $0036, $0035, $0036, $0032
, $0000);
which translates to a 61 char key
uQnZi2sFw22L0-MRa8pYX-1E2P8065-5N5M3459-3C93422P0-M04969-6562
The TLB that does not work (win 7 64) contains this instead:
const
CLicenseKey: array[0..2] of Word = ( $0050, $004D, $0000);
which translates to a 2 char key
PM
Replacing one const with the other and recompiling the component solved my issue. I don't really know what happened. I just know the Import/TLB produced a bad .pas file that can be corrected manually.
Related
I use Delphi X10 and Word 2016 64-bit on Windows 10 64-bit.
I always used ComObj.
for example:
uses ComObj;
procedure TForm1.RzBitBtn1Click(Sender: TObject);
var Excel: variant; i, j: word;
begin
Excel := CreateOleObject('Excel.Application');
Excel.Workbooks.Open('file.xls');
for i := 1 to 5 do
for j := 1 to 5 do
StringGrid1.Cells[j, i] := Excel.Sheets[1].Cells[i, j].Text;
end;
But, i want to use autocompleate for Excel methods. I read what i should import type library, but i cant find type library file in my system.
This is quite easy to do, as long as the type libraries for Excel anmd Word are correctly registered.
Go to the OCX\Servers folder under your Delphi install and find Word2010.Pas. Add it to a new VCL project, and USE it in the main form's unit. Declare a form variable A: WordApplication on your main form.
With that done, you should be able to go to Form1's Form.Create, type
A.
and autocomplete should offer you the possibilities for WordApplication's methods and properties.
Now, open Word2010.Pas and find the section
// File generated on 2/20/2013 5:56:45 PM from Type Library described below.
// ************************************************************************ //
// Type Lib: c:\Program Files\Microsoft Office\Office14\msword.olb (1)
// LIBID: {00020905-0000-0000-C000-000000000046}
That tells you the name and location of the type library which was used to generate Word2010.Pas.
Now, unless you need to use some method/property that has been added to Word/Excel since the 2010 version, Word2010.Pas and Excel2010.Pas may be all you need. However, you can import the type library of a more recent version using Delphi and have it generate an import unit for it. Exactly how to do that depends on your Delphi version, but for Delphi Seattle. you simply go to Component | Import Component from the IDE main menu, then select Import type library in the pop-up and follow the wizard's prompts.
Once you've generated the import unit, obviously you simply USE it in your project instead of MSWord2010.
Btw, strictly speaking, there is no "Delphi X10", recent versions (since XE8) have been Seattle, Berlin and Tokyo.
I get the CromisIPC cromis ipc site download and compile/rum successfully the demos and custom project on delphi XE5. Without any error.
But, when I get the same code and put on DELPHI 7 project, I have an error on unit Cromis. AnyValue, an compilation error.
TAnyValue = packed record
private
ValueData: TValueDataType;
{$IFDEF AnyValue_HookingOff}
IntfData : IInterface;
{$ELSE}
{$IFNDEF CPUX64}
Padding : array [0..3] of Byte;
{$ENDIF}
{$ENDIF}
ValueType: TValueType;
function GetAsInt64: Int64; inline;
Exactly on lyne:
ValueData: TValueDataType;
[Error] Cromis.AnyValue.pas(210): ',' or ':' expected but identifier 'ValueData' found
[Error] Cromis.AnyValue.pas(219): 'END' expected but 'FUNCTION' found
I use delphi 7 on a 64 bits windows 7 with a 32 bits VCL project.
The same code compiles on XE5.
What happens here ? any idea ?
tl;dr This code is not designed to work under Delphi 7.
Visibility specifiers are not allowed in Delphi 7 records. The compiler is objecting to the use of private. You can remove that, but then the next problem will be all the methods that are declared on the record. Again, they are not available in Delphi 7.
You might be able to make some headway by switching from packed record to packed object. However, I think it highly unlikely that this will be smooth sailing. Expect a lot of work to make this code compile on Delphi 7. Frankly, you would need to be a Delphi expert to take on this task.
You might try to find an old version of the library that actually supports Delphi 7. You might be able to get one from the library's author. But note that the website says:
All code is Delphi 2006 and upwards compatible. I will not support older Delphi version. If you still use them, then its time to upgrade.
Which leads to the other obvious solution. Upgrade to a modern version of Delphi.
If that is impossible, then you should look for a different library.
I just found that lockbox 3.6.0 should support Android. However when i look in my palette i see that the codec only supports win32 and win64.
How can i make it work for my android apps also?
Im using Delphi XE7 and have already followed the installation instructions supplied in the package. For a windows app it works just fine.
You have two options:
(1) Run-time
You can always create the components at run-time. There is an example on the website on how to do it, and I copy a fragment of this example below. Just replace the ShowMessage() functions with whatever is appropriate ...
procedure EncryptAStream( Plaintext, Ciphertext: TStream);
var
Codec1: TCodec;
CryptographicLibrary1: TCryptographicLibrary;
begin
ShowMessage( 'Demonstration of How to Encrypt a Stream with TurboPower LockBox 3.');
Codec1 := TCodec.Create( nil);
CryptographicLibrary1 := TCryptographicLibrary.Create( nil);
Codec1.CryptoLibrary := CryptographicLibrary1;
Codec1.StreamCipherId := uTPLb_Constants.BlockCipher_ProgId;
Codec1.BlockCipherId := 'native.AES-256';
Codec1.ChainModeId := uTPLb_Constants.CBC_ProgId;
Codec1.Password := 'my utf-16le password';
// Codec1.Reset; Reset if you are continuing from a previous encryption operation.
Codec1.EncryptStream( Plaintext, Ciphertext);
// Codec1.Burn; Burn if you need to purge memory of sensitive data.
Ciphertext.Position := 0;
ShowMessageFmt(
'The ciphertext for AES-256 with CBC chaining'#13#10 +
' of plaintext ''banana'' (UTF-8 encoding),'#13#10 +
' and password ''my utf-16le password'' (UTF-16LE encoding),'#13#10 +
' prepended by 64 bit nonce, (being the IV),'#13#10 +
' and rendered for display in base64 is ...'#13#10 +
'%s', [Stream_to_Base64( Ciphertext)]);
Codec1.Free;
CryptographicLibrary1.Free;
end;
(2) Design-time
A little bit of tweaking is required to get the components onto the palette for Android. This will be done for you in the next version of TPLockbox 3 to be released, but for now, here is the procedure ...
Remove vcl, vclimg and dbrtl from the TPLB3 run-time requirements.
For the run-time package, add the Android target platform, and make it the active one. But of course, don't add this platform to the design-time package.
The binary product for the run-time should be named libTP_LockBox3_XE7.so, where XE7 is a place-marker for your compiler version.
Preface the declarations for the two components (TCodec and TCryptographicLibrary) with
[ComponentPlatformsAttribute( pidWin32 or pidWin64 or pidOSX32 or pidiOSSimulator or pidiOSDevice or pidAndroid)]
TCodec = class( TTPLb_BaseNonVisualComponent, ICryptographicLibraryWatcher,
{ etc. }
This is the key to the whole thing. The ComponentPlatformsAttribute attribute declares what platforms should the component be displayed for, on the palette. If not declared, I believe that the default is pidWin32 or pidWin64, but I cannot point to any official documentation to support this.
Recompile the run-time package. Remember that if your are compiling with MS-BUILD, on certain compiler versions, you need to save-all before you can successfully compile.
Go to the IDE Tools | Options and open the Library Path for the Android platform. Make sure that this path include the location of where you put the dcu files for the Android case. For example, on my installation it is ...
C:\Dev\TPLB\work-products\ephemeral\dcu\XE6\Android
You should physically check this directory. It should have a file named TPLB3.AES.dcu and another named TPLB3.AES.so for example.
Recompile and re-install the design-time package
Open your mobile project. Slap design-time components for TCodec and TCryptographicLibrary on your Android forms. Proceed as you would for a windows application.
I'm currently updating some existing Delphi code to compile on MacOS using Delphi XE2.
The Delphi XE2 Update 3 is installed.
On Win32 and Win64 a particular bit of the code works as expected and it also compiles/runs as expected when compiling with Delphi 4 all the way up to Delphi XE.
However, when compiling for MacOS the same piece of code doesn't work the same way. We've also had some crashes on the Mac - but that might have been the XE2 debugger.
type
TFixedSizeAnsiStringArray = array[0..255] of AnsiString;
procedure TForm1.Button1Click(Sender: TObject);
var
FirstArray: TFixedSizeAnsiStringArray;
SecondArray: TFixedSizeAnsiStringArray;
begin
FirstArray[0] := 'Apple';
FirstArray[1] := 'Banana';
FirstArray[2] := 'Pineapple';
// ...
SecondArray := FirstArray;
Memo1.Lines.Add(SecondArray[0]);
Memo1.Lines.Add(SecondArray[1]);
// ....
end;
On Windows, all the elements of SecondArray are the same as the elements of FirstArray.
But on MacOS (when it does run) only the first element of SecondArray has the correct value.
It's easy to fix with a for loop - but understanding why it's different between Windows and MacOS would be good to know.
Maybe something to do with the use of AnsiString?
That would appear to be a bug in the Mac OS compiler. Please can you submit a report to Quality Central.
I have to use an existing dll, but got a problem with it.
Here's how I try to use it:
unit u_main;
...
implementation
procedure getUserData(var User, Pass: string); stdcall; external 'Common5.dll';
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
u, p: string;
begin
getUserData(u,p);
end;
...
end.
When I press the button the get the userData, I get an EInvalidPointer exception.
The dll is registerd and in some other projects it's in use and work. any ideas?
EDIT:
The DLL was created in Delphi7 and is now used in a Delphi 2009 project.
Maybe there's a problem with unicode strings or something like that?
You need to rebuild the Delphi 7 DLL, make it follow the WinApi standard of getting PChar and BufferLen parameters. You've got multiple problems with the current implementation:
string is platform-specific, it's implementation may change between delphi versions (and did change). You're not supposed to use string outside the platform!
You're passing the parameters as "var", suggesting the DLL might change the value of user and/or pass. String is an special, managed type, changing it requires allocating memory for the new string. This in turns requires you to share the memory manager between the DLL and the EXE (using sharemem.pas and BorlandMM.dll - or variants). The trouble is, sharing the memory manager between different versions of Delphi is an unsupported configuration! (gotton from embarcadero forums)
The Delphi 7 is hoping to receive an simple AnsiString (1 byte chars), while the Delphi 2009 exe is sending Unicode strings (2 bytes per char).
Along with using PChar, be sure to pre-allocate the space before you call GetUserData. i.e. if you assign 'foo' into a pchar that's empty, you'll blow up. So either use static length PChar/PAnsiChar arrays, or use this technique:
var
s : AnsiString;
begin
setlength(s,256);
MyDLLProc(PAnsiChar(s));
end;