2009-12-17 29 views
15

Tôi đang viết một tệp Win32 DLL có chức năng thêm thư mục vào biến môi trường Windows PATH (được sử dụng trong trình cài đặt).Lập trình thêm thư mục vào biến môi trường Windows PATH

Nhìn vào các biến môi trường trong Regedit hoặc Bảng điều khiển sau khi DLL đã chạy cho tôi thấy rằng DLL của tôi đã thành công trong việc thêm đường dẫn đến HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\EnvironmentHKEY_CURRENT_USER\Environment.

Nhưng khi tôi khởi động Command Prompt mới (sau khi chạy DLL), thư mục tôi thêm vào không hiển thị ở đầu ra của echo %PATH% và tôi không thể truy cập tệp thực thi trong thư mục đó bằng cách nhập tên của nó.

Tôi nghĩ chương trình của tôi không thực hiện tốt công việc thông báo cho hệ thống rằng PATH đã thay đổi hoặc có thể thông báo cho họ trước khi thay đổi có hiệu lực đầy đủ. Tôi đọc một article by Microsoft nói rằng để phát sóng thông điệp WM_SETTINGCHANGE sau khi thay đổi một biến môi trường, và tôi đang làm điều đó với mã này:

DWORD result2 = 0; 
LRESULT result = SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 
    (LPARAM)"Environment", SMTO_ABORTIFHUNG, 5000, &result2); 
if (result == 0){ /* ... Display error message to user ... */ } 

Trình tự của các cuộc gọi của tôi là: RegCreateKeyEx, RegSetValueEx, RegCloseKey, SendMessageTimeout

Nếu tôi nhấn "OK" trong cửa sổ "Biến môi trường" Bảng điều khiển, những thay đổi được thực hiện bởi DLL của tôi đến PATH hiển thị trong nhắc lệnh mới được tạo ra, do đó, có một cái gì đó mà Control Panel đang làm để tuyên truyền thay đổi PATH; Tôi muốn tìm ra nó là gì và làm điều tương tự.

Có ai biết tôi nên làm gì không?

Tôi đang chạy Windows Vista 64 bit nhưng tôi muốn tính năng này hoạt động trên tất cả các hệ điều hành Windows XP, Vista và Windows 7.

Cập nhật: Sự cố với mã tôi đã đăng ở trên là tôi không đặt tiền tố L vào chuỗi "Môi trường". Mặc dù nó không nói rõ ràng ở bất cứ đâu trong tài liệu của Microsoft mà tôi có thể tìm thấy, LPARAM cần phải là một con trỏ tới một chuỗi WCHAR (các ký tự 2 byte) trái ngược với chuỗi CHAR, đó là những gì trình biên dịch của Visual Studio tạo ra theo mặc định khi tôi viết một chuỗi chữ. Giải pháp cho vấn đề của tôi là thay đổi "Môi trường" thành L "Môi trường". (Tôi nghĩ rằng tôi đã cố gắng trước khi đăng câu hỏi này, nhưng dường như tôi đã không thử nó một cách chính xác!) Nhưng bất cứ ai muốn có một giải pháp C++ hoàn chỉnh cho nhiệm vụ này nên xem xét câu trả lời của Dan Moulding.

+0

Bạn có thể muốn xem mã nguồn của một số trình cài đặt nguồn mở, ví dụ: NSIS hoặc Thiết lập Inno. Họ làm đúng thông báo này. – bialix

+6

Một mẹo nhỏ cực nhanh, bạn có thể hiển thị nội dung PATH tại dấu nhắc lệnh bằng cách chỉ cần gõ "đường dẫn" và nhấn Enter. Tiết kiệm cho bạn 7 lần nhấn phím cho mỗi lần kiểm tra (9 đếm phím shift)! – Todd

+0

Ah, bạn phải xây dựng một ứng dụng Unicode, do đó, 'windows.h' mang đến phiên bản Unicode của API (' SendMessageTimeoutW'), sẽ yêu cầu 'LPCWSTR' cho' LPARAM' thay vì 'LPCSTR'. Tôi nghĩ rằng nếu bạn muốn hỗ trợ cả bản dựng "ANSI" và Unicode, thì điều đúng đắn cần làm là sử dụng 'LPCTSTR' (tức là thông qua macro' _T() '). Thư viện của tôi có thể sử dụng một bản cập nhật để làm cho nó "nhận thức Unicode". Nó hiện chỉ hỗ trợ các biến môi trường thiết lập bằng cách sử dụng "ANSI", điều này có thể có vấn đề nếu bạn cần một thư mục với các ký tự cyrillic trong đường dẫn của bạn. –

Trả lời

11

Hóa ra thực sự không phải là bất kỳ điều gì mới dưới ánh mặt trời. Điều này đã được thực hiện trước đó, ít nhất một lần. Bởi tôi. Tôi tạo ra một DLL rất giống với những gì bạn mô tả cho chính xác cùng một mục đích (để sử dụng trong việc sửa đổi đường dẫn từ một trình cài đặt NSIS). Nó được sử dụng bởi trình cài đặt Visual Leak Detector.

DLL được gọi là editenv.dll. The source có sẵn tại github. Tôi vừa thử nghiệm trình cài đặt và nó đã cập nhật biến môi trường PATH PATH, không vấn đề gì. Dựa trên những gì bạn đã viết, tôi không thấy bất cứ điều gì nổi bật là sai. Tôi cũng không thấy bất cứ điều gì rõ ràng là mất tích. Nhưng có thể đáng xem xét nguồn editenv.dll (bạn muốn quan tâm nhất đến EnvVar::set() trong EnvVar.cpp và có thể là các API pathAdd()pathRemove() C trong editenv.cpp).

+0

Cảm ơn mã Dan! Ngay cả khi nghĩ rằng tôi không thể tìm thấy giải pháp cụ thể của tôi bằng cách nhìn vào mã của bạn, câu trả lời của bạn sẽ vô cùng hữu ích cho độc giả tương lai của câu hỏi này. –

0

Tôi có một chương trình gọi cùng một API Win32 cho bạn để cập nhật môi trường và nó hoạt động tốt.

Một điều cần lưu ý là cách bạn đang mở lời nhắc lệnh.

Nếu bạn mở cửa sổ lệnh bằng cách làm này:

Start -> Run -> cmd.exe 

thì môi trường ở dấu nhắc cho thấy biến mới được thiết lập.

Tuy nhiên, tôi cũng có phím chức năng có thể lập trình trên bàn phím mà tôi đã đặt để chạy quy trình cmd.exe. Nếu tôi mở một dấu nhắc lệnh thông qua phím chức năng đó và sau đó nhập env, nó sẽ không hiển thị biến khi được đặt.

Tôi không chắc chắn lý do tại sao nó hoạt động khác nhau, nhưng nó phải có một cái gì đó để làm với cách quá trình cmd.exe được khởi chạy (mặc dù cả hai đang chạy dưới tên người dùng của tôi, không SYSTEM).

Bạn mở lời nhắc lệnh như thế nào?

+4

Chương trình quản lý các phím chức năng có thể lập trình của bạn đang khởi động CMD.EXE với bản sao môi trường riêng, chưa được cập nhật nếu bạn không khởi động lại sau khi thay đổi con đường. – Todd

+0

Thú vị. Tôi đã bắt đầu nhắc lệnh của tôi bằng cách nhấp vào "Command Prompt" trong trình đơn bắt đầu của tôi. Đây là một phím tắt đi kèm với Windows, trong menu Phụ kiện, mà tôi đã "ghim" vào trình đơn bắt đầu. Mục tiêu là% SystemRoot% \ system32 \ cmd.exe –

+0

@Todd - yep nghe có vẻ đúng. Phân tích tốt! @David - Bất kỳ sự khác biệt nào nếu bạn chạy cmd.exe từ Start-> Run? – LeopardSkinPillBoxHat

Các vấn đề liên quan