해결된 질문
작성
·
76
답변 1
2
성락님 안녕하세요?
배포파일을 만드는 것은 너무너무 간단한 작업이기 때문에,
그냥 답변으로도 알려드릴 수는 있습니다.
우선 (가상환경을 사용하신다는 전제하에)
pyinstaller라는 모듈을 pip install pyinstaller
로 설치하셔야 합니다.
그리고 (.ipynb 파일이 아닌) .py
확장자로 코드를 완성하신 후에
터미널에서 pyinstaller -F -w 소스코드.py
라고 입력하고 실행하시면 됩니다.
이 때 -F 는 --onefile과 같은 의미로, 하나의 exe 파일로 만들겠다는 의미이고,
-w는 콘솔창을 유지하지 않겠다는 의미입니다. (GUI가 없다면 백그라운드에서 실행되는 겁니다.)
보안모듈은 배포되는 PC의 레지스트리에디터를 건드려야 하므로
그냥 "번거로우시겠지만 '모두허용' 버튼을 한 번 클릭해주시라~" 고 안내를 드리는 방법도 있지만,
win32com 대신 pyhwpx 모듈을 이용하시는 경우라면
FilePathCheckerModule.dll
파일을 소스코드와 동일한 폴더에 넣으신 후,
pyinstaller -F -w --add-binary="FilePathCheckerModule.dll:." 소스코드.py
라고 실행하시면 배포된 PC에서 보안모듈이 자동등록되면서 팝업창이 뜨지 않게 됩니다.
(가급적 배포시에 FilePathCheckerModule.dll
파일도 실행파일과 같이 배포하시는 걸 추천드림)
이 때 가상환경에 외부모듈이 많이 설치되어 있으면
컴파일할 때 실행파일 용량이 어마어마하게 커지는 경우가 있습니다.
여러가지 최적화 방법이 있지만,
제일 무난한 방법은, 개발용 말고 컴파일용 가상환경을 새로 하나 만들어버리는 겁니다.
그리고 딱 pyhwpx, pyinstaller 두 개만 설치한 상태에서 컴파일을 하면
40~70메가바이트 용량 정도로 만들어지는 듯 합니다.
테스트해보시고,
추가로 궁금한 점 있으면 댓글 남겨주세요!
컴파일한 exe파일과 FilePathCheckerModule.dll 파일을 같이 전송하시면 됩니다^^ 같은 폴더에 있으면 확실히 되어야합니다;;; (근데 안 된다는 경우가 있더라고요...)
제대로 컴파일이 되었으면 dll파일은 빼고 보내도 되는데, (또 안된다는 경우가 있다고 하더라고요..)
그리고 혹시 진짜 혹시 같이 보내도 안 된다고 하면
dll파일을 사용자 폴더(C:\Users\사용자이름)에다 넣으시면 확실하게 됩니다.
사실 제가 갖고 있는 모든 PC에서는 세 가지 방법 다 잘 되는데...
저도 컴파일해서 나눠드리면 간혹 안된다는 분들이 있어서 안심이 안 되네요...ㅜㅜㅜ
일코님 자꾸 질문드려 죄송합니다..
pyhwpx라이브러리에서 보안모듈 기능만 import할 수 있을까요?
함께 import해서 배포파일을 만들어보니 용량이 꽤 많이 커져서 여쭤봅니다
맞아요...
pyhwpx의 일부 메서드에서 numpy와 pandas를 쓰고 있기 때문입니다ㅠ
아래는 pyhwpx에서 보안모듈 자동등록 부분만 잘라낸 코드입니다.
기존 win32com으로 작성하시는 코드 상단에 붙여넣으시고,
hwp
객체 생성 직후에, 커스텀함수인 register_module(hwp)
를 실행하시면 됩니다.
① 레지스트리에 보안모듈이 등록되어 있는지 체크
-> 보안모듈 등록되어 있으면 : 레지스트리 경로값에 DLL파일이 존재하는지 체크하고,
DLL파일이 해당 경로에 존재하면 바로 이어서 hwp.RegisterModule()
실행. 끝.
-> 보안모듈이 등록되어 있지 않으면 : ②번 과정으로.
② 실행폴더 또는 사용자폴더에 FilePathCheckerModule.dll
파일이 있는지 체크
-> 둘 중 하나에 DLL 파일이 있으면 : 레지스트리 경로값 수정 또는 레지스트리 등록
-> DLL 파일이 없으면 사용자 폴더에 DLL 파일 다운로드 후 레지스트리 등록
등록을 마친 후 hwp.RegisterModule()
실행. 끝.
이런 과정을 거칩니다.
코드는 아래와 같습니다.
"""
아래아한글 보안모듈(FilePathCheckerModule.DLL) 자동등록 코드.
`if __name__ == '__main__':` 라인 밑으로 코드 작성하시면 됩니다.
"""
import os
import win32com.client as win32
from winreg import ConnectRegistry, HKEY_CURRENT_USER, OpenKey, KEY_WRITE, SetValueEx, REG_SZ, CloseKey, KEY_READ, QueryValueEx
def check_registry_key():
"""
보안모듈이 등록되어 있는 경우, 레지스트리 수정하지 않기!
"""
winup_path = r"Software\HNC\HwpAutomation\Modules"
alt_winup_path = r"Software\Hnc\HwpUserAction\Modules"
reg_handle = ConnectRegistry(None, HKEY_CURRENT_USER)
for path in [winup_path, alt_winup_path]:
try:
key = OpenKey(reg_handle, path, 0, KEY_READ)
try:
value, regtype = QueryValueEx(key, "FilePathCheckerModule")
if value and os.path.exists(value):
print("Security Module already registered.")
CloseKey(key)
return True
else:
print("Security Module DLL doesn't exist in registered path.")
CloseKey(key)
return False
except FileNotFoundError:
pass
CloseKey(key)
except FileNotFoundError:
pass
return False
def register_module(hwp, module_type="FilePathCheckDLL", module_data="FilePathCheckerModule"):
"""
레지스트리 체크해서 보안모듈 등록되어 있지 않으면 등록하고 보안모듈 실행
"""
if not check_registry_key():
register_regedit()
return hwp.RegisterModule(ModuleType=module_type, ModuleData=module_data)
def register_regedit():
"""
레지스트리에 보안모듈 등록하기
"""
# 1. 현재 폴더에 보안모듈 파일이 있는지
location = os.environ["USERPROFILE"]
if "FilePathCheckerModule.dll".lower() in [i.lower() for i in os.listdir(os.getcwd())]:
print("Found Security Module DLL in Current Path.")
location = os.getcwd()
# 2. 사용자 폴더에 보안모듈 파일이 있는지
elif "FilePathCheckerModule.dll".lower in [i.lower() for i in os.listdir(os.path.join(os.environ["USERPROFILE"]))]:
print("Found Security Module DLL in USERPROFILE Path.")
pass
else:
# 3. 두 군데 다 없으면 직접 다운받아버리기
from urllib import request
from urllib.error import URLError
from zipfile import ZipFile
print("downloading FilePathCheckerModule.dll to USERPROFILE path")
try:
f = request.urlretrieve(
"https://github.com/hancom-io/devcenter-archive/raw/main/hwp-automation/%EB%B3%B4%EC%95%88%EB%AA%A8%EB%93%88(Automation).zip",
filename=os.path.join(os.environ["USERPROFILE"], "FilePathCheckerModule.zip"))
with ZipFile(f[0]) as zf:
zf.extract(
"FilePathCheckerModuleExample.dll",
os.path.join(os.environ["USERPROFILE"]))
os.remove(os.path.join(os.environ["USERPROFILE"], "FilePathCheckerModule.zip"))
if not os.path.exists(os.path.join(os.environ["USERPROFILE"], "FilePathCheckerModule.dll")):
os.rename(os.path.join(os.environ["USERPROFILE"], "FilePathCheckerModuleExample.dll"),
os.path.join(os.environ["USERPROFILE"], "FilePathCheckerModule.dll"))
location = os.environ["USERPROFILE"]
except URLError as e:
print(f"아래와 같은 이유로 URL 에러가 발생하여 보안모듈 다운로드에 실패했습니다: \n{e.reason}")
except Exception as e:
print(f"예기치 못한 오류가 발생했습니다. 아래 오류를 복사하여 개발자 이메일로 전달 부탁드립니다: \n{str(e)}\n\nto `martinii.fun@gmail.com`")
winup_path = r"Software\HNC\HwpAutomation\Modules"
reg_handle = ConnectRegistry(None, HKEY_CURRENT_USER)
try:
key = OpenKey(reg_handle, winup_path, 0, KEY_WRITE)
except FileNotFoundError as e:
winup_path = r"Software\Hnc\HwpUserAction\Modules"
key = OpenKey(reg_handle, winup_path, 0, KEY_WRITE)
SetValueEx(key, "FilePathCheckerModule", 0, REG_SZ, os.path.join(location, "FilePathCheckerModule.dll"))
CloseKey(key)
if __name__ == '__main__':
hwp = win32.gencache.EnsureDispatch("hwpframe.hwpobject")
register_module(hwp) # <--- 사전작업 및 hwp.RegisterModule()까지 실행하는 커스텀 함수
hwp.XHwpWindows.Item(0).Visible = True
# 아래에 이어서 코드 작성하시면 됩니다~~~
hwp.Open(r"C:\Users\Administrator\Documents\바탕화면에 있던 것들\수능수리\2024학년도 수능 수리(나형).hwp")
도움이 되길 바랍니다.
행복한 하루 되세요^^
안녕하세요! 테스트 해보았는데 잘 작동합니다.
다만, 보안모듈을 함께 넣어 배포해야할 것 같은데 자세한 내용을 설명 가능할까요..?
그냥 pyhwpx만 import하고 위의 내용대로 진행해도 동일하게 작동할까요?