According to this thread, F# Core must be SQLCLR-approved for assemblies to be marked SAFE. Is this planned? Can it even be done?
I believe it can be done. However, F# core library is the sole property of Microsoft. This means you can't modify its code and recompile it to match and comply with SQLCLR SAFE. I suggest you add suggestion to Microsoft using Microsoft's connect website.
Microsoft connect is at: http://connect.microsoft.com (you have to register and have email account on live.com or hotmail.com before register).
To manually add your .NET DLL and integrate it to SQL Server, you can do this:
In this example, the DLL from your F# code has to be compiled first. I take this step from MSDN Library link:
http://msdn.microsoft.com/en-us/library/ms254956(v=vs.80).aspx
Just don't forget to add PERMISSION_SET = SAFE to the CREATE ASSEMBLY command.
Here are the steps I quote from above link:
Loading and Running the "Hello World" Stored Procedure in SQL Server
Once the sample procedure has successfully
compiled, you can test it in SQL
Server. To do this, open SQL Server
Management Studio and create a new
query, connecting to a suitable test
database (for example, the
AdventureWorks sample database). We
will need to create the assembly so we
can access the stored procedure. For
this example, we will assume that you
have created the helloworld.dll
assembly in the C:\ directory. Add the
following Transact-SQL statement to
your query.
CREATE ASSEMBLY helloworld from 'c:\helloworld.dll' WITH PERMISSION_SET = SAFE
Once the assembly has been created,
we can now access our HelloWorld
method by using the create procedure
statement. We will call our stored
procedure "hello":
CREATE PROCEDURE hello
AS
EXTERNAL NAME helloworld.HelloWorldProc.HelloWorld
Once the procedure has been created,
it can be run just like a normal
stored procedure written in
Transact-SQL. Execute the following
command:
EXEC hello
This should result in the following
output in the SQL Server Management
Studio messages window.
Hello world!
Edit: based on the commenter below, he's right about F# is now open source! You can modify and recompile it to suit your needs.
Edit: adding more detail guide on how to integrate the DLL to SQL Server CLR integration.
A trick, as nasty as it is, would be using the --standalone flag of fsc (aka the F# compiler). This can even be added in the project settings and embeds in the output artifact the F# runtime library (along with all other dependencies deemed embeddable). I believe that at that point you should be able to do exactly what you want just by marking your assembly as SQLCLR safe.
Related
We have a COM server written in Delphi 10.2 Tokyo which contains 4 classes, all of which inherit from TAutoObject, and all have an initialization section containing the call to TAutoObjectFactory.Create.
In a typical installation, we have approximately 60 other programs that make use of the classes in the COM server. This all works fine. Each of the classes has their own GUID and the Delphi COM server does its usual thing of ensuring they are all registered correctly as part of the InitComServer process that runs from Application.Initialize.
We now have a need to run multiple installations side-by-side, where they may be different versions. Since we don't control all of the programs, we can't produce a different version of the COM server with different GUID's for every installation.
I had found this Microsoft document:
DLL/COM Redirection on Windows
But that approach does not work. When the main program starts and creates an instance of the first COM server class, I can see that it is the registered EXE that is running, not the COM server EXE in the same folder as the main program. This might be because it's an EXE and not a DLL, and Delphi's initialization is circumventing the DLL/COM redirection.
Here's an example of using one of the COM classes:
function ProduceReport(const ATenantID, AReportID: Integer; const AFilter: String): String;
var
AReportServer: IReportServer;
begin
Result := '';
AReportServer := CoReportServer.Create;
try
if AReportServer.Connect(ATenantID) then
begin
if not AReportServer.Print(AReportID, AFilter) then
Result := AReportServer.GetLastError;
end
else
Result := AReportServer.GetLastError;
except on E: Exception do
Result := E.Message;
end;
AReportServer := nil;
end;
The main thing of note is that the CoReportServer.Create does this internally:
Result := CreateComObject(CLASS_ReportServer) as IReportServer;
which in turn is doing this:
OleCheck(CoCreateInstance(ClassID, nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IUnknown, Result));
I can't see what CoCreateInstance is doing, but I am wondering if there is a way to call CoGetInstanceFromFile instead? Perhaps by changing the CoReportServer.Create in the TLB to use my own code instead of the CreateComObject?
Would changing the call to TAutoObjectFactory.Create to use a different TClassInstancing, such as ciSingleInstance, make any difference?
I just want it so that when a program calls CoReportServer.Create, it creates an instance of the server from the EXE it has in the program's folder, not by looking up the InprocServer from the Registry. I don't want the Registry to be used at all.
[Edit]
Since we also have an OCX that will need to be registry-free, I followed the steps discussed in this post:
Generate manifest files for registration-free COM
I have a manifest file for the OCX test app and a manifest file the OCX itself, both of which are in the same folder as the test app and the OCX. The manifest file specifies the same version number of the OCX as the one in the folder.
I then copied an old version of the OCX to a different folder, ran an elevated CMD prompt, and used Regsvr32 to register that OCX in that folder.
Running the OCX test app, which includes the ActiveX control on the main form, I can see from Process Explorer that it is using the registered OCX, and not the OCX in the same folder.
This may indicate that Delphi EXE programs can't handle the manifest approach to this, even if I include the custom manifest in the Project Options.
We have a mix of COM server EXE, ActiveX visual control OCX, and ActiveX type library DLL, all written in Delphi 10.2 Tokyo, that we need to make registry-free.
[Edit 23/03/2022]
I've made some progress on this by referencing the information contained in the answer for Registration-free COM/DLL?
I now have a manifest file for the DLL containing an <assemblyIdentity> tag, a <file> tag containing a list of <comClass> tags for each CLSID in my DLL, and a list of <comInterfaceExternalProxyStub> tags to link the CLSID's and IID's with the interface name.
And there is a manifest file for the host EXE, that includes the same <assemblyIdentity> tag information, but contained within a <dependentAssembly> tag.
Using SxSTrace, I can see "INFO: Activation Context generation succeeded.", so at least the side-by-side configuration is correct.
However, when running the test program, at the point it is calling CoReportServer.Create, it is falling over with a "Error loading type library/DLL" message. Based on the stack trace, this is from the LoadTypeLibrary call inside the TAutoObjectFactory.Create process from the initialization section of the first class implementation of the first interface.
Since the SO answer I looked at mentions making sure it will work when the DLL is registered, I tried using regsvr32 from an elevated command prompt, but get a "Runtime error 217" popup, followed by "The module "reportserver.dll" failed to load. A dynamic link library (DLL) initialization routine failed."
The Result from LoadTypeLibEx is -2147312566, which doesn't seem to match the TYPE_E_CANTLOADLIBRARY result.
So it looks like I may have got the registry-free COM part to work, but the conversion of the out-of-process COM server to an in-process COM library isn't right.
So I went back to the COM server EXE, and re-registered that to confirm the test program still works. It did. Then I altered the test program manifest to point to the COM server EXE instead of my trial conversion DLL, made a new manifest file for the COM server EXE, containing all the IID's and CLSID's, and un-registered the EXE.
The test program reports "Class not registered", so that pretty much confirms the activation context approach only works on DLL's.
That leaves me with figuring out why the DLL will not load, although another issue I just thought of is that the DLL is in-process, meaning every program that uses the library has to create it's own instance. That could be very resource intensive.
[Edit 25/03/2022]
Skipping the out-of-process COM server for the moment, I've now taken a look at our ActiveX Control, which is a descendent of a TProgressBar and is used either on a VCL form or created at runtime.
Following the same approach for defining the manifest file, I've created the <assemblyIdentify>, <file> and <comInterfaceExternalProxyStub> tags, but I noticed that in the _TLB.pas, there is one extra TGUID for DIID_IReportControlEvents.
Reviewing the Microsoft documentation for manifest files, I cannot see any reference to an events type of interface, so I'm not sure how that one will work.
In any case, a manifest file doesn't work for an OCX. I just get the "Class not registered" error.
The SxStrace file shows "INFO: Activation Context generation succeeded." but it doesn't include any information about the manifest for the OCX, so it is not loading it at all.
This is probably because the _TLB.pas for the OCX shows it is using OleControl rather than COM. Removing the {$E ocx} from the DPR means Delphi creates a DLL instead, but that also fails.
I am writing an exe OLE server to embed it in my own application. I am running OLE server (exe) with /regserver parameter as a normal user and I am getting following error:
Error accessing the OLE registry
I don't need any other programs to use this server. It is just for my own client and it will not be a DLL. Is there a way to register it as standard user?
Other problem is that i see codes which are not pascal in ridl file. Types of properties are C not Pascal. For example i see DATE but i don't see TDateTime in the list. I am using XE5.
Use switch "/REGSERVERPERUSER"
I use XE5, it work.
Delphi write corresponding register keys
Use the PerUserRegistration to ensure that your COM server self-registers to the per-user HKCU hive. Or simply write the registry settings yourself. Which is the recommended approach anyway if you are writing an install program.
RIDL is a flavour of Interface Description Language (IDL). It is used to describe the interface of your COM server. It is not Pascal. It's not passed to a Pascal compiler. It's processed by a tool that understands RIDL. Everything is as expected.
i am using Delphi XE4 to create a Voip program. i am using an outdated VOIP SDK From a company called BigSpeed which is no longer around the current code points to the following path 'C:\Program Files (x86)\BigSpeed Voice SDK\' where the active x controls are stored.
LIBID_bsVoiChatCln: TGUID = '{D2A88515-99E0-4EEE-A030-E5D2AB306A03}';
IID_IbsVoiChatClnX: TGUID = '{5055A626-56A1-4E58-A461-000A69CA3E03}';
DIID_IbsVoiChatClnXEvents: TGUID = '{665DB561-22D3-4624-B55B-4416309A2E03}';
CLASS_bsVoiChatClnX: TGUID = '{BE761C1E-1F6C-46F8-A99B-0AB29C9B2D03}';
How can i create a new GUID and have the program access the active x controls from a new directory.
You don't want to create new GUIDs. The GUIDs are the identifiers of that component. All you want to do, as far as I can tell from the question and your comments, is to register the DLL at a different location.
The ActiveX DLL almost certainly uses self-registration. This means that you can put the DLL somewhere else and register it there. For instance, suppose the DLL is located in:
C:\MyFolder\MyDll.dll
Then you could register it by executing this command:
regsvr32 C:\MyFolder\MyDll.dll
Looks like you do not understand (or do not explain) relations between your program, the library and the GUIDs.
How can i create a new GUID and
1) GUID is just a 128-bit random number. So you can "create new GUID" simply by editing its hexadecimal string. Or you can press Ctrl+Shift+G in Delphi source editor in designtime. In runtime you can use CreateGUID function of SysUtils unit.
http://docwiki.embarcadero.com/CodeExamples/XE5/en/UsingGUIDs_(Delphi)
http://docwiki.embarcadero.com/Libraries/XE2/en/System.SysUtils.CreateGUID
http://en.wikipedia.org/wiki/GUID
But i don't think creating new GUID will do you any good. If anything, it should mean explicitly declared incompatibility with old GUIDs (hence incompatibility with VOIP library)
from a new directory.
2) Why do you think your VoIP library is arranged as a set of ActiveX control ? Just because there are GUIDs there? Not any text file with GUIDs inside would be ActiveX.
ActiveX are specifically arranged Windows servers, that are registered in the registry so that any program could call them. Sometimes you can register them after the fact, if the installer failed it.
http://en.wikipedia.org/wiki/Activex
http://en.wikipedia.org/wiki/Regsvr32
http://support.microsoft.com/?id=207132
So you should read manuals for your library whether they constitute ActiveX or not, and if they do, how to register them in Windows (should be done by the library installer)
If installer does not provide for it, then you can not be sure that the library can work from a different place. Not only your program needs a connection to it, but also the library itself may need connection to its other parts.
have the program access the active x controls
3) If your library really conforms to ActiveX specifications and if it was correctly installed (registered) then you can just import them into Delphi IDE and drop them onto the form like you drop tables and dialogs.
http://docwiki.embarcadero.com/RADStudio/XE3/en/Import_Component_Wizard
http://delphi.about.com/library/howto/htaddactivex.htm
http://www.delphisources.ru/pages/faq/master-delphi-7/content/LiB0125.html
4) if you do not want to drop your VoIP component onto the form, then you can try to create it in runtime with CoCreateInstance. But first you have to read some tutorial about Microsoft COM for beginners. You may miss some advanced concepts, but you should understand the most basic things like how interfaces are similar to and different from classes, how their lifetime is managed, how COM runtime is initialized and finalized for your program and so on.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686615.aspx
http://delphi.about.com/library/weekly/aa121404a.htm
http://www.delphikingdom.ru/asp/viewitem.asp?catalogid=1135
How to use CoCreateInstance() to get a com object?
https://stackoverflow.com/search?q=%5Bdelphi%5D+cocreateinstance
all the MS Office related examples in c:\RAD Studio\9.0\OCX\Servers\
5) you may also try to bypass the proper Windows ways of locating and loading the server and try to do it yourself, using DllGetClassObject routines in proper DLLs. If the library is permissive, it will work. But if it does rely on Windows-provided services that has a potential for all kinds of crashes and unmet expectations.
https://www.google.com/search?client=opera&q=CoCreateInstance+and+DllGetClassObject&sourceid=opera&ie=utf-8&oe=utf-8&channel=suggest
http://msdn.microsoft.com/en-us/library/windows/desktop/ms680760.aspx
How do I use a COM DLL with LoadLibrary in C++
DllGetClassObject return "No such interface supported" while CoCreateInstance can find it successful
If my memory serves me, You can find examples of that approach in early HTML Help units for delphi. Microsoft HTML Help provides for both late binding using CoCreateInstance and runtime ActiveX servers registry, or early binding towards htmlhlp.ocx treated as DLL. Early versions of HTML Help API for Delphi provided for both options. But i may be wrong here.
My project is on Delphi 2009, Paradox DB and Google Maps. The code is OK and the time right now is to build the project. This is the first time to do it. As I know there are two programs to create the setup file; InstallShield or InstallAware. Via InstallAware I did my first test but its fail and the problem is the DB, I could not run it after the setup. How can I make the DB work in setup file.
In my delphi project there is two part for DB connections;
the first one with; Query1--->DataScore1
the second one; Table1--->Datascore2
the root of delphi files is "Desktop\ttelekom\ttelekom.exe
the root of DB files is "C:\Program Files\Common Files\CodeGear Shared\Data\databasettelekom.db"
Here the picture of Delphi main form;
http://img267.imageshack.us/img267/5333/77714402.png
Thanks for all.
How are you accessing the database? If it's using the BDE, you have to install the BDE. There's a merge module you can add to your installation, by default in %CommonProgramFiles%\Borland Shared\BDE\ - read the bdedeploy.txt file you'll find there, along with bdeinst.txt.
If you're using another way to access the Paradox files (for instance, ODBC), you'll have to configure that instead.
asilloo, when you said "..As I know there are two programs to create the setup file.." that is not true, exist many options to create installers like wise, nsis, Inno-setup.
for you specific task i will you recommend Inno-setup, because is freeware, reliable, easy to learn and the script language used to create the installers is delphi.
to deploy your application do you need install the bde in client machine. check this sample using inno-setup.
Inno Setup Knowledge Base - HOWTO: Deploy BDE (Borland Database Engine)
I downloaded the system.xml.dll, then added it to my Delphi code as following:
uses system.xml;
etc...
When I try to compile the project, the following message appears:
file not found system.xml.dcu.
Can anyone guide me how to solve this problem?
Thanks.
The uses clause in Delphi refers to Delphi units, either compiled in a *.dcu file or a *.pas source file that the compiler will use to generate the corresponding *.dcu that is needed.
You cannot just reference the DLL itself.
To use your DLL, you would need at least a unit that would expose in a Pascal way the DLL interface or parts of it.
It can be the Pascal translation of a C header file or just declaring some external routines from the dll to load statically with your program...
What you probably need to reference to work with XML in Delphi are XMLIntf and maybe xmldom.
Have you looked at what the XML Data binding wizard or the XML Mapper Tool can do for you?
Note: I assumed you were working with Delphi Win32. And AFAIK system.xml.dll is part of the .NET world.
If you are using Delphi for .Net you need to add a reference to the system.xml.dll assembly to your project.
If you are using Delphi (Win32), then in order to be able to use .NET assemblies (DLLs), you have the option of using COM interfaces. Follow below steps:
Open the project you want to use it in.
Use Component menu.
Select "Import Type Library"
Select the DLL you want to use.
Follow the next steps as given by wizard.
This will generate a source file which is essentially a wrapper. You can call function of that wrapper as you need.
Please note that using above method will mean that .NET framework must be present on the computer running your application.