Excel VBA Cmをポイントに変換する ポイントをCm、ｍｍに変換するユーザー定義関数

# シートの書式設定
余白をCm単位で指定しようとするとポイントに変える必要がある。
1ポイントは1／72インチ。1インチが約25.4mmなので、1ポイントは25.4mm÷72より、約0.3528mm
行の高さはポイント
列幅は「8.38」が列幅を表す数値で、「標準フォント」の半角文字の文字数
列幅のCm単位の指定は CmToPt(3) / ((希望するセル.列幅)/(希望するセル.行の高さ))
[行高さと列幅をセンチメートル単位にする ： Excel(エクセル)](https://www.excel-excel.com/tips/vba_205.html)
[Range.ColumnWidth プロパティ](https://msdn.microsoft.com/ja-jp/vba/excel-vba/articles/range-columnwidth-property-excel?f=255&MSPPError=-2147217396)

>列幅の単位は、標準スタイルの 1 文字分の幅に相当します。プロポーショナル フォントでは、数字の 0 の幅が列幅の単位になります。
列幅をポイント単位で取得するには、 Width プロパティを使ってください。
対象セル範囲内のすべての列が同じ幅である場合、 ColumnWidth プロパティはその値を返します。対象セル範囲内の各列の幅が異なる場合、このプロパティは Null 値を返します。

# 謎 関数から返ってくる値のデータ型が違う
Accessと違いExcelにはCentimetersmToPointsがある。これはDobleで受けてDobleで返す。
##Excelの説明
［Application.CentimetersToPoints メソッド (Excel)］(https://msdn.microsoft.com/ja-jp/vba/excel-vba/articles/application-centimeterstopoints-method-excel?f=255&MSPPError=-2147217396)
###構文 
式 . CentimetersToPoints( Centimeters )
###式
Application オブジェクトを表す変数。
###パラメーター

|名前	|必須 / 省略可能	|データ型|説明|
|:-----:|:-------------:|:-----:|:------|
|Centimeters|必須|倍精度浮動小数点型 (Double)|変換の対象となる数値を指定します。|



これはWord PublisherにもあるがSngleで受けてSingleで返す。
[MillimetersToPoints Method](https://msdn.microsoft.com/en-us/library/office/aa212376%28v=office.11%29.aspx?f=255&MSPPError=-2147217396)


>Converts a measurement from millimeters to points (1 mm = 2.85 points). Returns the converted measurement as a Single.

また、Excelにはこの逆の関数はない。


#ユーザー定義関数
##仕組み
WordかPublisherを呼び出し、その関数を使って換算して返す。
なお、データ型はSingleになる。

##謎2
単純にWordの関数を起動してあとでNothingにすると、Wordはタスクマネージャーで詳細を出すと終了していないことが分かる。つまり必ずQuit命令がないとWordが増え続ける。
このため、Publisherを持っている人はPublisherにするとよい。
Publisherはシングル起動なので、別のPublisherを起動すると結果的に前のPublisherが終了しているためだと思われる。
##ユーザー定義関数で名前を省略
また関数名が長いのでCmToPointという関数を作って名前を省略する



```visualbasic

Public Function CmToPoint(CentiMenterUnitNum As Variant) As Double
On Error Resume Next
Dim CentiMeterDouble As Double
CentiMeterDouble = CDbl(CentiMenterUnitNum)
If Err.Number = 0 Then CmToPoint = Application.CentimetersToPoints(CentiMeterDouble) Else CmToPoint = 0
End Function

Public Function PtToCM(PointUnitDouble As Double) As Single
On Error Resume Next
Dim PointSingle As Single
Dim xApp,bl As Boolean
On Error Resume Next
Set xApp = CreateObject("Publisher.Application")
bl = True
If Err.Number <> 0 Then
Err.Clear
Set xApp = CreateObject("Word.Application")
bl = False
End if
PointSingle = CSng(PointUnitDouble)
If Err.Number = 0 Then PtToCM = Fix((xApp.PointsToCentimeters(PointSingle) * 100000) + 0.5) / 100000 Else PtToCM = 0: Debug.Print Err.Number, Err.Description: Err.Clear: Exit Function
If Not xApp Is Nothing And bl = True Then
 Set xApp = Nothing
 Exit Function
End If
If Not xApp Is Nothing And bl = False Then
If bl = False Then
xApp.Quit
Set xApp = Nothing
Exit Function
End If

End Function

Public Function PtToMM(PointUnitVariant As Variant) As Single
'Point to MilliMeters transfer (Single)
'Publisher And Excel You Need
On Error Resume Next
Dim PointSingle As Single
'Dim wApp: Set wApp = CreateObject("Word.Application")
Dim pApp: Set pApp = CreateObject("Publisher.Application")
PointSingle = CSng(PointUnitVariant)
If Err.Number = 0 Then PtToMM = Fix((pApp.PointsToMillimeters(PointSingle) * 100000) + 0.5) / 100000 Else PtToMM = 0: Debug.Print Err.Number, Err.Description: Err.Clear: Exit Function
Set pApp = Nothing
'WApp.Quit : Set wApp = Nothing 'Wordの場合はこちらをアクティブにする
End Function
```
#Access はCentimetersToPointsもない
[Access VBA Cmをポイントに変換する ポイントをCm、ｍｍに変換するユーザー定義関数](https://qiita.com/Q11Q/items/14bee01962f2c867021d)
なのでAccessはCentimetersToPointsからユーザー定義関数を作っている。

# 参考文献
[StandardWidth Property [Excel 2003 VBA Language Reference]](https://msdn.microsoft.com/en-us/library/office/aa215714%28v=office.11%29.aspx?f=255&MSPPError=-2147217396)

>Returns or sets the standard (default) width of all the columns in the worksheet. Read/write Double.