module DwgProvider
#nowarn "25"
open System
open System.IO
open System.Text
open Autodesk.AutoCAD.ApplicationServices
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Samples.FSharp.ProvidedTypes
open Microsoft.FSharp.Core.CompilerServices
let GetDwgProp path= //функция "бинарного" получения пользовательских свойств dwg файла
let br=new BinaryReader(File.OpenRead(path))
let rec PropVal=function
|a::b::c->(a,b)::PropVal c
|_->[]
let ReadProps count=
{1..count}|>Seq.map (fun _ -> let str=br.ReadBytes(int32(br.ReadInt16())*2)
|>Encoding.Unicode.GetString
str.Substring(0,str.Length-1))
|>Seq.toList
br.BaseStream.Seek(32L,SeekOrigin.Begin)|>ignore
br.BaseStream.Seek(br.ReadInt32()|>int64,SeekOrigin.Begin)|>ignore
let sp=ReadProps 8
br.BaseStream.Seek(24L,SeekOrigin.Current)|>ignore
sp,ReadProps(int32(br.ReadInt16())*2)|>PropVal
let DbProperty (db:obj)= //функция получение пользовательских свойств Database через .Net Api
let cp=(db:?>Database).SummaryInfo.CustomProperties //аргумент приведен к Object чтоб не требовалась сборка AutoCAD во время компиляции
Seq.unfold (function |true->Some((cp.Entry.Key:?>string,cp.Entry.Value:?>string),cp.MoveNext())
|false->None)
(cp.MoveNext())
[<TypeProvider>] //объявление поставщика типа
type DwgPr() as this =
inherit TypeProviderForNamespaces()
let asm,ns = System.Reflection.Assembly.GetExecutingAssembly(),"DwgProvider"
let IniTy = ProvidedTypeDefinition(asm, ns, "DwgProv", None)
do IniTy.DefineStaticParameters(
[ProvidedStaticParameter("path", typeof<string>)],
fun tyName [|:? string as path|] ->
let ty = ProvidedTypeDefinition(asm, ns, tyName, None)
ProvidedConstructor([ProvidedParameter("Database",typeof<obj>)],
InvokeCode=(fun [db]-> <@@ (%%db:obj)|>DbProperty @@>)) //цитированный код конструтора (работает во время выполнения)
|>ty.AddMember
path|>GetDwgProp|>snd // создаем свойства типа на основе шаблона path (во время компиляции)
|>Seq.map (fun (key,_)->
ProvidedProperty(key,typeof<string option>,
GetterCode=fun [arg] -> //цитированный код получения свойства работающий во время выполнения
<@@ (%%arg:obj):?>(string*string) seq
|>Seq.tryPick (function |k,v when k=key->Some(v)
|_->None) @@>))
|>Seq.toList|>ty.AddMembers
ty)
this.AddNamespace(ns, [IniTy])
[<TypeProviderAssembly>]
do()// запускаем поставщик