win_wrap/com/
persist.rs

1/*
2 * Copyright (c) 2024. The RigelA open source project team and
3 * its contributors reserve all rights.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and limitations under the License.
12 */
13
14use std::fmt::{Debug, Formatter};
15pub use windows::Win32::System::Com::{
16    STGM, STGM_CONVERT, STGM_CREATE, STGM_DELETEONRELEASE, STGM_DIRECT, STGM_DIRECT_SWMR,
17    STGM_FAILIFTHERE, STGM_NOSCRATCH, STGM_NOSNAPSHOT, STGM_PRIORITY, STGM_READ, STGM_READWRITE,
18    STGM_SHARE_DENY_NONE, STGM_SHARE_DENY_READ, STGM_SHARE_DENY_WRITE, STGM_SHARE_EXCLUSIVE,
19    STGM_TRANSACTED, STGM_WRITE,
20};
21use windows::{core::HSTRING, Win32::System::Com::IPersistFile};
22
23/// 允许从磁盘文件加载对象或将其保存到磁盘文件,而不是存储对象或流。由于打开文件所需的信息因应用程序而异,因此对象上的 load 实现还必须打开其磁盘文件。
24pub struct PersistFile(IPersistFile);
25
26// https://learn.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-ipersistfile
27impl PersistFile {
28    #[allow(dead_code)]
29    pub(crate) fn from_raw(raw: IPersistFile) -> Self {
30        Self(raw)
31    }
32
33    /**
34    查询与对象关联的文件的当前名称。如果没有当前工作文件,此方法将检索对象的默认保存提示。
35    返回的文件名是加载文档时在调用 load 时指定的名称;如果文档已保存到其他文件,则在 save_completed 中。
36    如果对象没有当前工作文件,则该对象应提供默认提示,该提示将显示在“另存为”对话框中。例如,字处理器对象的默认保存提示可以是“*.txt”。
37    OLE 不调用 get_cur_file 方法。应用程序不会调用此方法,除非它们也调用此接口的 save 方法。
38    在保存对象时,可以在调用save之前调用此方法,以确定对象是否具有关联的文件。如果此方法成功返回,则可以使用NULL文件名和remember参数的true值调用save,以告知对象将自身保存到其当前文件。如果此方法失败,则可以使用返回的保存提示来要求最终用户提供文件名。然后,可以使用用户输入的文件名调用save以执行另存为操作。
39    */
40    pub fn get_cur_file(&self) -> Option<String> {
41        unsafe {
42            if let Ok(f) = self.0.GetCurFile() {
43                return match f.to_string() {
44                    Ok(s) => Some(s.clone()),
45                    Err(_) => None,
46                };
47            }
48        }
49        None
50    }
51
52    /**
53    确定对象自上次保存到其当前文件以来是否已更改。
54    使用此方法可确定是否应在关闭对象之前保存该对象。在  save  方法中有条件地清除对象的脏标志。
55    */
56    pub fn is_dirty(&self) -> bool {
57        unsafe { self.0.IsDirty() }.is_ok()
58    }
59
60    //noinspection SpellCheckingInspection
61    /**
62    打开指定的文件并根据文件内容初始化对象。
63    load 从指定文件加载对象。此方法仅用于初始化,不会向最终用户显示对象。它不等同于用户选择“文件打开”命令时发生的情况。
64    文件名字对象中的  bind_to_object  方法调用此方法以在名字对象绑定操作期间加载对象 (当链接对象运行时) 。通常,应用程序不会直接调用此方法。
65    `filename` 要打开的文件的绝对路径。
66    `mode` 打开文件时要使用的访问模式。可能的值取自 STGM 枚举。该方法可以将此值视为建议,并在必要时添加更多限制性权限。如果 mode 为 0,则实现应使用用户打开文件时使用的任何默认权限打开文件。
67    */
68    pub fn load(&self, filename: String, mode: STGM) {
69        unsafe { self.0.Load(&HSTRING::from(filename), mode) }.unwrap_or(())
70    }
71
72    /**
73    将对象的副本保存到指定的文件。
74    可以通过以下三种方式之一调用此方法将对象保存到指定文件:
75    实现者必须检测调用方请求的保存操作类型。如果 filename 参数为 NULL,则请求 save。如果 filename 参数不为 NULL,请使用 remember 参数的值来区分“另存为”和“另存副本为”。
76    在“保存”或“另存为”操作中,save 在保存后清除内部脏标志,并将 AdviseSink::on_save 通知发送到任何咨询连接。此外,在这些操作中,对象处于 NoScribble 模式,直到它收到 save_completed 调用。在 NoScribble 模式下,对象不得写入文件。
77    在另存为方案中,实现还应将 AdviseSink::on_rename 通知发送到任何咨询连接。
78    在“另存为”方案中,实现不会在保存后清除内部脏标志。
79    OLE 不调用 save。通常,应用程序不会调用它,除非它们将对象直接保存到文件中,这通常留给最终用户。
80    `filename` 应将对象保存到的文件的绝对路径。如果 filename 为 NULL,则对象应将其数据保存到当前文件(如果有)。
81    `remember` 指示是否将filename参数用作当前工作文件。如果为true,则filename将成为当前文件,并且对象应在保存后清除其脏标志。如果为false,则此保存操作是“将副本另存为...”操作。在这种情况下,当前文件保持不变,对象不应清除其脏标志。如果filename为NULL,则实现应忽略remember标志。
82    */
83    pub fn save(&self, filename: Option<String>, remember: bool) {
84        unsafe {
85            match filename {
86                None => self.0.Save(None, remember),
87                Some(f) => self.0.Save(&HSTRING::from(f), remember),
88            }
89        }
90        .unwrap_or(());
91    }
92
93    /**
94    通知对象它可以写入其文件。它通过通知对象它可以从 NoScribble 模式(在该模式下不得写入其文件)恢复到正常模式(在该模式下可以)来实现此目的。组件在收到 save 调用时进入 NoScribble 模式。
95    当完成对save的调用时,将调用save_completed,并且保存的文件现在是当前工作文件(已使用“保存”或“另存为”操作保存)。对save的调用将对象置于NoScribble模式,因此它无法写入其文件。调用save_completed时,对象将恢复为正常模式,在该模式下,它可以自由地写入其文件。
96    OLE 不调用 save_completed 方法。通常,除非应用程序将对象直接保存到文件中,否则应用程序不会调用它,该操作通常留给最终用户。
97    `filename` 之前保存对象的文件的绝对路径。
98    */
99    pub fn save_completed(&self, filename: String) {
100        unsafe { self.0.SaveCompleted(&HSTRING::from(filename)) }.unwrap_or(())
101    }
102}
103
104impl Debug for PersistFile {
105    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
106        write!(f, "PersistFile()")
107    }
108}